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 int hl; 146 int hostnamelen; 147 char hostname[256]; 148 149 strcpy(hostname, ""); 150 hostnamelen = strlen(hostname); 151 152 /* Here's the executive summary on authentication requirements of the 153 * various NFS server implementations: Linux accepts both AUTH_NONE 154 * and AUTH_UNIX authentication (also accepts an empty hostname field 155 * in the AUTH_UNIX scheme). *BSD refuses AUTH_NONE, but accepts 156 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX 157 * scheme). To be safe, use AUTH_UNIX and pass the hostname if we have 158 * it (if the BOOTP/DHCP reply didn't give one, just use an empty 159 * hostname). */ 160 161 hl = (hostnamelen + 3) & ~3; 162 163 /* Provide an AUTH_UNIX credential. */ 164 *p++ = htonl(1); /* AUTH_UNIX */ 165 *p++ = htonl(hl+20); /* auth length */ 166 *p++ = htonl(0); /* stamp */ 167 *p++ = htonl(hostnamelen); /* hostname string */ 168 if (hostnamelen & 3) 169 *(p + hostnamelen / 4) = 0; /* add zero padding */ 170 memcpy(p, hostname, hostnamelen); 171 p += hl / 4; 172 *p++ = 0; /* uid */ 173 *p++ = 0; /* gid */ 174 *p++ = 0; /* auxiliary gid list */ 175 176 /* Provide an AUTH_NONE verifier. */ 177 *p++ = 0; /* AUTH_NONE */ 178 *p++ = 0; /* auth length */ 179 180 return p; 181 } 182 183 /************************************************************************** 184 RPC_LOOKUP - Lookup RPC Port numbers 185 **************************************************************************/ 186 static struct rpc_t *rpc_req_prep(void) 187 { 188 return (struct rpc_t *)(net_tx_packet + net_eth_hdr_size() + 189 IP_UDP_HDR_SIZE); 190 } 191 192 static void rpc_req(int rpc_prog, int rpc_proc, struct rpc_t *rpc_pkt, 193 int datalen) 194 { 195 unsigned long id; 196 int pktlen; 197 int sport; 198 199 id = ++rpc_id; 200 rpc_pkt->u.call.id = htonl(id); 201 rpc_pkt->u.call.type = htonl(MSG_CALL); 202 rpc_pkt->u.call.rpcvers = htonl(2); /* use RPC version 2 */ 203 rpc_pkt->u.call.prog = htonl(rpc_prog); 204 switch (rpc_prog) { 205 case PROG_NFS: 206 if (supported_nfs_versions & NFSV2_FLAG) 207 rpc_pkt->u.call.vers = htonl(2); /* NFS v2 */ 208 else /* NFSV3_FLAG */ 209 rpc_pkt->u.call.vers = htonl(3); /* NFS v3 */ 210 break; 211 case PROG_PORTMAP: 212 case PROG_MOUNT: 213 default: 214 /* portmapper is version 2 */ 215 rpc_pkt->u.call.vers = htonl(2); 216 } 217 rpc_pkt->u.call.proc = htonl(rpc_proc); 218 219 pktlen = ((char *)&rpc_pkt->u.call.data - (char *)&rpc_pkt) + 220 datalen * sizeof(uint32_t); 221 222 if (rpc_prog == PROG_PORTMAP) 223 sport = SUNRPC_PORT; 224 else if (rpc_prog == PROG_MOUNT) 225 sport = nfs_server_mount_port; 226 else 227 sport = nfs_server_port; 228 229 net_send_udp_packet(net_server_ethaddr, nfs_server_ip, sport, 230 nfs_our_port, pktlen); 231 } 232 233 /************************************************************************** 234 RPC_LOOKUP - Lookup RPC Port numbers 235 **************************************************************************/ 236 static void rpc_lookup_req(int prog, int ver) 237 { 238 uint32_t *data; 239 struct rpc_t *rpc_pkt = rpc_req_prep(); 240 241 data = rpc_pkt->u.call.data; 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, rpc_pkt, 8); 249 } 250 251 /************************************************************************** 252 NFS_MOUNT - Mount an NFS Filesystem 253 **************************************************************************/ 254 static void nfs_mount_req(char *path) 255 { 256 uint32_t *p; 257 int len; 258 int pathlen; 259 struct rpc_t *rpc_pkt = rpc_req_prep(); 260 261 pathlen = strlen(path); 262 263 p = rpc_pkt->u.call.data; 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 *)&(rpc_pkt->u.call.data); 273 274 rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, rpc_pkt, 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 *p; 283 int len; 284 struct rpc_t *rpc_pkt = rpc_req_prep(); 285 286 if ((nfs_server_mount_port == -1) || (!fs_mounted)) 287 /* Nothing mounted, nothing to umount */ 288 return; 289 290 p = rpc_pkt->u.call.data; 291 p = rpc_add_credentials(p); 292 293 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 294 295 rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, rpc_pkt, 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 *p; 308 int len; 309 struct rpc_t *rpc_pkt = rpc_req_prep(); 310 311 p = rpc_pkt->u.call.data; 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, filefh, filefh3_length); 320 p += (filefh3_length / 4); 321 } 322 323 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 324 325 rpc_req(PROG_NFS, NFS_READLINK, rpc_pkt, len); 326 } 327 328 /************************************************************************** 329 NFS_LOOKUP - Lookup Pathname 330 **************************************************************************/ 331 static void nfs_lookup_req(char *fname) 332 { 333 uint32_t *p; 334 int len; 335 int fnamelen; 336 struct rpc_t *rpc_pkt = rpc_req_prep(); 337 338 fnamelen = strlen(fname); 339 340 p = rpc_pkt->u.call.data; 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 *)&(rpc_pkt->u.call.data); 353 354 rpc_req(PROG_NFS, NFS_LOOKUP, rpc_pkt, 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 *)&(rpc_pkt->u.call.data); 366 367 rpc_req(PROG_NFS, NFS3PROC_LOOKUP, rpc_pkt, 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 *p; 377 int len; 378 struct rpc_t *rpc_pkt = rpc_req_prep(); 379 380 p = rpc_pkt->u.call.data; 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, filefh, 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 *)&(rpc_pkt->u.call.data); 400 401 rpc_req(PROG_NFS, NFS_READ, rpc_pkt, 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(&rpc_pkt.u.data[0], 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(&rpc_pkt.u.data[0], 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(&rpc_pkt.u.data[0], 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(&rpc_pkt.u.data[0], 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) ? 553 2 : 3, 554 ntohl(rpc_pkt.u.reply.data[0]), 555 ntohl(rpc_pkt.u.reply.data[1])); 556 debug("Will retry with NFSv3\n"); 557 /* Clear NFSV2_FLAG from supported versions */ 558 supported_nfs_versions &= ~NFSV2_FLAG; 559 return -NFS_RPC_PROG_MISMATCH; 560 case 4: 561 default: 562 puts("*** ERROR: NFS version not supported"); 563 debug(": Requested: V%d, accepted: min V%d - max V%d\n", 564 (supported_nfs_versions & NFSV2_FLAG) ? 565 2 : 3, 566 ntohl(rpc_pkt.u.reply.data[0]), 567 ntohl(rpc_pkt.u.reply.data[1])); 568 puts("\n"); 569 } 570 break; 571 case NFS_RPC_PROG_UNAVAIL: 572 case NFS_RPC_PROC_UNAVAIL: 573 case NFS_RPC_GARBAGE_ARGS: 574 case NFS_RPC_SYSTEM_ERR: 575 default: /* Unknown error on 'accept state' flag */ 576 debug("*** ERROR: accept state error (%d)\n", 577 ntohl(rpc_pkt.u.reply.astatus)); 578 break; 579 } 580 return -1; 581 } 582 583 if (supported_nfs_versions & NFSV2_FLAG) { 584 memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 585 } else { /* NFSV3_FLAG */ 586 filefh3_length = ntohl(rpc_pkt.u.reply.data[1]); 587 if (filefh3_length > NFS3_FHSIZE) 588 filefh3_length = NFS3_FHSIZE; 589 memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length); 590 } 591 592 return 0; 593 } 594 595 static int nfs3_get_attributes_offset(uint32_t *data) 596 { 597 if (ntohl(data[1]) != 0) { 598 /* 'attributes_follow' flag is TRUE, 599 * so we have attributes on 21 dwords */ 600 /* Skip unused values : 601 type; 32 bits value, 602 mode; 32 bits value, 603 nlink; 32 bits value, 604 uid; 32 bits value, 605 gid; 32 bits value, 606 size; 64 bits value, 607 used; 64 bits value, 608 rdev; 64 bits value, 609 fsid; 64 bits value, 610 fileid; 64 bits value, 611 atime; 64 bits value, 612 mtime; 64 bits value, 613 ctime; 64 bits value, 614 */ 615 return 22; 616 } else { 617 /* 'attributes_follow' flag is FALSE, 618 * so we don't have any attributes */ 619 return 1; 620 } 621 } 622 623 static int nfs_readlink_reply(uchar *pkt, unsigned len) 624 { 625 struct rpc_t rpc_pkt; 626 int rlen; 627 int nfsv3_data_offset = 0; 628 629 debug("%s\n", __func__); 630 631 memcpy((unsigned char *)&rpc_pkt, pkt, len); 632 633 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 634 return -NFS_RPC_ERR; 635 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 636 return -NFS_RPC_DROP; 637 638 if (rpc_pkt.u.reply.rstatus || 639 rpc_pkt.u.reply.verifier || 640 rpc_pkt.u.reply.astatus || 641 rpc_pkt.u.reply.data[0]) 642 return -1; 643 644 if (!(supported_nfs_versions & NFSV2_FLAG)) { /* NFSV3_FLAG */ 645 nfsv3_data_offset = 646 nfs3_get_attributes_offset(rpc_pkt.u.reply.data); 647 } 648 649 /* new path length */ 650 rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); 651 652 if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') { 653 int pathlen; 654 655 strcat(nfs_path, "/"); 656 pathlen = strlen(nfs_path); 657 memcpy(nfs_path + pathlen, 658 (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), 659 rlen); 660 nfs_path[pathlen + rlen] = 0; 661 } else { 662 memcpy(nfs_path, 663 (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), 664 rlen); 665 nfs_path[rlen] = 0; 666 } 667 return 0; 668 } 669 670 static int nfs_read_reply(uchar *pkt, unsigned len) 671 { 672 struct rpc_t rpc_pkt; 673 int rlen; 674 uchar *data_ptr; 675 676 debug("%s\n", __func__); 677 678 memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply)); 679 680 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 681 return -NFS_RPC_ERR; 682 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 683 return -NFS_RPC_DROP; 684 685 if (rpc_pkt.u.reply.rstatus || 686 rpc_pkt.u.reply.verifier || 687 rpc_pkt.u.reply.astatus || 688 rpc_pkt.u.reply.data[0]) { 689 if (rpc_pkt.u.reply.rstatus) 690 return -9999; 691 if (rpc_pkt.u.reply.astatus) 692 return -9999; 693 return -ntohl(rpc_pkt.u.reply.data[0]); 694 } 695 696 if ((nfs_offset != 0) && !((nfs_offset) % 697 (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) 698 puts("\n\t "); 699 if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) 700 putc('#'); 701 702 if (supported_nfs_versions & NFSV2_FLAG) { 703 rlen = ntohl(rpc_pkt.u.reply.data[18]); 704 data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]); 705 } else { /* NFSV3_FLAG */ 706 int nfsv3_data_offset = 707 nfs3_get_attributes_offset(rpc_pkt.u.reply.data); 708 709 /* count value */ 710 rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); 711 /* Skip unused values : 712 EOF: 32 bits value, 713 data_size: 32 bits value, 714 */ 715 data_ptr = (uchar *) 716 &(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]); 717 } 718 719 if (store_block(data_ptr, nfs_offset, rlen)) 720 return -9999; 721 722 return rlen; 723 } 724 725 /************************************************************************** 726 Interfaces of U-BOOT 727 **************************************************************************/ 728 static void nfs_timeout_handler(void) 729 { 730 if (++nfs_timeout_count > NFS_RETRY_COUNT) { 731 puts("\nRetry count exceeded; starting again\n"); 732 net_start_again(); 733 } else { 734 puts("T "); 735 net_set_timeout_handler(nfs_timeout + 736 NFS_TIMEOUT * nfs_timeout_count, 737 nfs_timeout_handler); 738 nfs_send(); 739 } 740 } 741 742 static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, 743 unsigned src, unsigned len) 744 { 745 int rlen; 746 int reply; 747 748 debug("%s\n", __func__); 749 750 if (dest != nfs_our_port) 751 return; 752 753 switch (nfs_state) { 754 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 755 if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) 756 break; 757 nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; 758 nfs_send(); 759 break; 760 761 case STATE_PRCLOOKUP_PROG_NFS_REQ: 762 if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) 763 break; 764 nfs_state = STATE_MOUNT_REQ; 765 nfs_send(); 766 break; 767 768 case STATE_MOUNT_REQ: 769 reply = nfs_mount_reply(pkt, len); 770 if (reply == -NFS_RPC_DROP) { 771 break; 772 } else if (reply == -NFS_RPC_ERR) { 773 puts("*** ERROR: Cannot mount\n"); 774 /* just to be sure... */ 775 nfs_state = STATE_UMOUNT_REQ; 776 nfs_send(); 777 } else { 778 nfs_state = STATE_LOOKUP_REQ; 779 nfs_send(); 780 } 781 break; 782 783 case STATE_UMOUNT_REQ: 784 reply = nfs_umountall_reply(pkt, len); 785 if (reply == -NFS_RPC_DROP) { 786 break; 787 } else if (reply == -NFS_RPC_ERR) { 788 debug("*** ERROR: Cannot umount\n"); 789 net_set_state(NETLOOP_FAIL); 790 } else { 791 puts("\ndone\n"); 792 net_set_state(nfs_download_state); 793 } 794 break; 795 796 case STATE_LOOKUP_REQ: 797 reply = nfs_lookup_reply(pkt, len); 798 if (reply == -NFS_RPC_DROP) { 799 break; 800 } else if (reply == -NFS_RPC_ERR) { 801 puts("*** ERROR: File lookup fail\n"); 802 nfs_state = STATE_UMOUNT_REQ; 803 nfs_send(); 804 } else if (reply == -NFS_RPC_PROG_MISMATCH && 805 supported_nfs_versions != 0) { 806 /* umount */ 807 nfs_state = STATE_UMOUNT_REQ; 808 nfs_send(); 809 /* And retry with another supported version */ 810 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 811 nfs_send(); 812 } else { 813 nfs_state = STATE_READ_REQ; 814 nfs_offset = 0; 815 nfs_len = NFS_READ_SIZE; 816 nfs_send(); 817 } 818 break; 819 820 case STATE_READLINK_REQ: 821 reply = nfs_readlink_reply(pkt, len); 822 if (reply == -NFS_RPC_DROP) { 823 break; 824 } else if (reply == -NFS_RPC_ERR) { 825 puts("*** ERROR: Symlink fail\n"); 826 nfs_state = STATE_UMOUNT_REQ; 827 nfs_send(); 828 } else { 829 debug("Symlink --> %s\n", nfs_path); 830 nfs_filename = basename(nfs_path); 831 nfs_path = dirname(nfs_path); 832 833 nfs_state = STATE_MOUNT_REQ; 834 nfs_send(); 835 } 836 break; 837 838 case STATE_READ_REQ: 839 rlen = nfs_read_reply(pkt, len); 840 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 841 if (rlen > 0) { 842 nfs_offset += rlen; 843 nfs_send(); 844 } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { 845 /* symbolic link */ 846 nfs_state = STATE_READLINK_REQ; 847 nfs_send(); 848 } else { 849 if (!rlen) 850 nfs_download_state = NETLOOP_SUCCESS; 851 if (rlen < 0) 852 debug("NFS READ error (%d)\n", rlen); 853 nfs_state = STATE_UMOUNT_REQ; 854 nfs_send(); 855 } 856 break; 857 } 858 } 859 860 861 void nfs_start(void) 862 { 863 debug("%s\n", __func__); 864 nfs_download_state = NETLOOP_FAIL; 865 866 nfs_server_ip = net_server_ip; 867 nfs_path = (char *)nfs_path_buff; 868 869 if (nfs_path == NULL) { 870 net_set_state(NETLOOP_FAIL); 871 debug("*** ERROR: Fail allocate memory\n"); 872 return; 873 } 874 875 if (net_boot_file_name[0] == '\0') { 876 sprintf(nfs_path, "/nfsroot/%02X%02X%02X%02X.img", 877 net_ip.s_addr & 0xFF, 878 (net_ip.s_addr >> 8) & 0xFF, 879 (net_ip.s_addr >> 16) & 0xFF, 880 (net_ip.s_addr >> 24) & 0xFF); 881 882 debug("*** Warning: no boot file name; using '%s'\n", 883 nfs_path); 884 } else { 885 char *p = net_boot_file_name; 886 887 p = strchr(p, ':'); 888 889 if (p != NULL) { 890 nfs_server_ip = string_to_ip(net_boot_file_name); 891 ++p; 892 strcpy(nfs_path, p); 893 } else { 894 strcpy(nfs_path, net_boot_file_name); 895 } 896 } 897 898 nfs_filename = basename(nfs_path); 899 nfs_path = dirname(nfs_path); 900 901 debug("Using %s device\n", eth_get_name()); 902 903 debug("File transfer via NFS from server %pI4; our IP address is %pI4", 904 &nfs_server_ip, &net_ip); 905 906 /* Check if we need to send across this subnet */ 907 if (net_gateway.s_addr && net_netmask.s_addr) { 908 struct in_addr our_net; 909 struct in_addr server_net; 910 911 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; 912 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr; 913 if (our_net.s_addr != server_net.s_addr) 914 debug("; sending through gateway %pI4", 915 &net_gateway); 916 } 917 debug("\nFilename '%s/%s'.", nfs_path, nfs_filename); 918 919 if (net_boot_file_expected_size_in_blocks) { 920 debug(" Size is 0x%x Bytes = ", 921 net_boot_file_expected_size_in_blocks << 9); 922 print_size(net_boot_file_expected_size_in_blocks << 9, ""); 923 } 924 debug("\nLoad address: 0x%lx\nLoading: *\b", load_addr); 925 926 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 927 net_set_udp_handler(nfs_handler); 928 929 nfs_timeout_count = 0; 930 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 931 932 /*nfs_our_port = 4096 + (get_ticks() % 3072);*/ 933 /*FIX ME !!!*/ 934 nfs_our_port = 1000; 935 936 /* zero out server ether in case the server ip has changed */ 937 memset(net_server_ethaddr, 0, 6); 938 939 nfs_send(); 940 } 941