Blame view
net/nfs.c
18.5 KB
cbd8a35c6
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/* * NFS support driver - based on etherboot and U-BOOT's tftp.c * * Masami Komiya <mkomiya@sonare.it> 2004 * */ /* 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. */ #include <common.h> #include <command.h> #include <net.h> #include <malloc.h> #include "nfs.h" #include "bootp.h" |
cbd8a35c6
|
31 |
#define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */ |
fe891ecf4
|
32 |
#define NFS_RETRY_COUNT 30 |
48a3e999c
|
33 34 35 36 37 |
#ifndef CONFIG_NFS_TIMEOUT # define NFS_TIMEOUT 2000UL #else # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT #endif |
cbd8a35c6
|
38 |
|
fa84fa708
|
39 40 |
#define NFS_RPC_ERR 1 #define NFS_RPC_DROP 124 |
c9f6c91b4
|
41 42 |
static int fs_mounted; static unsigned long rpc_id; |
cbd8a35c6
|
43 44 |
static int nfs_offset = -1; static int nfs_len; |
fa84fa708
|
45 |
static ulong nfs_timeout = NFS_TIMEOUT; |
cbd8a35c6
|
46 47 48 |
static char dirfh[NFS_FHSIZE]; /* file handle of directory */ static char filefh[NFS_FHSIZE]; /* file handle of kernel image */ |
22f6e99d5
|
49 |
static enum net_loop_state nfs_download_state; |
cbd8a35c6
|
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
static IPaddr_t NfsServerIP; static int NfsSrvMountPort; static int NfsSrvNfsPort; static int NfsOurPort; static int NfsTimeoutCount; static int NfsState; #define STATE_PRCLOOKUP_PROG_MOUNT_REQ 1 #define STATE_PRCLOOKUP_PROG_NFS_REQ 2 #define STATE_MOUNT_REQ 3 #define STATE_UMOUNT_REQ 4 #define STATE_LOOKUP_REQ 5 #define STATE_READ_REQ 6 #define STATE_READLINK_REQ 7 static char default_filename[64]; static char *nfs_filename; static char *nfs_path; static char nfs_path_buff[2048]; |
c9f6c91b4
|
68 69 |
static inline int store_block(uchar *src, unsigned offset, unsigned len) |
cbd8a35c6
|
70 |
{ |
a084f7da8
|
71 |
ulong newsize = offset + len; |
6d0f6bcf3
|
72 |
#ifdef CONFIG_SYS_DIRECT_FLASH_NFS |
cbd8a35c6
|
73 |
int i, rc = 0; |
c9f6c91b4
|
74 |
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
cbd8a35c6
|
75 76 77 78 79 80 81 82 |
/* start address in flash? */ if (load_addr + offset >= flash_info[i].start[0]) { rc = 1; break; } } if (rc) { /* Flash is destination for this packet */ |
c9f6c91b4
|
83 |
rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len); |
cbd8a35c6
|
84 |
if (rc) { |
c9f6c91b4
|
85 |
flash_perror(rc); |
23a7a32d4
|
86 |
return -1; |
cbd8a35c6
|
87 88 |
} } else |
6d0f6bcf3
|
89 |
#endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ |
cbd8a35c6
|
90 |
{ |
c9f6c91b4
|
91 |
(void)memcpy((void *)(load_addr + offset), src, len); |
cbd8a35c6
|
92 |
} |
a084f7da8
|
93 94 95 |
if (NetBootFileXferSize < (offset+len)) NetBootFileXferSize = newsize; |
23a7a32d4
|
96 |
return 0; |
cbd8a35c6
|
97 98 99 |
} static char* |
c9f6c91b4
|
100 |
basename(char *path) |
cbd8a35c6
|
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
{ char *fname; fname = path + strlen(path) - 1; while (fname >= path) { if (*fname == '/') { fname++; break; } fname--; } return fname; } static char* |
c9f6c91b4
|
116 |
dirname(char *path) |
cbd8a35c6
|
117 118 |
{ char *fname; |
c9f6c91b4
|
119 |
fname = basename(path); |
cbd8a35c6
|
120 121 122 123 124 125 |
--fname; *fname = '\0'; return path; } /************************************************************************** |
cbd8a35c6
|
126 127 |
RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries **************************************************************************/ |
c9f6c91b4
|
128 |
static long *rpc_add_credentials(long *p) |
cbd8a35c6
|
129 130 131 132 |
{ int hl; int hostnamelen; char hostname[256]; |
c9f6c91b4
|
133 134 |
strcpy(hostname, ""); hostnamelen = strlen(hostname); |
cbd8a35c6
|
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
/* 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 */ |
c9f6c91b4
|
152 |
if (hostnamelen & 3) |
cbd8a35c6
|
153 |
*(p + hostnamelen / 4) = 0; /* add zero padding */ |
c9f6c91b4
|
154 |
memcpy(p, hostname, hostnamelen); |
cbd8a35c6
|
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
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; } /************************************************************************** RPC_LOOKUP - Lookup RPC Port numbers **************************************************************************/ static void |
c9f6c91b4
|
171 |
rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) |
cbd8a35c6
|
172 173 174 175 176 177 |
{ struct rpc_t pkt; unsigned long id; uint32_t *p; int pktlen; int sport; |
c3f9d4939
|
178 |
id = ++rpc_id; |
cbd8a35c6
|
179 180 181 182 183 184 185 186 187 |
pkt.u.call.id = htonl(id); pkt.u.call.type = htonl(MSG_CALL); pkt.u.call.rpcvers = htonl(2); /* use RPC version 2 */ pkt.u.call.prog = htonl(rpc_prog); pkt.u.call.vers = htonl(2); /* portmapper is version 2 */ pkt.u.call.proc = htonl(rpc_proc); p = (uint32_t *)&(pkt.u.call.data); if (datalen) |
c9f6c91b4
|
188 |
memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t)); |
cbd8a35c6
|
189 190 |
pktlen = (char *)p + datalen*sizeof(uint32_t) - (char *)&pkt; |
594c26f8a
|
191 |
memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE, |
c9f6c91b4
|
192 |
(char *)&pkt, pktlen); |
cbd8a35c6
|
193 194 195 196 197 198 199 |
if (rpc_prog == PROG_PORTMAP) sport = SUNRPC_PORT; else if (rpc_prog == PROG_MOUNT) sport = NfsSrvMountPort; else sport = NfsSrvNfsPort; |
c9f6c91b4
|
200 201 |
NetSendUDPPacket(NetServerEther, NfsServerIP, sport, NfsOurPort, pktlen); |
cbd8a35c6
|
202 203 204 205 206 207 |
} /************************************************************************** RPC_LOOKUP - Lookup RPC Port numbers **************************************************************************/ static void |
c9f6c91b4
|
208 |
rpc_lookup_req(int prog, int ver) |
cbd8a35c6
|
209 210 211 212 213 214 215 216 217 |
{ uint32_t data[16]; data[0] = 0; data[1] = 0; /* auth credential */ data[2] = 0; data[3] = 0; /* auth verifier */ data[4] = htonl(prog); data[5] = htonl(ver); data[6] = htonl(17); /* IP_UDP */ data[7] = 0; |
c9f6c91b4
|
218 |
rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8); |
cbd8a35c6
|
219 220 221 222 223 224 |
} /************************************************************************** NFS_MOUNT - Mount an NFS Filesystem **************************************************************************/ static void |
c9f6c91b4
|
225 |
nfs_mount_req(char *path) |
cbd8a35c6
|
226 227 228 229 230 |
{ uint32_t data[1024]; uint32_t *p; int len; int pathlen; |
c9f6c91b4
|
231 |
pathlen = strlen(path); |
cbd8a35c6
|
232 233 234 235 236 |
p = &(data[0]); p = (uint32_t *)rpc_add_credentials((long *)p); *p++ = htonl(pathlen); |
c9f6c91b4
|
237 238 239 |
if (pathlen & 3) *(p + pathlen / 4) = 0; memcpy(p, path, pathlen); |
cbd8a35c6
|
240 241 242 |
p += (pathlen + 3) / 4; len = (uint32_t *)p - (uint32_t *)&(data[0]); |
c9f6c91b4
|
243 |
rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len); |
cbd8a35c6
|
244 245 246 247 248 249 |
} /************************************************************************** NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server **************************************************************************/ static void |
c9f6c91b4
|
250 |
nfs_umountall_req(void) |
cbd8a35c6
|
251 252 253 254 |
{ uint32_t data[1024]; uint32_t *p; int len; |
c9f6c91b4
|
255 |
if ((NfsSrvMountPort == -1) || (!fs_mounted)) |
cbd8a35c6
|
256 257 |
/* Nothing mounted, nothing to umount */ return; |
cbd8a35c6
|
258 259 |
p = &(data[0]); |
c9f6c91b4
|
260 |
p = (uint32_t *)rpc_add_credentials((long *)p); |
cbd8a35c6
|
261 262 |
len = (uint32_t *)p - (uint32_t *)&(data[0]); |
c9f6c91b4
|
263 |
rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); |
cbd8a35c6
|
264 265 266 267 268 269 270 271 272 273 |
} /*************************************************************************** * 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 void |
c9f6c91b4
|
274 |
nfs_readlink_req(void) |
cbd8a35c6
|
275 276 277 278 279 280 |
{ uint32_t data[1024]; uint32_t *p; int len; p = &(data[0]); |
c9f6c91b4
|
281 |
p = (uint32_t *)rpc_add_credentials((long *)p); |
cbd8a35c6
|
282 |
|
c9f6c91b4
|
283 |
memcpy(p, filefh, NFS_FHSIZE); |
cbd8a35c6
|
284 285 286 |
p += (NFS_FHSIZE / 4); len = (uint32_t *)p - (uint32_t *)&(data[0]); |
c9f6c91b4
|
287 |
rpc_req(PROG_NFS, NFS_READLINK, data, len); |
cbd8a35c6
|
288 289 290 291 292 293 |
} /************************************************************************** NFS_LOOKUP - Lookup Pathname **************************************************************************/ static void |
c9f6c91b4
|
294 |
nfs_lookup_req(char *fname) |
cbd8a35c6
|
295 296 297 298 299 |
{ uint32_t data[1024]; uint32_t *p; int len; int fnamelen; |
c9f6c91b4
|
300 |
fnamelen = strlen(fname); |
cbd8a35c6
|
301 302 |
p = &(data[0]); |
c9f6c91b4
|
303 |
p = (uint32_t *)rpc_add_credentials((long *)p); |
cbd8a35c6
|
304 |
|
c9f6c91b4
|
305 |
memcpy(p, dirfh, NFS_FHSIZE); |
cbd8a35c6
|
306 307 |
p += (NFS_FHSIZE / 4); *p++ = htonl(fnamelen); |
c9f6c91b4
|
308 309 310 |
if (fnamelen & 3) *(p + fnamelen / 4) = 0; memcpy(p, fname, fnamelen); |
cbd8a35c6
|
311 312 313 |
p += (fnamelen + 3) / 4; len = (uint32_t *)p - (uint32_t *)&(data[0]); |
c9f6c91b4
|
314 |
rpc_req(PROG_NFS, NFS_LOOKUP, data, len); |
cbd8a35c6
|
315 316 317 318 319 320 |
} /************************************************************************** NFS_READ - Read File on NFS Server **************************************************************************/ static void |
c9f6c91b4
|
321 |
nfs_read_req(int offset, int readlen) |
cbd8a35c6
|
322 323 324 325 326 327 |
{ uint32_t data[1024]; uint32_t *p; int len; p = &(data[0]); |
c9f6c91b4
|
328 |
p = (uint32_t *)rpc_add_credentials((long *)p); |
cbd8a35c6
|
329 |
|
c9f6c91b4
|
330 |
memcpy(p, filefh, NFS_FHSIZE); |
cbd8a35c6
|
331 332 333 334 335 336 |
p += (NFS_FHSIZE / 4); *p++ = htonl(offset); *p++ = htonl(readlen); *p++ = 0; len = (uint32_t *)p - (uint32_t *)&(data[0]); |
c9f6c91b4
|
337 |
rpc_req(PROG_NFS, NFS_READ, data, len); |
cbd8a35c6
|
338 339 340 341 342 343 344 |
} /************************************************************************** RPC request dispatcher **************************************************************************/ static void |
c9f6c91b4
|
345 |
NfsSend(void) |
cbd8a35c6
|
346 |
{ |
0ebf04c60
|
347 348 |
debug("%s ", __func__); |
cbd8a35c6
|
349 350 351 |
switch (NfsState) { case STATE_PRCLOOKUP_PROG_MOUNT_REQ: |
c9f6c91b4
|
352 |
rpc_lookup_req(PROG_MOUNT, 1); |
cbd8a35c6
|
353 354 |
break; case STATE_PRCLOOKUP_PROG_NFS_REQ: |
c9f6c91b4
|
355 |
rpc_lookup_req(PROG_NFS, 2); |
cbd8a35c6
|
356 357 |
break; case STATE_MOUNT_REQ: |
c9f6c91b4
|
358 |
nfs_mount_req(nfs_path); |
cbd8a35c6
|
359 360 |
break; case STATE_UMOUNT_REQ: |
c9f6c91b4
|
361 |
nfs_umountall_req(); |
cbd8a35c6
|
362 363 |
break; case STATE_LOOKUP_REQ: |
c9f6c91b4
|
364 |
nfs_lookup_req(nfs_filename); |
cbd8a35c6
|
365 366 |
break; case STATE_READ_REQ: |
c9f6c91b4
|
367 |
nfs_read_req(nfs_offset, nfs_len); |
cbd8a35c6
|
368 369 |
break; case STATE_READLINK_REQ: |
c9f6c91b4
|
370 |
nfs_readlink_req(); |
cbd8a35c6
|
371 372 373 374 375 376 377 378 379 |
break; } } /************************************************************************** Handlers for the reply from server **************************************************************************/ static int |
c9f6c91b4
|
380 |
rpc_lookup_reply(int prog, uchar *pkt, unsigned len) |
cbd8a35c6
|
381 382 |
{ struct rpc_t rpc_pkt; |
c9f6c91b4
|
383 |
memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c6
|
384 |
|
0ebf04c60
|
385 386 |
debug("%s ", __func__); |
cbd8a35c6
|
387 |
|
fa84fa708
|
388 389 390 391 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
392 |
|
cbd8a35c6
|
393 394 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || |
c9f6c91b4
|
395 |
rpc_pkt.u.reply.astatus) |
c3f9d4939
|
396 |
return -1; |
cbd8a35c6
|
397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
switch (prog) { case PROG_MOUNT: NfsSrvMountPort = ntohl(rpc_pkt.u.reply.data[0]); break; case PROG_NFS: NfsSrvNfsPort = ntohl(rpc_pkt.u.reply.data[0]); break; } return 0; } static int |
c9f6c91b4
|
411 |
nfs_mount_reply(uchar *pkt, unsigned len) |
cbd8a35c6
|
412 413 |
{ struct rpc_t rpc_pkt; |
0ebf04c60
|
414 415 |
debug("%s ", __func__); |
cbd8a35c6
|
416 |
|
c9f6c91b4
|
417 |
memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c6
|
418 |
|
fa84fa708
|
419 420 421 422 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
423 |
|
cbd8a35c6
|
424 425 426 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || |
c9f6c91b4
|
427 |
rpc_pkt.u.reply.data[0]) |
cbd8a35c6
|
428 |
return -1; |
cbd8a35c6
|
429 430 |
fs_mounted = 1; |
c9f6c91b4
|
431 |
memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); |
cbd8a35c6
|
432 433 434 435 436 |
return 0; } static int |
c9f6c91b4
|
437 |
nfs_umountall_reply(uchar *pkt, unsigned len) |
cbd8a35c6
|
438 439 |
{ struct rpc_t rpc_pkt; |
0ebf04c60
|
440 441 |
debug("%s ", __func__); |
cbd8a35c6
|
442 |
|
c9f6c91b4
|
443 |
memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c6
|
444 |
|
fa84fa708
|
445 446 447 448 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
449 |
|
cbd8a35c6
|
450 451 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || |
c9f6c91b4
|
452 |
rpc_pkt.u.reply.astatus) |
cbd8a35c6
|
453 |
return -1; |
cbd8a35c6
|
454 455 |
fs_mounted = 0; |
c9f6c91b4
|
456 |
memset(dirfh, 0, sizeof(dirfh)); |
cbd8a35c6
|
457 458 459 460 461 |
return 0; } static int |
c9f6c91b4
|
462 |
nfs_lookup_reply(uchar *pkt, unsigned len) |
cbd8a35c6
|
463 464 |
{ struct rpc_t rpc_pkt; |
0ebf04c60
|
465 466 |
debug("%s ", __func__); |
cbd8a35c6
|
467 |
|
c9f6c91b4
|
468 |
memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c6
|
469 |
|
fa84fa708
|
470 471 472 473 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
474 |
|
cbd8a35c6
|
475 476 477 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || |
c9f6c91b4
|
478 |
rpc_pkt.u.reply.data[0]) |
cbd8a35c6
|
479 |
return -1; |
cbd8a35c6
|
480 |
|
c9f6c91b4
|
481 |
memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); |
cbd8a35c6
|
482 483 484 485 486 |
return 0; } static int |
c9f6c91b4
|
487 |
nfs_readlink_reply(uchar *pkt, unsigned len) |
cbd8a35c6
|
488 489 490 |
{ struct rpc_t rpc_pkt; int rlen; |
0ebf04c60
|
491 492 |
debug("%s ", __func__); |
cbd8a35c6
|
493 |
|
c9f6c91b4
|
494 |
memcpy((unsigned char *)&rpc_pkt, pkt, len); |
cbd8a35c6
|
495 |
|
fa84fa708
|
496 497 498 499 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
500 |
|
cbd8a35c6
|
501 502 503 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || |
c9f6c91b4
|
504 |
rpc_pkt.u.reply.data[0]) |
cbd8a35c6
|
505 |
return -1; |
cbd8a35c6
|
506 |
|
c9f6c91b4
|
507 |
rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */ |
cbd8a35c6
|
508 509 510 |
if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') { int pathlen; |
c9f6c91b4
|
511 |
strcat(nfs_path, "/"); |
cbd8a35c6
|
512 |
pathlen = strlen(nfs_path); |
c9f6c91b4
|
513 514 |
memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen); |
f64ef9bb9
|
515 |
nfs_path[pathlen + rlen] = 0; |
cbd8a35c6
|
516 |
} else { |
c9f6c91b4
|
517 |
memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen); |
cbd8a35c6
|
518 519 520 521 522 523 |
nfs_path[rlen] = 0; } return 0; } static int |
c9f6c91b4
|
524 |
nfs_read_reply(uchar *pkt, unsigned len) |
cbd8a35c6
|
525 526 527 |
{ struct rpc_t rpc_pkt; int rlen; |
0ebf04c60
|
528 529 |
debug("%s ", __func__); |
cbd8a35c6
|
530 |
|
c9f6c91b4
|
531 |
memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply)); |
cbd8a35c6
|
532 |
|
fa84fa708
|
533 534 535 536 |
if (ntohl(rpc_pkt.u.reply.id) > rpc_id) return -NFS_RPC_ERR; else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) return -NFS_RPC_DROP; |
c3f9d4939
|
537 |
|
cbd8a35c6
|
538 539 540 541 |
if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || rpc_pkt.u.reply.data[0]) { |
c9f6c91b4
|
542 |
if (rpc_pkt.u.reply.rstatus) |
cbd8a35c6
|
543 |
return -9999; |
c9f6c91b4
|
544 |
if (rpc_pkt.u.reply.astatus) |
cbd8a35c6
|
545 |
return -9999; |
c9f6c91b4
|
546 |
return -ntohl(rpc_pkt.u.reply.data[0]); |
cbd8a35c6
|
547 |
} |
c9f6c91b4
|
548 549 550 551 552 553 |
if ((nfs_offset != 0) && !((nfs_offset) % (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) puts(" \t "); if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) putc('#'); |
cbd8a35c6
|
554 555 |
rlen = ntohl(rpc_pkt.u.reply.data[18]); |
c9f6c91b4
|
556 557 |
if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply), nfs_offset, rlen)) |
23a7a32d4
|
558 |
return -9999; |
cbd8a35c6
|
559 560 561 562 563 564 565 566 567 |
return rlen; } /************************************************************************** Interfaces of U-BOOT **************************************************************************/ static void |
c9f6c91b4
|
568 |
NfsTimeout(void) |
a5725fabc
|
569 |
{ |
c9f6c91b4
|
570 571 572 573 574 |
if (++NfsTimeoutCount > NFS_RETRY_COUNT) { puts(" Retry count exceeded; starting again "); NetStartAgain(); |
aabb8cb08
|
575 576 |
} else { puts("T "); |
fa84fa708
|
577 578 |
NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount, NfsTimeout); |
c9f6c91b4
|
579 |
NfsSend(); |
fe891ecf4
|
580 |
} |
a5725fabc
|
581 582 583 |
} static void |
03eb129f8
|
584 |
NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) |
cbd8a35c6
|
585 586 |
{ int rlen; |
fa84fa708
|
587 |
int reply; |
cbd8a35c6
|
588 |
|
0ebf04c60
|
589 590 |
debug("%s ", __func__); |
cbd8a35c6
|
591 |
|
c9f6c91b4
|
592 593 |
if (dest != NfsOurPort) return; |
cbd8a35c6
|
594 595 596 |
switch (NfsState) { case STATE_PRCLOOKUP_PROG_MOUNT_REQ: |
fa84fa708
|
597 598 |
if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) break; |
cbd8a35c6
|
599 |
NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ; |
c9f6c91b4
|
600 |
NfsSend(); |
cbd8a35c6
|
601 602 603 |
break; case STATE_PRCLOOKUP_PROG_NFS_REQ: |
fa84fa708
|
604 605 |
if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) break; |
cbd8a35c6
|
606 |
NfsState = STATE_MOUNT_REQ; |
c9f6c91b4
|
607 |
NfsSend(); |
cbd8a35c6
|
608 609 610 |
break; case STATE_MOUNT_REQ: |
fa84fa708
|
611 612 613 614 |
reply = nfs_mount_reply(pkt, len); if (reply == -NFS_RPC_DROP) break; else if (reply == -NFS_RPC_ERR) { |
c9f6c91b4
|
615 616 |
puts("*** ERROR: Cannot mount "); |
cbd8a35c6
|
617 618 |
/* just to be sure... */ NfsState = STATE_UMOUNT_REQ; |
c9f6c91b4
|
619 |
NfsSend(); |
cbd8a35c6
|
620 621 |
} else { NfsState = STATE_LOOKUP_REQ; |
c9f6c91b4
|
622 |
NfsSend(); |
cbd8a35c6
|
623 624 625 626 |
} break; case STATE_UMOUNT_REQ: |
fa84fa708
|
627 628 629 630 |
reply = nfs_umountall_reply(pkt, len); if (reply == -NFS_RPC_DROP) break; else if (reply == -NFS_RPC_ERR) { |
c9f6c91b4
|
631 632 |
puts("*** ERROR: Cannot umount "); |
22f6e99d5
|
633 |
net_set_state(NETLOOP_FAIL); |
cbd8a35c6
|
634 |
} else { |
c9f6c91b4
|
635 636 637 |
puts(" done "); |
22f6e99d5
|
638 |
net_set_state(nfs_download_state); |
cbd8a35c6
|
639 640 641 642 |
} break; case STATE_LOOKUP_REQ: |
fa84fa708
|
643 644 645 646 |
reply = nfs_lookup_reply(pkt, len); if (reply == -NFS_RPC_DROP) break; else if (reply == -NFS_RPC_ERR) { |
c9f6c91b4
|
647 648 |
puts("*** ERROR: File lookup fail "); |
cbd8a35c6
|
649 |
NfsState = STATE_UMOUNT_REQ; |
c9f6c91b4
|
650 |
NfsSend(); |
cbd8a35c6
|
651 652 653 654 |
} else { NfsState = STATE_READ_REQ; nfs_offset = 0; nfs_len = NFS_READ_SIZE; |
c9f6c91b4
|
655 |
NfsSend(); |
cbd8a35c6
|
656 657 658 659 |
} break; case STATE_READLINK_REQ: |
fa84fa708
|
660 661 662 663 |
reply = nfs_readlink_reply(pkt, len); if (reply == -NFS_RPC_DROP) break; else if (reply == -NFS_RPC_ERR) { |
c9f6c91b4
|
664 665 |
puts("*** ERROR: Symlink fail "); |
cbd8a35c6
|
666 |
NfsState = STATE_UMOUNT_REQ; |
c9f6c91b4
|
667 |
NfsSend(); |
cbd8a35c6
|
668 |
} else { |
0ebf04c60
|
669 670 |
debug("Symlink --> %s ", nfs_path); |
c9f6c91b4
|
671 672 |
nfs_filename = basename(nfs_path); nfs_path = dirname(nfs_path); |
cbd8a35c6
|
673 674 |
NfsState = STATE_MOUNT_REQ; |
c9f6c91b4
|
675 |
NfsSend(); |
cbd8a35c6
|
676 677 678 679 |
} break; case STATE_READ_REQ: |
c9f6c91b4
|
680 |
rlen = nfs_read_reply(pkt, len); |
fa84fa708
|
681 |
NetSetTimeout(nfs_timeout, NfsTimeout); |
cbd8a35c6
|
682 683 |
if (rlen > 0) { nfs_offset += rlen; |
c9f6c91b4
|
684 685 |
NfsSend(); } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { |
cbd8a35c6
|
686 687 |
/* symbolic link */ NfsState = STATE_READLINK_REQ; |
c9f6c91b4
|
688 |
NfsSend(); |
cbd8a35c6
|
689 |
} else { |
c9f6c91b4
|
690 |
if (!rlen) |
22f6e99d5
|
691 |
nfs_download_state = NETLOOP_SUCCESS; |
cbd8a35c6
|
692 |
NfsState = STATE_UMOUNT_REQ; |
c9f6c91b4
|
693 |
NfsSend(); |
cbd8a35c6
|
694 695 696 697 |
} break; } } |
cbd8a35c6
|
698 699 |
void |
c9f6c91b4
|
700 |
NfsStart(void) |
cbd8a35c6
|
701 |
{ |
0ebf04c60
|
702 703 |
debug("%s ", __func__); |
22f6e99d5
|
704 |
nfs_download_state = NETLOOP_FAIL; |
cbd8a35c6
|
705 706 707 708 709 |
NfsServerIP = NetServerIP; nfs_path = (char *)nfs_path_buff; if (nfs_path == NULL) { |
22f6e99d5
|
710 |
net_set_state(NETLOOP_FAIL); |
c9f6c91b4
|
711 712 |
puts("*** ERROR: Fail allocate memory "); |
cbd8a35c6
|
713 714 715 716 |
return; } if (BootFile[0] == '\0') { |
ea45cb0ad
|
717 |
sprintf(default_filename, "/nfsroot/%02X%02X%02X%02X.img", |
c43352ccf
|
718 719 720 |
NetOurIP & 0xFF, (NetOurIP >> 8) & 0xFF, (NetOurIP >> 16) & 0xFF, |
c9f6c91b4
|
721 722 |
(NetOurIP >> 24) & 0xFF); strcpy(nfs_path, default_filename); |
cbd8a35c6
|
723 |
|
c9f6c91b4
|
724 725 |
printf("*** Warning: no boot file name; using '%s' ", |
cbd8a35c6
|
726 727 |
nfs_path); } else { |
c9f6c91b4
|
728 |
char *p = BootFile; |
cbd8a35c6
|
729 |
|
c9f6c91b4
|
730 |
p = strchr(p, ':'); |
cbd8a35c6
|
731 732 |
if (p != NULL) { |
c9f6c91b4
|
733 |
NfsServerIP = string_to_ip(BootFile); |
cbd8a35c6
|
734 |
++p; |
c9f6c91b4
|
735 |
strcpy(nfs_path, p); |
cbd8a35c6
|
736 |
} else { |
c9f6c91b4
|
737 |
strcpy(nfs_path, BootFile); |
cbd8a35c6
|
738 739 |
} } |
c9f6c91b4
|
740 741 |
nfs_filename = basename(nfs_path); nfs_path = dirname(nfs_path); |
cbd8a35c6
|
742 |
|
c9f6c91b4
|
743 744 |
printf("Using %s device ", eth_get_name()); |
cbd8a35c6
|
745 |
|
b6446b677
|
746 747 |
printf("File transfer via NFS from server %pI4" "; our IP address is %pI4", &NfsServerIP, &NetOurIP); |
cbd8a35c6
|
748 749 750 751 752 |
/* Check if we need to send across this subnet */ if (NetOurGatewayIP && NetOurSubnetMask) { IPaddr_t OurNet = NetOurIP & NetOurSubnetMask; IPaddr_t ServerNet = NetServerIP & NetOurSubnetMask; |
b6446b677
|
753 |
if (OurNet != ServerNet) |
c9f6c91b4
|
754 755 |
printf("; sending through gateway %pI4", &NetOurGatewayIP); |
cbd8a35c6
|
756 |
} |
c9f6c91b4
|
757 758 |
printf(" Filename '%s/%s'.", nfs_path, nfs_filename); |
cbd8a35c6
|
759 760 |
if (NetBootFileSize) { |
c9f6c91b4
|
761 762 |
printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9); print_size(NetBootFileSize<<9, ""); |
cbd8a35c6
|
763 |
} |
c9f6c91b4
|
764 765 766 |
printf(" Load address: 0x%lx " |
4b9206ed5
|
767 |
"Loading: *\b", load_addr); |
cbd8a35c6
|
768 |
|
fa84fa708
|
769 |
NetSetTimeout(nfs_timeout, NfsTimeout); |
ece223b52
|
770 |
net_set_udp_handler(NfsHandler); |
cbd8a35c6
|
771 |
|
cbd8a35c6
|
772 773 774 775 776 777 778 779 |
NfsTimeoutCount = 0; NfsState = STATE_PRCLOOKUP_PROG_MOUNT_REQ; /*NfsOurPort = 4096 + (get_ticks() % 3072);*/ /*FIX ME !!!*/ NfsOurPort = 1000; /* zero out server ether in case the server ip has changed */ |
c9f6c91b4
|
780 |
memset(NetServerEther, 0, 6); |
cbd8a35c6
|
781 |
|
c9f6c91b4
|
782 |
NfsSend(); |
cbd8a35c6
|
783 |
} |