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