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("*** Waring: 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 debug("*** ERROR: Fail allocate memory\n"); 859 return; 860 } 861 862 if (net_boot_file_name[0] == '\0') { 863 sprintf(nfs_path, "/nfsroot/%02X%02X%02X%02X.img", 864 net_ip.s_addr & 0xFF, 865 (net_ip.s_addr >> 8) & 0xFF, 866 (net_ip.s_addr >> 16) & 0xFF, 867 (net_ip.s_addr >> 24) & 0xFF); 868 869 debug("*** Warning: no boot file name; using '%s'\n", 870 nfs_path); 871 } else { 872 char *p = net_boot_file_name; 873 874 p = strchr(p, ':'); 875 876 if (p != NULL) { 877 nfs_server_ip = string_to_ip(net_boot_file_name); 878 ++p; 879 strcpy(nfs_path, p); 880 } else { 881 strcpy(nfs_path, net_boot_file_name); 882 } 883 } 884 885 nfs_filename = basename(nfs_path); 886 nfs_path = dirname(nfs_path); 887 888 debug("Using %s device\n", eth_get_name()); 889 890 debug("File transfer via NFS from server %pI4; our IP address is %pI4", 891 &nfs_server_ip, &net_ip); 892 893 /* Check if we need to send across this subnet */ 894 if (net_gateway.s_addr && net_netmask.s_addr) { 895 struct in_addr our_net; 896 struct in_addr server_net; 897 898 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; 899 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr; 900 if (our_net.s_addr != server_net.s_addr) 901 debug("; sending through gateway %pI4", 902 &net_gateway); 903 } 904 debug("\nFilename '%s/%s'.", nfs_path, nfs_filename); 905 906 if (net_boot_file_expected_size_in_blocks) { 907 debug(" Size is 0x%x Bytes = ", 908 net_boot_file_expected_size_in_blocks << 9); 909 print_size(net_boot_file_expected_size_in_blocks << 9, ""); 910 } 911 debug("\nLoad address: 0x%lx\nLoading: *\b", load_addr); 912 913 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 914 net_set_udp_handler(nfs_handler); 915 916 nfs_timeout_count = 0; 917 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 918 919 /*nfs_our_port = 4096 + (get_ticks() % 3072);*/ 920 /*FIX ME !!!*/ 921 nfs_our_port = 1000; 922 923 /* zero out server ether in case the server ip has changed */ 924 memset(net_server_ethaddr, 0, 6); 925 926 nfs_send(); 927 } 928