[proto] Remove unsupported NFS protocol
authorStefan Hajnoczi <stefanha@gmail.com>
Sat, 30 Jan 2010 09:48:21 +0000 (09:48 +0000)
committerMarty Connor <mdc@etherboot.org>
Mon, 1 Feb 2010 00:21:00 +0000 (19:21 -0500)
The NFS protocol code came from legacy Etherboot and was never updated
to work as a gPXE protocol.  There has been no demand for this protocol,
so this patch removes it.

I have an unfinished NFSv3 over TCP implementation for gPXE that can be
used as the base for new work, should we want to resurrect this
protocol.

Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Marty Connor <mdc@etherboot.org>
src/config/config.c
src/config/general.h
src/core/main.c
src/core/settings.c
src/include/nfs.h [deleted file]
src/proto/nfs.c [deleted file]

index 8252402..dd3b09a 100644 (file)
@@ -109,9 +109,6 @@ REQUIRE_OBJECT ( pxe_call );
 #ifdef DOWNLOAD_PROTO_TFTP
 REQUIRE_OBJECT ( tftp );
 #endif
-#ifdef DOWNLOAD_PROTO_NFS
-REQUIRE_OBJECT ( nfs );
-#endif
 #ifdef DOWNLOAD_PROTO_HTTP
 REQUIRE_OBJECT ( http );
 #endif
index eb8a0b5..3501846 100644 (file)
@@ -54,7 +54,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 #define        DOWNLOAD_PROTO_TFTP     /* Trivial File Transfer Protocol */
-#undef DOWNLOAD_PROTO_NFS      /* Network File System */
 #define        DOWNLOAD_PROTO_HTTP     /* Hypertext Transfer Protocol */
 #undef DOWNLOAD_PROTO_HTTPS    /* Secure Hypertext Transfer Protocol */
 #undef DOWNLOAD_PROTO_FTP      /* File Transfer Protocol */
index 74452b7..ec052b0 100644 (file)
@@ -9,7 +9,6 @@ Literature dealing with the network protocols:
        DHCP - RFC2131, RFC2132 (options)
        TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
        RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
-       NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
        IGMP - RFC1112
 
 **************************************************************************/
