xref: /openbmc/u-boot/net/nfs.c (revision c882163b09b8a2c52e3dd8acd7d296d6d06d1f2e)
1  /*
2   * NFS support driver - based on etherboot and U-BOOT's tftp.c
3   *
4   * Masami Komiya <mkomiya@sonare.it> 2004
5   *
6   */
7  
8  /* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read:
9   * large portions are copied verbatim) as distributed in OSKit 0.97.  A few
10   * changes were necessary to adapt the code to Etherboot and to fix several
11   * inconsistencies.  Also the RPC message preparation is done "by hand" to
12   * avoid adding netsprintf() which I find hard to understand and use.  */
13  
14  /* NOTE 2: Etherboot does not care about things beyond the kernel image, so
15   * it loads the kernel image off the boot server (ARP_SERVER) and does not
16   * access the client root disk (root-path in dhcpd.conf), which would use
17   * ARP_ROOTSERVER.  The root disk is something the operating system we are
18   * about to load needs to use.	This is different from the OSKit 0.97 logic.  */
19  
20  /* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14
21   * If a symlink is encountered, it is followed as far as possible (recursion
22   * possible, maximum 16 steps). There is no clearing of ".."'s inside the
23   * path, so please DON'T DO THAT. thx. */
24  
25  /* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20.
26   * NFSv2 is still used by default. But if server does not support NFSv2, then
27   * NFSv3 is used, if available on NFS server. */
28  
29  #include <common.h>
30  #include <command.h>
31  #include <net.h>
32  #include <malloc.h>
33  #include <mapmem.h>
34  #include "nfs.h"
35  #include "bootp.h"
36  
37  #define HASHES_PER_LINE 65	/* Number of "loading" hashes per line	*/
38  #define NFS_RETRY_COUNT 30
39  #ifndef CONFIG_NFS_TIMEOUT
40  # define NFS_TIMEOUT 2000UL
41  #else
42  # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
43  #endif
44  
45  #define NFS_RPC_ERR	1
46  #define NFS_RPC_DROP	124
47  
48  static int fs_mounted;
49  static unsigned long rpc_id;
50  static int nfs_offset = -1;
51  static int nfs_len;
52  static ulong nfs_timeout = NFS_TIMEOUT;
53  
54  static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
55  static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
56  static int filefh3_length;	/* (variable) length of filefh when NFSv3 */
57  
58  static enum net_loop_state nfs_download_state;
59  static struct in_addr nfs_server_ip;
60  static int nfs_server_mount_port;
61  static int nfs_server_port;
62  static int nfs_our_port;
63  static int nfs_timeout_count;
64  static int nfs_state;
65  #define STATE_PRCLOOKUP_PROG_MOUNT_REQ	1
66  #define STATE_PRCLOOKUP_PROG_NFS_REQ	2
67  #define STATE_MOUNT_REQ			3
68  #define STATE_UMOUNT_REQ		4
69  #define STATE_LOOKUP_REQ		5
70  #define STATE_READ_REQ			6
71  #define STATE_READLINK_REQ		7
72  
73  static char *nfs_filename;
74  static char *nfs_path;
75  static char nfs_path_buff[2048];
76  
77  #define NFSV2_FLAG 1
78  #define NFSV3_FLAG 1 << 1
79  static char supported_nfs_versions = NFSV2_FLAG | NFSV3_FLAG;
80  
81  static inline int store_block(uchar *src, unsigned offset, unsigned len)
82  {
83  	ulong newsize = offset + len;
84  #ifdef CONFIG_SYS_DIRECT_FLASH_NFS
85  	int i, rc = 0;
86  
87  	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
88  		/* start address in flash? */
89  		if (load_addr + offset >= flash_info[i].start[0]) {
90  			rc = 1;
91  			break;
92  		}
93  	}
94  
95  	if (rc) { /* Flash is destination for this packet */
96  		rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len);
97  		if (rc) {
98  			flash_perror(rc);
99  			return -1;
100  		}
101  	} else
102  #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */
103  	{
104  		void *ptr = map_sysmem(load_addr + offset, len);
105  
106  		memcpy(ptr, src, len);
107  		unmap_sysmem(ptr);
108  	}
109  
110  	if (net_boot_file_size < (offset + len))
111  		net_boot_file_size = newsize;
112  	return 0;
113  }
114  
115  static char *basename(char *path)
116  {
117  	char *fname;
118  
119  	fname = path + strlen(path) - 1;
120  	while (fname >= path) {
121  		if (*fname == '/') {
122  			fname++;
123  			break;
124  		}
125  		fname--;
126  	}
127  	return fname;
128  }
129  
130  static char *dirname(char *path)
131  {
132  	char *fname;
133  
134  	fname = basename(path);
135  	--fname;
136  	*fname = '\0';
137  	return path;
138  }
139  
140  /**************************************************************************
141  RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries
142  **************************************************************************/
143  static uint32_t *rpc_add_credentials(uint32_t *p)
144  {
145  	/* Here's the executive summary on authentication requirements of the
146  	 * various NFS server implementations:	Linux accepts both AUTH_NONE
147  	 * and AUTH_UNIX authentication (also accepts an empty hostname field
148  	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
149  	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
150  	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
151  	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty
152  	 * hostname).  */
153  
154  	/* Provide an AUTH_UNIX credential.  */
155  	*p++ = htonl(1);		/* AUTH_UNIX */
156  	*p++ = htonl(20);		/* auth length */
157  	*p++ = 0;			/* stamp */
158  	*p++ = 0;			/* hostname string */
159  	*p++ = 0;			/* uid */
160  	*p++ = 0;			/* gid */
161  	*p++ = 0;			/* auxiliary gid list */
162  
163  	/* Provide an AUTH_NONE verifier.  */
164  	*p++ = 0;			/* AUTH_NONE */
165  	*p++ = 0;			/* auth length */
166  
167  	return p;
168  }
169  
170  /**************************************************************************
171  RPC_LOOKUP - Lookup RPC Port numbers
172  **************************************************************************/
173  static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
174  {
175  	struct rpc_t rpc_pkt;
176  	unsigned long id;
177  	uint32_t *p;
178  	int pktlen;
179  	int sport;
180  
181  	id = ++rpc_id;
182  	rpc_pkt.u.call.id = htonl(id);
183  	rpc_pkt.u.call.type = htonl(MSG_CALL);
184  	rpc_pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
185  	rpc_pkt.u.call.prog = htonl(rpc_prog);
186  	switch (rpc_prog) {
187  	case PROG_NFS:
188  		if (supported_nfs_versions & NFSV2_FLAG)
189  			rpc_pkt.u.call.vers = htonl(2);	/* NFS v2 */
190  		else /* NFSV3_FLAG */
191  			rpc_pkt.u.call.vers = htonl(3);	/* NFS v3 */
192  		break;
193  	case PROG_PORTMAP:
194  	case PROG_MOUNT:
195  	default:
196  		rpc_pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
197  	}
198  	rpc_pkt.u.call.proc = htonl(rpc_proc);
199  	p = (uint32_t *)&(rpc_pkt.u.call.data);
200  
201  	if (datalen)
202  		memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t));
203  
204  	pktlen = (char *)p + datalen * sizeof(uint32_t) - (char *)&rpc_pkt;
205  
206  	memcpy((char *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE,
207  	       &rpc_pkt.u.data[0], pktlen);
208  
209  	if (rpc_prog == PROG_PORTMAP)
210  		sport = SUNRPC_PORT;
211  	else if (rpc_prog == PROG_MOUNT)
212  		sport = nfs_server_mount_port;
213  	else
214  		sport = nfs_server_port;
215  
216  	net_send_udp_packet(net_server_ethaddr, nfs_server_ip, sport,
217  			    nfs_our_port, pktlen);
218  }
219  
220  /**************************************************************************
221  RPC_LOOKUP - Lookup RPC Port numbers
222  **************************************************************************/
223  static void rpc_lookup_req(int prog, int ver)
224  {
225  	uint32_t data[16];
226  
227  	data[0] = 0; data[1] = 0;	/* auth credential */
228  	data[2] = 0; data[3] = 0;	/* auth verifier */
229  	data[4] = htonl(prog);
230  	data[5] = htonl(ver);
231  	data[6] = htonl(17);	/* IP_UDP */
232  	data[7] = 0;
233  	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
234  }
235  
236  /**************************************************************************
237  NFS_MOUNT - Mount an NFS Filesystem
238  **************************************************************************/
239  static void nfs_mount_req(char *path)
240  {
241  	uint32_t data[1024];
242  	uint32_t *p;
243  	int len;
244  	int pathlen;
245  
246  	pathlen = strlen(path);
247  
248  	p = &(data[0]);
249  	p = rpc_add_credentials(p);
250  
251  	*p++ = htonl(pathlen);
252  	if (pathlen & 3)
253  		*(p + pathlen / 4) = 0;
254  	memcpy(p, path, pathlen);
255  	p += (pathlen + 3) / 4;
256  
257  	len = (uint32_t *)p - (uint32_t *)&(data[0]);
258  
259  	rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len);
260  }
261  
262  /**************************************************************************
263  NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
264  **************************************************************************/
265  static void nfs_umountall_req(void)
266  {
267  	uint32_t data[1024];
268  	uint32_t *p;
269  	int len;
270  
271  	if ((nfs_server_mount_port == -1) || (!fs_mounted))
272  		/* Nothing mounted, nothing to umount */
273  		return;
274  
275  	p = &(data[0]);
276  	p = rpc_add_credentials(p);
277  
278  	len = (uint32_t *)p - (uint32_t *)&(data[0]);
279  
280  	rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len);
281  }
282  
283  /***************************************************************************
284   * NFS_READLINK (AH 2003-07-14)
285   * This procedure is called when read of the first block fails -
286   * this probably happens when it's a directory or a symlink
287   * In case of successful readlink(), the dirname is manipulated,
288   * so that inside the nfs() function a recursion can be done.
289   **************************************************************************/
290  static void nfs_readlink_req(void)
291  {
292  	uint32_t data[1024];
293  	uint32_t *p;
294  	int len;
295  
296  	p = &(data[0]);
297  	p = rpc_add_credentials(p);
298  
299  	if (supported_nfs_versions & NFSV2_FLAG) {
300  		memcpy(p, filefh, NFS_FHSIZE);
301  		p += (NFS_FHSIZE / 4);
302  	} else { /* NFSV3_FLAG */
303  		*p++ = htonl(filefh3_length);
304  		memcpy(p, filefh, filefh3_length);
305  		p += (filefh3_length / 4);
306  	}
307  
308  	len = (uint32_t *)p - (uint32_t *)&(data[0]);
309  
310  	rpc_req(PROG_NFS, NFS_READLINK, data, len);
311  }
312  
313  /**************************************************************************
314  NFS_LOOKUP - Lookup Pathname
315  **************************************************************************/
316  static void nfs_lookup_req(char *fname)
317  {
318  	uint32_t data[1024];
319  	uint32_t *p;
320  	int len;
321  	int fnamelen;
322  
323  	fnamelen = strlen(fname);
324  
325  	p = &(data[0]);
326  	p = rpc_add_credentials(p);
327  
328  	if (supported_nfs_versions & NFSV2_FLAG) {
329  		memcpy(p, dirfh, NFS_FHSIZE);
330  		p += (NFS_FHSIZE / 4);
331  		*p++ = htonl(fnamelen);
332  		if (fnamelen & 3)
333  			*(p + fnamelen / 4) = 0;
334  		memcpy(p, fname, fnamelen);
335  		p += (fnamelen + 3) / 4;
336  
337  		len = (uint32_t *)p - (uint32_t *)&(data[0]);
338  
339  		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
340  	} else {  /* NFSV3_FLAG */
341  		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
342  		memcpy(p, dirfh, NFS_FHSIZE);
343  		p += (NFS_FHSIZE / 4);
344  		*p++ = htonl(fnamelen);
345  		if (fnamelen & 3)
346  			*(p + fnamelen / 4) = 0;
347  		memcpy(p, fname, fnamelen);
348  		p += (fnamelen + 3) / 4;
349  
350  		len = (uint32_t *)p - (uint32_t *)&(data[0]);
351  
352  		rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len);
353  	}
354  }
355  
356  /**************************************************************************
357  NFS_READ - Read File on NFS Server
358  **************************************************************************/
359  static void nfs_read_req(int offset, int readlen)
360  {
361  	uint32_t data[1024];
362  	uint32_t *p;
363  	int len;
364  
365  	p = &(data[0]);
366  	p = rpc_add_credentials(p);
367  
368  	if (supported_nfs_versions & NFSV2_FLAG) {
369  		memcpy(p, filefh, NFS_FHSIZE);
370  		p += (NFS_FHSIZE / 4);
371  		*p++ = htonl(offset);
372  		*p++ = htonl(readlen);
373  		*p++ = 0;
374  	} else { /* NFSV3_FLAG */
375  		*p++ = htonl(filefh3_length);
376  		memcpy(p, filefh, filefh3_length);
377  		p += (filefh3_length / 4);
378  		*p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */
379  		*p++ = htonl(offset);
380  		*p++ = htonl(readlen);
381  		*p++ = 0;
382  	}
383  
384  	len = (uint32_t *)p - (uint32_t *)&(data[0]);
385  
386  	rpc_req(PROG_NFS, NFS_READ, data, len);
387  }
388  
389  /**************************************************************************
390  RPC request dispatcher
391  **************************************************************************/
392  static void nfs_send(void)
393  {
394  	debug("%s\n", __func__);
395  
396  	switch (nfs_state) {
397  	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
398  		if (supported_nfs_versions & NFSV2_FLAG)
399  			rpc_lookup_req(PROG_MOUNT, 1);
400  		else  /* NFSV3_FLAG */
401  			rpc_lookup_req(PROG_MOUNT, 3);
402  		break;
403  	case STATE_PRCLOOKUP_PROG_NFS_REQ:
404  		if (supported_nfs_versions & NFSV2_FLAG)
405  			rpc_lookup_req(PROG_NFS, 2);
406  		else  /* NFSV3_FLAG */
407  			rpc_lookup_req(PROG_NFS, 3);
408  		break;
409  	case STATE_MOUNT_REQ:
410  		nfs_mount_req(nfs_path);
411  		break;
412  	case STATE_UMOUNT_REQ:
413  		nfs_umountall_req();
414  		break;
415  	case STATE_LOOKUP_REQ:
416  		nfs_lookup_req(nfs_filename);
417  		break;
418  	case STATE_READ_REQ:
419  		nfs_read_req(nfs_offset, nfs_len);
420  		break;
421  	case STATE_READLINK_REQ:
422  		nfs_readlink_req();
423  		break;
424  	}
425  }
426  
427  /**************************************************************************
428  Handlers for the reply from server
429  **************************************************************************/
430  
431  static int rpc_lookup_reply(int prog, uchar *pkt, unsigned len)
432  {
433  	struct rpc_t rpc_pkt;
434  
435  	memcpy(&rpc_pkt.u.data[0], pkt, len);
436  
437  	debug("%s\n", __func__);
438  
439  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
440  		return -NFS_RPC_ERR;
441  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
442  		return -NFS_RPC_DROP;
443  
444  	if (rpc_pkt.u.reply.rstatus  ||
445  	    rpc_pkt.u.reply.verifier ||
446  	    rpc_pkt.u.reply.astatus)
447  		return -1;
448  
449  	switch (prog) {
450  	case PROG_MOUNT:
451  		nfs_server_mount_port = ntohl(rpc_pkt.u.reply.data[0]);
452  		break;
453  	case PROG_NFS:
454  		nfs_server_port = ntohl(rpc_pkt.u.reply.data[0]);
455  		break;
456  	}
457  
458  	return 0;
459  }
460  
461  static int nfs_mount_reply(uchar *pkt, unsigned len)
462  {
463  	struct rpc_t rpc_pkt;
464  
465  	debug("%s\n", __func__);
466  
467  	memcpy(&rpc_pkt.u.data[0], pkt, len);
468  
469  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
470  		return -NFS_RPC_ERR;
471  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
472  		return -NFS_RPC_DROP;
473  
474  	if (rpc_pkt.u.reply.rstatus  ||
475  	    rpc_pkt.u.reply.verifier ||
476  	    rpc_pkt.u.reply.astatus  ||
477  	    rpc_pkt.u.reply.data[0])
478  		return -1;
479  
480  	fs_mounted = 1;
481  	/*  NFSv2 and NFSv3 use same structure */
482  	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
483  
484  	return 0;
485  }
486  
487  static int nfs_umountall_reply(uchar *pkt, unsigned len)
488  {
489  	struct rpc_t rpc_pkt;
490  
491  	debug("%s\n", __func__);
492  
493  	memcpy(&rpc_pkt.u.data[0], pkt, len);
494  
495  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
496  		return -NFS_RPC_ERR;
497  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
498  		return -NFS_RPC_DROP;
499  
500  	if (rpc_pkt.u.reply.rstatus  ||
501  	    rpc_pkt.u.reply.verifier ||
502  	    rpc_pkt.u.reply.astatus)
503  		return -1;
504  
505  	fs_mounted = 0;
506  	memset(dirfh, 0, sizeof(dirfh));
507  
508  	return 0;
509  }
510  
511  static int nfs_lookup_reply(uchar *pkt, unsigned len)
512  {
513  	struct rpc_t rpc_pkt;
514  
515  	debug("%s\n", __func__);
516  
517  	memcpy(&rpc_pkt.u.data[0], pkt, len);
518  
519  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
520  		return -NFS_RPC_ERR;
521  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
522  		return -NFS_RPC_DROP;
523  
524  	if (rpc_pkt.u.reply.rstatus  ||
525  	    rpc_pkt.u.reply.verifier ||
526  	    rpc_pkt.u.reply.astatus  ||
527  	    rpc_pkt.u.reply.data[0]) {
528  		switch (ntohl(rpc_pkt.u.reply.astatus)) {
529  		case NFS_RPC_SUCCESS: /* Not an error */
530  			break;
531  		case NFS_RPC_PROG_MISMATCH:
532  			/* Remote can't support NFS version */
533  			switch (ntohl(rpc_pkt.u.reply.data[0])) {
534  			/* Minimal supported NFS version */
535  			case 3:
536  				debug("*** Warning: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
537  				      (supported_nfs_versions & NFSV2_FLAG) ?
538  						2 : 3,
539  				      ntohl(rpc_pkt.u.reply.data[0]),
540  				      ntohl(rpc_pkt.u.reply.data[1]));
541  				debug("Will retry with NFSv3\n");
542  				/* Clear NFSV2_FLAG from supported versions */
543  				supported_nfs_versions &= ~NFSV2_FLAG;
544  				return -NFS_RPC_PROG_MISMATCH;
545  			case 4:
546  			default:
547  				puts("*** ERROR: NFS version not supported");
548  				debug(": Requested: V%d, accepted: min V%d - max V%d\n",
549  				      (supported_nfs_versions & NFSV2_FLAG) ?
550  						2 : 3,
551  				      ntohl(rpc_pkt.u.reply.data[0]),
552  				      ntohl(rpc_pkt.u.reply.data[1]));
553  				puts("\n");
554  			}
555  			break;
556  		case NFS_RPC_PROG_UNAVAIL:
557  		case NFS_RPC_PROC_UNAVAIL:
558  		case NFS_RPC_GARBAGE_ARGS:
559  		case NFS_RPC_SYSTEM_ERR:
560  		default: /* Unknown error on 'accept state' flag */
561  			debug("*** ERROR: accept state error (%d)\n",
562  			      ntohl(rpc_pkt.u.reply.astatus));
563  			break;
564  		}
565  		return -1;
566  	}
567  
568  	if (supported_nfs_versions & NFSV2_FLAG) {
569  		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
570  	} else {  /* NFSV3_FLAG */
571  		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
572  		if (filefh3_length > NFS3_FHSIZE)
573  			filefh3_length  = NFS3_FHSIZE;
574  		memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length);
575  	}
576  
577  	return 0;
578  }
579  
580  static int nfs3_get_attributes_offset(uint32_t *data)
581  {
582  	if (ntohl(data[1]) != 0) {
583  		/* 'attributes_follow' flag is TRUE,
584  		 * so we have attributes on 21 dwords */
585  		/* Skip unused values :
586  			type;	32 bits value,
587  			mode;	32 bits value,
588  			nlink;	32 bits value,
589  			uid;	32 bits value,
590  			gid;	32 bits value,
591  			size;	64 bits value,
592  			used;	64 bits value,
593  			rdev;	64 bits value,
594  			fsid;	64 bits value,
595  			fileid;	64 bits value,
596  			atime;	64 bits value,
597  			mtime;	64 bits value,
598  			ctime;	64 bits value,
599  		*/
600  		return 22;
601  	} else {
602  		/* 'attributes_follow' flag is FALSE,
603  		 * so we don't have any attributes */
604  		return 1;
605  	}
606  }
607  
608  static int nfs_readlink_reply(uchar *pkt, unsigned len)
609  {
610  	struct rpc_t rpc_pkt;
611  	int rlen;
612  	int nfsv3_data_offset = 0;
613  
614  	debug("%s\n", __func__);
615  
616  	memcpy((unsigned char *)&rpc_pkt, pkt, len);
617  
618  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
619  		return -NFS_RPC_ERR;
620  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
621  		return -NFS_RPC_DROP;
622  
623  	if (rpc_pkt.u.reply.rstatus  ||
624  	    rpc_pkt.u.reply.verifier ||
625  	    rpc_pkt.u.reply.astatus  ||
626  	    rpc_pkt.u.reply.data[0])
627  		return -1;
628  
629  	if (!(supported_nfs_versions & NFSV2_FLAG)) { /* NFSV3_FLAG */
630  		nfsv3_data_offset =
631  			nfs3_get_attributes_offset(rpc_pkt.u.reply.data);
632  	}
633  
634  	/* new path length */
635  	rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]);
636  
637  	if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') {
638  		int pathlen;
639  
640  		strcat(nfs_path, "/");
641  		pathlen = strlen(nfs_path);
642  		memcpy(nfs_path + pathlen,
643  		       (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
644  		       rlen);
645  		nfs_path[pathlen + rlen] = 0;
646  	} else {
647  		memcpy(nfs_path,
648  		       (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
649  		       rlen);
650  		nfs_path[rlen] = 0;
651  	}
652  	return 0;
653  }
654  
655  static int nfs_read_reply(uchar *pkt, unsigned len)
656  {
657  	struct rpc_t rpc_pkt;
658  	int rlen;
659  	uchar *data_ptr;
660  
661  	debug("%s\n", __func__);
662  
663  	memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply));
664  
665  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
666  		return -NFS_RPC_ERR;
667  	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
668  		return -NFS_RPC_DROP;
669  
670  	if (rpc_pkt.u.reply.rstatus  ||
671  	    rpc_pkt.u.reply.verifier ||
672  	    rpc_pkt.u.reply.astatus  ||
673  	    rpc_pkt.u.reply.data[0]) {
674  		if (rpc_pkt.u.reply.rstatus)
675  			return -9999;
676  		if (rpc_pkt.u.reply.astatus)
677  			return -9999;
678  		return -ntohl(rpc_pkt.u.reply.data[0]);
679  	}
680  
681  	if ((nfs_offset != 0) && !((nfs_offset) %
682  			(NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE)))
683  		puts("\n\t ");
684  	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
685  		putc('#');
686  
687  	if (supported_nfs_versions & NFSV2_FLAG) {
688  		rlen = ntohl(rpc_pkt.u.reply.data[18]);
689  		data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
690  	} else {  /* NFSV3_FLAG */
691  		int nfsv3_data_offset =
692  			nfs3_get_attributes_offset(rpc_pkt.u.reply.data);
693  
694  		/* count value */
695  		rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]);
696  		/* Skip unused values :
697  			EOF:		32 bits value,
698  			data_size:	32 bits value,
699  		*/
700  		data_ptr = (uchar *)
701  			&(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]);
702  	}
703  
704  	if (store_block(data_ptr, nfs_offset, rlen))
705  			return -9999;
706  
707  	return rlen;
708  }
709  
710  /**************************************************************************
711  Interfaces of U-BOOT
712  **************************************************************************/
713  static void nfs_timeout_handler(void)
714  {
715  	if (++nfs_timeout_count > NFS_RETRY_COUNT) {
716  		puts("\nRetry count exceeded; starting again\n");
717  		net_start_again();
718  	} else {
719  		puts("T ");
720  		net_set_timeout_handler(nfs_timeout +
721  					NFS_TIMEOUT * nfs_timeout_count,
722  					nfs_timeout_handler);
723  		nfs_send();
724  	}
725  }
726  
727  static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
728  			unsigned src, unsigned len)
729  {
730  	int rlen;
731  	int reply;
732  
733  	debug("%s\n", __func__);
734  
735  	if (dest != nfs_our_port)
736  		return;
737  
738  	switch (nfs_state) {
739  	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
740  		if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
741  			break;
742  		nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ;
743  		nfs_send();
744  		break;
745  
746  	case STATE_PRCLOOKUP_PROG_NFS_REQ:
747  		if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
748  			break;
749  		nfs_state = STATE_MOUNT_REQ;
750  		nfs_send();
751  		break;
752  
753  	case STATE_MOUNT_REQ:
754  		reply = nfs_mount_reply(pkt, len);
755  		if (reply == -NFS_RPC_DROP) {
756  			break;
757  		} else if (reply == -NFS_RPC_ERR) {
758  			puts("*** ERROR: Cannot mount\n");
759  			/* just to be sure... */
760  			nfs_state = STATE_UMOUNT_REQ;
761  			nfs_send();
762  		} else {
763  			nfs_state = STATE_LOOKUP_REQ;
764  			nfs_send();
765  		}
766  		break;
767  
768  	case STATE_UMOUNT_REQ:
769  		reply = nfs_umountall_reply(pkt, len);
770  		if (reply == -NFS_RPC_DROP) {
771  			break;
772  		} else if (reply == -NFS_RPC_ERR) {
773  			debug("*** ERROR: Cannot umount\n");
774  			net_set_state(NETLOOP_FAIL);
775  		} else {
776  			puts("\ndone\n");
777  			net_set_state(nfs_download_state);
778  		}
779  		break;
780  
781  	case STATE_LOOKUP_REQ:
782  		reply = nfs_lookup_reply(pkt, len);
783  		if (reply == -NFS_RPC_DROP) {
784  			break;
785  		} else if (reply == -NFS_RPC_ERR) {
786  			puts("*** ERROR: File lookup fail\n");
787  			nfs_state = STATE_UMOUNT_REQ;
788  			nfs_send();
789  		} else if (reply == -NFS_RPC_PROG_MISMATCH &&
790  			   supported_nfs_versions != 0) {
791  			/* umount */
792  			nfs_state = STATE_UMOUNT_REQ;
793  			nfs_send();
794  			/* And retry with another supported version */
795  			nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
796  			nfs_send();
797  		} else {
798  			nfs_state = STATE_READ_REQ;
799  			nfs_offset = 0;
800  			nfs_len = NFS_READ_SIZE;
801  			nfs_send();
802  		}
803  		break;
804  
805  	case STATE_READLINK_REQ:
806  		reply = nfs_readlink_reply(pkt, len);
807  		if (reply == -NFS_RPC_DROP) {
808  			break;
809  		} else if (reply == -NFS_RPC_ERR) {
810  			puts("*** ERROR: Symlink fail\n");
811  			nfs_state = STATE_UMOUNT_REQ;
812  			nfs_send();
813  		} else {
814  			debug("Symlink --> %s\n", nfs_path);
815  			nfs_filename = basename(nfs_path);
816  			nfs_path     = dirname(nfs_path);
817  
818  			nfs_state = STATE_MOUNT_REQ;
819  			nfs_send();
820  		}
821  		break;
822  
823  	case STATE_READ_REQ:
824  		rlen = nfs_read_reply(pkt, len);
825  		if (rlen == -NFS_RPC_DROP)
826  			break;
827  		net_set_timeout_handler(nfs_timeout, nfs_timeout_handler);
828  		if (rlen > 0) {
829  			nfs_offset += rlen;
830  			nfs_send();
831  		} else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) {
832  			/* symbolic link */
833  			nfs_state = STATE_READLINK_REQ;
834  			nfs_send();
835  		} else {
836  			if (!rlen)
837  				nfs_download_state = NETLOOP_SUCCESS;
838  			if (rlen < 0)
839  				debug("NFS READ error (%d)\n", rlen);
840  			nfs_state = STATE_UMOUNT_REQ;
841  			nfs_send();
842  		}
843  		break;
844  	}
845  }
846  
847  
848  void nfs_start(void)
849  {
850  	debug("%s\n", __func__);
851  	nfs_download_state = NETLOOP_FAIL;
852  
853  	nfs_server_ip = net_server_ip;
854  	nfs_path = (char *)nfs_path_buff;
855  
856  	if (nfs_path == NULL) {
857  		net_set_state(NETLOOP_FAIL);
858  		printf("*** ERROR: Fail allocate memory\n");
859  		return;
860  	}
861  
862  	if (!net_parse_bootfile(&nfs_server_ip, nfs_path,
863  				sizeof(nfs_path_buff))) {
864  		sprintf(nfs_path, "/nfsroot/%02X%02X%02X%02X.img",
865  			net_ip.s_addr & 0xFF,
866  			(net_ip.s_addr >>  8) & 0xFF,
867  			(net_ip.s_addr >> 16) & 0xFF,
868  			(net_ip.s_addr >> 24) & 0xFF);
869  
870  		printf("*** Warning: no boot file name; using '%s'\n",
871  		       nfs_path);
872  	}
873  
874  	nfs_filename = basename(nfs_path);
875  	nfs_path     = dirname(nfs_path);
876  
877  	printf("Using %s device\n", eth_get_name());
878  
879  	printf("File transfer via NFS from server %pI4; our IP address is %pI4",
880  	       &nfs_server_ip, &net_ip);
881  
882  	/* Check if we need to send across this subnet */
883  	if (net_gateway.s_addr && net_netmask.s_addr) {
884  		struct in_addr our_net;
885  		struct in_addr server_net;
886  
887  		our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
888  		server_net.s_addr = nfs_server_ip.s_addr & net_netmask.s_addr;
889  		if (our_net.s_addr != server_net.s_addr)
890  			printf("; sending through gateway %pI4",
891  			       &net_gateway);
892  	}
893  	printf("\nFilename '%s/%s'.", nfs_path, nfs_filename);
894  
895  	if (net_boot_file_expected_size_in_blocks) {
896  		printf(" Size is 0x%x Bytes = ",
897  		       net_boot_file_expected_size_in_blocks << 9);
898  		print_size(net_boot_file_expected_size_in_blocks << 9, "");
899  	}
900  	printf("\nLoad address: 0x%lx\nLoading: *\b", load_addr);
901  
902  	net_set_timeout_handler(nfs_timeout, nfs_timeout_handler);
903  	net_set_udp_handler(nfs_handler);
904  
905  	nfs_timeout_count = 0;
906  	nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
907  
908  	/*nfs_our_port = 4096 + (get_ticks() % 3072);*/
909  	/*FIX ME !!!*/
910  	nfs_our_port = 1000;
911  
912  	/* zero out server ether in case the server ip has changed */
913  	memset(net_server_ethaddr, 0, 6);
914  
915  	nfs_send();
916  }
917