[gPXE] [PATCH 2/4] [proto] Remove unsupported NFS protocol

Stefan Hajnoczi stefanha at gmail.com
Sat Jan 30 05:15:18 EST 2010


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 at gmail.com>
---
 src/config/config.c  |    3 -
 src/config/general.h |    1 -
 src/core/main.c      |    1 -
 src/core/settings.c  |    2 +-
 src/include/nfs.h    |   63 -----
 src/proto/nfs.c      |  616 --------------------------------------------------
 6 files changed, 1 insertions(+), 685 deletions(-)
 delete mode 100644 src/include/nfs.h
 delete mode 100644 src/proto/nfs.c

diff --git a/src/config/config.c b/src/config/config.c
index 8252402..dd3b09a 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -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
diff --git a/src/config/general.h b/src/config/general.h
index eb8a0b5..3501846 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -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 */
diff --git a/src/core/main.c b/src/core/main.c
index 74452b7..ec052b0 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -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
 
 **************************************************************************/
diff --git a/src/core/settings.c b/src/core/settings.c
index 2fefdb9..7d83101 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -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
index 0877bb6..0000000
--- a/src/include/nfs.h
+++ /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
index 943081a..0000000
--- a/src/proto/nfs.c
+++ /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
-- 
1.6.5



More information about the gPXE mailing list