index 2fefdb9..7d83101 100644 (file)
@@ -1426,7 +1426,7 @@ struct setting filename_setting __setting = {
 /** Root path setting */
 struct setting root_path_setting __setting = {
        .name = "root-path",
-       .description = "NFS/iSCSI root path",
+       .description = "iSCSI root path",
        .tag = DHCP_ROOT_PATH,
        .type = &setting_type_string,
 };
diff --git a/src/include/nfs.h b/src/include/nfs.h
deleted file mode 100644 (file)
index 0877bb6..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef        _NFS_H
-#define        _NFS_H
-
-#define SUNRPC_PORT    111
-
-#define PROG_PORTMAP   100000
-#define PROG_NFS       100003
-#define PROG_MOUNT     100005
-
-#define MSG_CALL       0
-#define MSG_REPLY      1
-
-#define PORTMAP_GETPORT        3
-
-#define MOUNT_ADDENTRY 1
-#define MOUNT_UMOUNTALL        4
-
-#define NFS_LOOKUP     4
-#define        NFS_READLINK    5
-#define NFS_READ       6
-
-#define NFS_FHSIZE     32
-
-#define NFSERR_PERM    1
-#define NFSERR_NOENT   2
-#define NFSERR_ACCES   13
-#define        NFSERR_ISDIR    21
-#define        NFSERR_INVAL    22
-
-/* Block size used for NFS read accesses.  A RPC reply packet (including  all
- * headers) must fit within a single Ethernet frame to avoid fragmentation.
- * Chosen to be a power of two, as most NFS servers are optimized for this.  */
-#define NFS_READ_SIZE  1024
-
-#define NFS_MAXLINKDEPTH 16
-
-struct rpc_t {
-       struct iphdr ip;
-       struct udphdr udp;
-       union {
-               uint8_t  data[300];             /* longest RPC call must fit!!!! */
-               struct {
-                       uint32_t id;
-                       uint32_t type;
-                       uint32_t rpcvers;
-                       uint32_t prog;
-                       uint32_t vers;
-                       uint32_t proc;
-                       uint32_t data[1];
-               } call;
-               struct {
-                       uint32_t id;
-                       uint32_t type;
-                       uint32_t rstatus;
-                       uint32_t verifier;
-                       uint32_t v2;
-                       uint32_t astatus;
-                       uint32_t data[1];
-               } reply;
-       } u;
-} PACKED;
-
-#endif /* _NFS_H */
diff --git a/src/proto/nfs.c b/src/proto/nfs.c
deleted file mode 100644 (file)
index 943081a..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-#if 0
-
-#include <gpxe/init.h>
-#include <gpxe/in.h>
-
-/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read:
- * large portions are copied verbatim) as distributed in OSKit 0.97.  A few
- * changes were necessary to adapt the code to Etherboot and to fix several
- * inconsistencies.  Also the RPC message preparation is done "by hand" to
- * avoid adding netsprintf() which I find hard to understand and use.  */
-
-/* NOTE 2: Etherboot does not care about things beyond the kernel image, so
- * it loads the kernel image off the boot server (ARP_SERVER) and does not
- * access the client root disk (root-path in dhcpd.conf), which would use
- * ARP_ROOTSERVER.  The root disk is something the operating system we are
- * about to load needs to use.  This is different from the OSKit 0.97 logic.  */
-
-/* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14
- * If a symlink is encountered, it is followed as far as possible (recursion
- * possible, maximum 16 steps). There is no clearing of ".."'s inside the
- * path, so please DON'T DO THAT. thx. */
-
-#define START_OPORT 700                /* mountd usually insists on secure ports */
-#define OPORT_SWEEP 200                /* make sure we don't leave secure range */
-
-static int oport = START_OPORT;
-static struct sockaddr_in mount_server;
-static struct sockaddr_in nfs_server;
-static unsigned long rpc_id;
-
-/**************************************************************************
-RPC_INIT - set up the ID counter to something fairly random
-**************************************************************************/
-void rpc_init(void)
-{
-       unsigned long t;
-
-       t = currticks();
-       rpc_id = t ^ (t << 8) ^ (t << 16);
-}
-
-/**************************************************************************
-RPC_PRINTERROR - Print a low level RPC error message
-**************************************************************************/
-static void rpc_printerror(struct rpc_t *rpc)
-{
-       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-           rpc->u.reply.astatus) {
-               /* rpc_printerror() is called for any RPC related error,
-                * suppress output if no low level RPC error happened.  */
-               DBG("RPC error: (%ld,%ld,%ld)\n", ntohl(rpc->u.reply.rstatus),
-                   ntohl(rpc->u.reply.verifier),
-                   ntohl(rpc->u.reply.astatus));
-       }
-}
-
-/**************************************************************************
-AWAIT_RPC - Wait for an rpc packet
-**************************************************************************/
-static int await_rpc(int ival, void *ptr,
-                    unsigned short ptype __unused, struct iphdr *ip,
-                    struct udphdr *udp, struct tcphdr *tcp __unused)
-{
-       struct rpc_t *rpc;
-       if (!udp) 
-               return 0;
-       if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
-               return 0;
-       if (ntohs(udp->dest) != ival)
-               return 0;
-       if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) + 8)
-               return 0;
-       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-       if (*(unsigned long *)ptr != ntohl(rpc->u.reply.id))
-               return 0;
-       if (MSG_REPLY != ntohl(rpc->u.reply.type))
-               return 0;
-       return 1;
-}
-
-/**************************************************************************
-RPC_LOOKUP - Lookup RPC Port numbers
-**************************************************************************/
-static int rpc_lookup(struct sockaddr_in *addr, int prog, int ver, int sport)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       int retries;
-       long *p;
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_PORTMAP);
-       buf.u.call.vers = htonl(2);     /* portmapper is version 2 */
-       buf.u.call.proc = htonl(PORTMAP_GETPORT);
-       p = (long *)buf.u.call.data;
-       *p++ = 0; *p++ = 0;                             /* auth credential */
-       *p++ = 0; *p++ = 0;                             /* auth verifier */
-       *p++ = htonl(prog);
-       *p++ = htonl(ver);
-       *p++ = htonl(IP_UDP);
-       *p++ = 0;
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout;
-               udp_transmit(addr->sin_addr.s_addr, sport, addr->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               if (await_reply(await_rpc, sport, &id, timeout)) {
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus) {
-                               rpc_printerror(rpc);
-                               return 0;
-                       } else {
-                               return ntohl(rpc->u.reply.data[0]);
-                       }
-               }
-       }
-       return 0;
-}
-
-/**************************************************************************
-RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries
-**************************************************************************/
-static long *rpc_add_credentials(long *p)
-{
-       int hl;
-
-       /* Here's the executive summary on authentication requirements of the
-        * various NFS server implementations:  Linux accepts both AUTH_NONE
-        * and AUTH_UNIX authentication (also accepts an empty hostname field
-        * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
-        * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
-        * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
-        * it (if the BOOTP/DHCP reply didn't give one, just use an empty
-        * hostname).  */
-
-       hl = (hostnamelen + 3) & ~3;
-
-       /* Provide an AUTH_UNIX credential.  */
-       *p++ = htonl(1);                /* AUTH_UNIX */
-       *p++ = htonl(hl+20);            /* auth length */
-       *p++ = htonl(0);                /* stamp */
-       *p++ = htonl(hostnamelen);      /* hostname string */
-       if (hostnamelen & 3) {
-               *(p + hostnamelen / 4) = 0; /* add zero padding */
-       }
-       memcpy(p, hostname, hostnamelen);
-       p += hl / 4;
-       *p++ = 0;                       /* uid */
-       *p++ = 0;                       /* gid */
-       *p++ = 0;                       /* auxiliary gid list */
-
-       /* Provide an AUTH_NONE verifier.  */
-       *p++ = 0;                       /* AUTH_NONE */
-       *p++ = 0;                       /* auth length */
-
-       return p;
-}
-
-/**************************************************************************
-NFS_PRINTERROR - Print a NFS error message
-**************************************************************************/
-static void nfs_printerror(int err)
-{
-       switch (-err) {
-       case NFSERR_PERM:
-               printf("Not owner\n");
-               break;
-       case NFSERR_NOENT:
-               printf("No such file or directory\n");
-               break;
-       case NFSERR_ACCES:
-               printf("Permission denied\n");
-               break;
-       case NFSERR_ISDIR:
-               printf("Directory given where filename expected\n");
-               break;
-       case NFSERR_INVAL:
-               printf("Invalid filehandle\n");
-               break; // INVAL is not defined in NFSv2, some NFS-servers
-               // seem to use it in answers to v2 nevertheless.
-       case 9998:
-               printf("low-level RPC failure (parameter decoding problem?)\n");
-               break;
-       case 9999:
-               printf("low-level RPC failure (authentication problem?)\n");
-               break;
-       default:
-               printf("Unknown NFS error %d\n", -err);
-       }
-}
-
-/**************************************************************************
-NFS_MOUNT - Mount an NFS Filesystem
-**************************************************************************/
-static int nfs_mount(struct sockaddr_in *server, char *path, char *fh, int sport)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       int retries;
-       long *p;
-       int pathlen = strlen(path);
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_MOUNT);
-       buf.u.call.vers = htonl(1);     /* mountd is version 1 */
-       buf.u.call.proc = htonl(MOUNT_ADDENTRY);
-       p = rpc_add_credentials((long *)buf.u.call.data);
-       *p++ = htonl(pathlen);
-       if (pathlen & 3) {
-               *(p + pathlen / 4) = 0; /* add zero padding */
-       }
-       memcpy(p, path, pathlen);
-       p += (pathlen + 3) / 4;
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout;
-               udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               if (await_reply(await_rpc, sport, &id, timeout)) {
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus || rpc->u.reply.data[0]) {
-                               rpc_printerror(rpc);
-                               if (rpc->u.reply.rstatus) {
-                                       /* RPC failed, no verifier, data[0] */
-                                       return -9999;
-                               }
-                               if (rpc->u.reply.astatus) {
-                                       /* RPC couldn't decode parameters */
-                                       return -9998;
-                               }
-                               return -ntohl(rpc->u.reply.data[0]);
-                       } else {
-                               memcpy(fh, rpc->u.reply.data + 1, NFS_FHSIZE);
-                               return 0;
-                       }
-               }
-       }
-       return -1;
-}
-
-/**************************************************************************
-NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
-**************************************************************************/
-static void nfs_umountall(struct sockaddr_in *server)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       int retries;
-       long *p;
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_MOUNT);
-       buf.u.call.vers = htonl(1);     /* mountd is version 1 */
-       buf.u.call.proc = htonl(MOUNT_UMOUNTALL);
-       p = rpc_add_credentials((long *)buf.u.call.data);
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               udp_transmit(server->sin_addr.s_addr, oport, server->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               if (await_reply(await_rpc, oport, &id, timeout)) {
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus) {
-                               rpc_printerror(rpc);
-                       }
-                       break;
-               }
-       }
-}
-
-/**************************************************************************
-NFS_RESET - Reset the NFS subsystem
-**************************************************************************/
-static void nfs_reset ( void ) {
-       /* If we have a mount server, call nfs_umountall() */
-       if ( mount_server.sin_addr.s_addr ) {
-               nfs_umountall ( &mount_server );
-       }
-       /* Zero the data structures */
-       memset ( &mount_server, 0, sizeof ( mount_server ) );
-       memset ( &nfs_server, 0, sizeof ( nfs_server ) );
-}
-
-/***************************************************************************
- * NFS_READLINK (AH 2003-07-14)
- * This procedure is called when read of the first block fails -
- * this probably happens when it's a directory or a symlink
- * In case of successful readlink(), the dirname is manipulated,
- * so that inside the nfs() function a recursion can be done.
- **************************************************************************/
-static int nfs_readlink(struct sockaddr_in *server, char *fh __unused,
-                       char *path, char *nfh, int sport)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       long *p;
-       int retries;
-       int pathlen = strlen(path);
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_NFS);
-       buf.u.call.vers = htonl(2);     /* nfsd is version 2 */
-       buf.u.call.proc = htonl(NFS_READLINK);
-       p = rpc_add_credentials((long *)buf.u.call.data);
-       memcpy(p, nfh, NFS_FHSIZE);
-       p += (NFS_FHSIZE / 4);
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               if (await_reply(await_rpc, sport, &id, timeout)) {
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus || rpc->u.reply.data[0]) {
-                               rpc_printerror(rpc);
-                               if (rpc->u.reply.rstatus) {
-                                       /* RPC failed, no verifier, data[0] */
-                                       return -9999;
-                               }
-                               if (rpc->u.reply.astatus) {
-                                       /* RPC couldn't decode parameters */
-                                       return -9998;
-                               }
-                               return -ntohl(rpc->u.reply.data[0]);
-                       } else {
-                               // It *is* a link.
-                               // If it's a relative link, append everything to dirname, filename TOO!
-                               retries = strlen ( (char *)(&(rpc->u.reply.data[2]) ));
-                               if ( *((char *)(&(rpc->u.reply.data[2]))) != '/' ) {
-                                       path[pathlen++] = '/';
-                                       while ( ( retries + pathlen ) > 298 ) {
-                                               retries--;
-                                       }
-                                       if ( retries > 0 ) {
-                                               memcpy(path + pathlen, &(rpc->u.reply.data[2]), retries + 1);
-                                       } else { retries = 0; }
-                                       path[pathlen + retries] = 0;
-                               } else {
-                                       // Else make it the only path.
-                                       if ( retries > 298 ) { retries = 298; }
-                                       memcpy ( path, &(rpc->u.reply.data[2]), retries + 1 );
-                                       path[retries] = 0;
-                               }
-                               return 0;
-                       }
-               }
-       }
-       return -1;
-}
-/**************************************************************************
-NFS_LOOKUP - Lookup Pathname
-**************************************************************************/
-static int nfs_lookup(struct sockaddr_in *server, char *fh, char *path, char *nfh,
-       int sport)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       long *p;
-       int retries;
-       int pathlen = strlen(path);
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_NFS);
-       buf.u.call.vers = htonl(2);     /* nfsd is version 2 */
-       buf.u.call.proc = htonl(NFS_LOOKUP);
-       p = rpc_add_credentials((long *)buf.u.call.data);
-       memcpy(p, fh, NFS_FHSIZE);
-       p += (NFS_FHSIZE / 4);
-       *p++ = htonl(pathlen);
-       if (pathlen & 3) {
-               *(p + pathlen / 4) = 0; /* add zero padding */
-       }
-       memcpy(p, path, pathlen);
-       p += (pathlen + 3) / 4;
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               if (await_reply(await_rpc, sport, &id, timeout)) {
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus || rpc->u.reply.data[0]) {
-                               rpc_printerror(rpc);
-                               if (rpc->u.reply.rstatus) {
-                                       /* RPC failed, no verifier, data[0] */
-                                       return -9999;
-                               }
-                               if (rpc->u.reply.astatus) {
-                                       /* RPC couldn't decode parameters */
-                                       return -9998;
-                               }
-                               return -ntohl(rpc->u.reply.data[0]);
-                       } else {
-                               memcpy(nfh, rpc->u.reply.data + 1, NFS_FHSIZE);
-                               return 0;
-                       }
-               }
-       }
-       return -1;
-}
-
-/**************************************************************************
-NFS_READ - Read File on NFS Server
-**************************************************************************/
-static int nfs_read(struct sockaddr_in *server, char *fh, int offset, int len,
-                   int sport)
-{
-       struct rpc_t buf, *rpc;
-       unsigned long id;
-       int retries;
-       long *p;
-
-       static int tokens=0;
-       /*
-        * Try to implement something similar to a window protocol in
-        * terms of response to losses. On successful receive, increment
-        * the number of tokens by 1 (cap at 256). On failure, halve it.
-        * When the number of tokens is >= 2, use a very short timeout.
-        */
-
-       id = rpc_id++;
-       buf.u.call.id = htonl(id);
-       buf.u.call.type = htonl(MSG_CALL);
-       buf.u.call.rpcvers = htonl(2);  /* use RPC version 2 */
-       buf.u.call.prog = htonl(PROG_NFS);
-       buf.u.call.vers = htonl(2);     /* nfsd is version 2 */
-       buf.u.call.proc = htonl(NFS_READ);
-       p = rpc_add_credentials((long *)buf.u.call.data);
-       memcpy(p, fh, NFS_FHSIZE);
-       p += NFS_FHSIZE / 4;
-       *p++ = htonl(offset);
-       *p++ = htonl(len);
-       *p++ = 0;               /* unused parameter */
-       for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {
-               long timeout = rfc2131_sleep_interval(TIMEOUT, retries);
-               if (tokens >= 2)
-                       timeout = TICKS_PER_SEC/2;
-
-               udp_transmit(server->sin_addr.s_addr, sport, server->sin_port,
-                       (char *)p - (char *)&buf, &buf);
-               if (await_reply(await_rpc, sport, &id, timeout)) {
-                       if (tokens < 256)
-                               tokens++;
-                       rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-                       if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
-                           rpc->u.reply.astatus || rpc->u.reply.data[0]) {
-                               rpc_printerror(rpc);
-                               if (rpc->u.reply.rstatus) {
-                                       /* RPC failed, no verifier, data[0] */
-                                       return -9999;
-                               }
-                               if (rpc->u.reply.astatus) {
-                                       /* RPC couldn't decode parameters */
-                                       return -9998;
-                               }
-                               return -ntohl(rpc->u.reply.data[0]);
-                       } else {
-                               return 0;
-                       }
-               } else
-                       tokens >>= 1;
-       }
-       return -1;
-}
-
-/**************************************************************************
-NFS - Download extended BOOTP data, or kernel image from NFS server
-**************************************************************************/
-static int nfs ( char *url __unused, struct sockaddr_in *server,
-                char *name, struct buffer *buffer ) {
-       static int recursion = 0;
-       int sport;
-       int err, namelen = strlen(name);
-       char dirname[300], *fname;
-       char dirfh[NFS_FHSIZE];         /* file handle of directory */
-       char filefh[NFS_FHSIZE];        /* file handle of kernel image */
-       int rlen, size, offs, len;
-       struct rpc_t *rpc;
-
-       sport = oport++;
-       if (oport > START_OPORT+OPORT_SWEEP) {
-               oport = START_OPORT;
-       }
-
-       mount_server.sin_addr = nfs_server.sin_addr = server->sin_addr;
-       mount_server.sin_port = rpc_lookup(server, PROG_MOUNT, 1, sport);
-       if ( ! mount_server.sin_port ) {
-               DBG ( "Cannot get mount port from %s:%d\n",
-                     inet_ntoa ( server->sin_addr ), server->sin_port );
-               return 0;
-       }
-       nfs_server.sin_port = rpc_lookup(server, PROG_NFS, 2, sport);
-       if ( ! mount_server.sin_port ) {
-               DBG ( "Cannot get nfs port from %s:%d\n",
-                     inet_ntoa ( server->sin_addr ), server->sin_port );
-               return 0;
-       }
-
-       if ( name != dirname ) {
-               memcpy(dirname, name, namelen + 1);
-       }
-       recursion = 0;
-nfssymlink:
-       if ( recursion > NFS_MAXLINKDEPTH ) {
-               DBG ( "\nRecursion: More than %d symlinks followed. Abort.\n",
-                     NFS_MAXLINKDEPTH );
-               return  0;
-       }
-       recursion++;
-       fname = dirname + (namelen - 1);
-       while (fname >= dirname) {
-               if (*fname == '/') {
-                       *fname = '\0';
-                       fname++;
-                       break;
-               }
-               fname--;
-       }
-       if (fname < dirname) {
-               DBG("can't parse file name %s\n", name);
-               return 0;
-       }
-
-       err = nfs_mount(&mount_server, dirname, dirfh, sport);
-       if (err) {
-               DBG("mounting %s: ", dirname);
-               nfs_printerror(err);
-               /* just to be sure... */
-               nfs_reset();
-               return 0;
-       }
-
-       err = nfs_lookup(&nfs_server, dirfh, fname, filefh, sport);
-       if (err) {
-               DBG("looking up %s: ", fname);
-               nfs_printerror(err);
-               nfs_reset();
-               return 0;
-       }
-
-       offs = 0;
-       size = -1;      /* will be set properly with the first reply */
-       len = NFS_READ_SIZE;    /* first request is always full size */
-       do {
-               err = nfs_read(&nfs_server, filefh, offs, len, sport);
-                if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) {
-                       // An error occured. NFS servers tend to sending
-                       // errors 21 / 22 when symlink instead of real file
-                       // is requested. So check if it's a symlink!
-                       if ( nfs_readlink(&nfs_server, dirfh, dirname,
-                                         filefh, sport) == 0 ) {
-                               printf("\nLoading symlink:%s ..",dirname);
-                               goto nfssymlink;
-                       }
-                       nfs_printerror(err);
-                       nfs_reset();
-                       return 0;
-               }
-               if (err) {
-                       printf("\nError reading at offset %d: ", offs);
-                       nfs_printerror(err);
-                       nfs_reset();
-                       return 0;
-               }
-
-               rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
-
-               /* size must be found out early to allow EOF detection */
-               if (size == -1) {
-                       size = ntohl(rpc->u.reply.data[6]);
-               }
-               rlen = ntohl(rpc->u.reply.data[18]);
-               if (rlen > len) {
-                       rlen = len;     /* shouldn't happen...  */
-               }
-
-               if ( ! fill_buffer ( buffer, &rpc->u.reply.data[19],
-                                    offs, rlen ) ) {
-                       nfs_reset();
-                       return 0;
-               }
-
-               offs += rlen;
-               /* last request is done with matching requested read size */
-               if (size-offs < NFS_READ_SIZE) {
-                       len = size-offs;
-               }
-       } while (len != 0);
-       /* len == 0 means that all the file has been read */
-       return 1;
-}
-
-struct protocol nfs_protocol __protocol = {
-       .name = "nfs",
-       .default_port = SUNRPC_PORT,
-       .load = nfs,
-};
-
-#endif