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 struct rpc_t *rpc_req_prep(void) 174 { 175 return (struct rpc_t *)(net_tx_packet + net_eth_hdr_size() + 176 IP_UDP_HDR_SIZE); 177 } 178 179 static void rpc_req(int rpc_prog, int rpc_proc, struct rpc_t *rpc_pkt, 180 int datalen) 181 { 182 unsigned long id; 183 int pktlen; 184 int sport; 185 186 id = ++rpc_id; 187 rpc_pkt->u.call.id = htonl(id); 188 rpc_pkt->u.call.type = htonl(MSG_CALL); 189 rpc_pkt->u.call.rpcvers = htonl(2); /* use RPC version 2 */ 190 rpc_pkt->u.call.prog = htonl(rpc_prog); 191 switch (rpc_prog) { 192 case PROG_NFS: 193 if (supported_nfs_versions & NFSV2_FLAG) 194 rpc_pkt->u.call.vers = htonl(2); /* NFS v2 */ 195 else /* NFSV3_FLAG */ 196 rpc_pkt->u.call.vers = htonl(3); /* NFS v3 */ 197 break; 198 case PROG_PORTMAP: 199 case PROG_MOUNT: 200 default: 201 /* portmapper is version 2 */ 202 rpc_pkt->u.call.vers = htonl(2); 203 } 204 rpc_pkt->u.call.proc = htonl(rpc_proc); 205 206 pktlen = ((char *)&rpc_pkt->u.call.data - (char *)&rpc_pkt) + 207 datalen * sizeof(uint32_t); 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; 226 struct rpc_t *rpc_pkt = rpc_req_prep(); 227 228 data = rpc_pkt->u.call.data; 229 data[0] = 0; data[1] = 0; /* auth credential */ 230 data[2] = 0; data[3] = 0; /* auth verifier */ 231 data[4] = htonl(prog); 232 data[5] = htonl(ver); 233 data[6] = htonl(17); /* IP_UDP */ 234 data[7] = 0; 235 rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, rpc_pkt, 8); 236 } 237 238 /************************************************************************** 239 NFS_MOUNT - Mount an NFS Filesystem 240 **************************************************************************/ 241 static void nfs_mount_req(char *path) 242 { 243 uint32_t *p; 244 int len; 245 int pathlen; 246 struct rpc_t *rpc_pkt = rpc_req_prep(); 247 248 pathlen = strlen(path); 249 250 p = rpc_pkt->u.call.data; 251 p = rpc_add_credentials(p); 252 253 *p++ = htonl(pathlen); 254 if (pathlen & 3) 255 *(p + pathlen / 4) = 0; 256 memcpy(p, path, pathlen); 257 p += (pathlen + 3) / 4; 258 259 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 260 261 rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, rpc_pkt, len); 262 } 263 264 /************************************************************************** 265 NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server 266 **************************************************************************/ 267 static void nfs_umountall_req(void) 268 { 269 uint32_t *p; 270 int len; 271 struct rpc_t *rpc_pkt = rpc_req_prep(); 272 273 if ((nfs_server_mount_port == -1) || (!fs_mounted)) 274 /* Nothing mounted, nothing to umount */ 275 return; 276 277 p = rpc_pkt->u.call.data; 278 p = rpc_add_credentials(p); 279 280 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 281 282 rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, rpc_pkt, len); 283 } 284 285 /*************************************************************************** 286 * NFS_READLINK (AH 2003-07-14) 287 * This procedure is called when read of the first block fails - 288 * this probably happens when it's a directory or a symlink 289 * In case of successful readlink(), the dirname is manipulated, 290 * so that inside the nfs() function a recursion can be done. 291 **************************************************************************/ 292 static void nfs_readlink_req(void) 293 { 294 uint32_t *p; 295 int len; 296 struct rpc_t *rpc_pkt = rpc_req_prep(); 297 298 p = rpc_pkt->u.call.data; 299 p = rpc_add_credentials(p); 300 301 if (supported_nfs_versions & NFSV2_FLAG) { 302 memcpy(p, filefh, NFS_FHSIZE); 303 p += (NFS_FHSIZE / 4); 304 } else { /* NFSV3_FLAG */ 305 *p++ = htonl(filefh3_length); 306 memcpy(p, filefh, filefh3_length); 307 p += (filefh3_length / 4); 308 } 309 310 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 311 312 rpc_req(PROG_NFS, NFS_READLINK, rpc_pkt, len); 313 } 314 315 /************************************************************************** 316 NFS_LOOKUP - Lookup Pathname 317 **************************************************************************/ 318 static void nfs_lookup_req(char *fname) 319 { 320 uint32_t *p; 321 int len; 322 int fnamelen; 323 struct rpc_t *rpc_pkt = rpc_req_prep(); 324 325 fnamelen = strlen(fname); 326 327 p = rpc_pkt->u.call.data; 328 p = rpc_add_credentials(p); 329 330 if (supported_nfs_versions & NFSV2_FLAG) { 331 memcpy(p, dirfh, NFS_FHSIZE); 332 p += (NFS_FHSIZE / 4); 333 *p++ = htonl(fnamelen); 334 if (fnamelen & 3) 335 *(p + fnamelen / 4) = 0; 336 memcpy(p, fname, fnamelen); 337 p += (fnamelen + 3) / 4; 338 339 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 340 341 rpc_req(PROG_NFS, NFS_LOOKUP, rpc_pkt, len); 342 } else { /* NFSV3_FLAG */ 343 *p++ = htonl(NFS_FHSIZE); /* Dir handle length */ 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, NFS3PROC_LOOKUP, rpc_pkt, len); 355 } 356 } 357 358 /************************************************************************** 359 NFS_READ - Read File on NFS Server 360 **************************************************************************/ 361 static void nfs_read_req(int offset, int readlen) 362 { 363 uint32_t *p; 364 int len; 365 struct rpc_t *rpc_pkt = rpc_req_prep(); 366 367 p = rpc_pkt->u.call.data; 368 p = rpc_add_credentials(p); 369 370 if (supported_nfs_versions & NFSV2_FLAG) { 371 memcpy(p, filefh, NFS_FHSIZE); 372 p += (NFS_FHSIZE / 4); 373 *p++ = htonl(offset); 374 *p++ = htonl(readlen); 375 *p++ = 0; 376 } else { /* NFSV3_FLAG */ 377 *p++ = htonl(filefh3_length); 378 memcpy(p, filefh, filefh3_length); 379 p += (filefh3_length / 4); 380 *p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */ 381 *p++ = htonl(offset); 382 *p++ = htonl(readlen); 383 *p++ = 0; 384 } 385 386 len = (uint32_t *)p - (uint32_t *)&(rpc_pkt->u.call.data); 387 388 rpc_req(PROG_NFS, NFS_READ, rpc_pkt, len); 389 } 390 391 /************************************************************************** 392 RPC request dispatcher 393 **************************************************************************/ 394 static void nfs_send(void) 395 { 396 debug("%s\n", __func__); 397 398 switch (nfs_state) { 399 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 400 if (supported_nfs_versions & NFSV2_FLAG) 401 rpc_lookup_req(PROG_MOUNT, 1); 402 else /* NFSV3_FLAG */ 403 rpc_lookup_req(PROG_MOUNT, 3); 404 break; 405 case STATE_PRCLOOKUP_PROG_NFS_REQ: 406 if (supported_nfs_versions & NFSV2_FLAG) 407 rpc_lookup_req(PROG_NFS, 2); 408 else /* NFSV3_FLAG */ 409 rpc_lookup_req(PROG_NFS, 3); 410 break; 411 case STATE_MOUNT_REQ: 412 nfs_mount_req(nfs_path); 413 break; 414 case STATE_UMOUNT_REQ: 415 nfs_umountall_req(); 416 break; 417 case STATE_LOOKUP_REQ: 418 nfs_lookup_req(nfs_filename); 419 break; 420 case STATE_READ_REQ: 421 nfs_read_req(nfs_offset, nfs_len); 422 break; 423 case STATE_READLINK_REQ: 424 nfs_readlink_req(); 425 break; 426 } 427 } 428 429 /************************************************************************** 430 Handlers for the reply from server 431 **************************************************************************/ 432 433 static int rpc_lookup_reply(int prog, uchar *pkt, unsigned len) 434 { 435 struct rpc_t rpc_pkt; 436 437 memcpy(&rpc_pkt.u.data[0], pkt, len); 438 439 debug("%s\n", __func__); 440 441 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 442 return -NFS_RPC_ERR; 443 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 444 return -NFS_RPC_DROP; 445 446 if (rpc_pkt.u.reply.rstatus || 447 rpc_pkt.u.reply.verifier || 448 rpc_pkt.u.reply.astatus) 449 return -1; 450 451 switch (prog) { 452 case PROG_MOUNT: 453 nfs_server_mount_port = ntohl(rpc_pkt.u.reply.data[0]); 454 break; 455 case PROG_NFS: 456 nfs_server_port = ntohl(rpc_pkt.u.reply.data[0]); 457 break; 458 } 459 460 return 0; 461 } 462 463 static int nfs_mount_reply(uchar *pkt, unsigned len) 464 { 465 struct rpc_t rpc_pkt; 466 467 debug("%s\n", __func__); 468 469 memcpy(&rpc_pkt.u.data[0], pkt, len); 470 471 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 472 return -NFS_RPC_ERR; 473 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 474 return -NFS_RPC_DROP; 475 476 if (rpc_pkt.u.reply.rstatus || 477 rpc_pkt.u.reply.verifier || 478 rpc_pkt.u.reply.astatus || 479 rpc_pkt.u.reply.data[0]) 480 return -1; 481 482 fs_mounted = 1; 483 /* NFSv2 and NFSv3 use same structure */ 484 memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 485 486 return 0; 487 } 488 489 static int nfs_umountall_reply(uchar *pkt, unsigned len) 490 { 491 struct rpc_t rpc_pkt; 492 493 debug("%s\n", __func__); 494 495 memcpy(&rpc_pkt.u.data[0], pkt, len); 496 497 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 498 return -NFS_RPC_ERR; 499 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 500 return -NFS_RPC_DROP; 501 502 if (rpc_pkt.u.reply.rstatus || 503 rpc_pkt.u.reply.verifier || 504 rpc_pkt.u.reply.astatus) 505 return -1; 506 507 fs_mounted = 0; 508 memset(dirfh, 0, sizeof(dirfh)); 509 510 return 0; 511 } 512 513 static int nfs_lookup_reply(uchar *pkt, unsigned len) 514 { 515 struct rpc_t rpc_pkt; 516 517 debug("%s\n", __func__); 518 519 memcpy(&rpc_pkt.u.data[0], pkt, len); 520 521 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 522 return -NFS_RPC_ERR; 523 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 524 return -NFS_RPC_DROP; 525 526 if (rpc_pkt.u.reply.rstatus || 527 rpc_pkt.u.reply.verifier || 528 rpc_pkt.u.reply.astatus || 529 rpc_pkt.u.reply.data[0]) { 530 switch (ntohl(rpc_pkt.u.reply.astatus)) { 531 case NFS_RPC_SUCCESS: /* Not an error */ 532 break; 533 case NFS_RPC_PROG_MISMATCH: 534 /* Remote can't support NFS version */ 535 switch (ntohl(rpc_pkt.u.reply.data[0])) { 536 /* Minimal supported NFS version */ 537 case 3: 538 debug("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n", 539 (supported_nfs_versions & NFSV2_FLAG) ? 540 2 : 3, 541 ntohl(rpc_pkt.u.reply.data[0]), 542 ntohl(rpc_pkt.u.reply.data[1])); 543 debug("Will retry with NFSv3\n"); 544 /* Clear NFSV2_FLAG from supported versions */ 545 supported_nfs_versions &= ~NFSV2_FLAG; 546 return -NFS_RPC_PROG_MISMATCH; 547 case 4: 548 default: 549 puts("*** ERROR: NFS version not supported"); 550 debug(": Requested: V%d, accepted: min V%d - max V%d\n", 551 (supported_nfs_versions & NFSV2_FLAG) ? 552 2 : 3, 553 ntohl(rpc_pkt.u.reply.data[0]), 554 ntohl(rpc_pkt.u.reply.data[1])); 555 puts("\n"); 556 } 557 break; 558 case NFS_RPC_PROG_UNAVAIL: 559 case NFS_RPC_PROC_UNAVAIL: 560 case NFS_RPC_GARBAGE_ARGS: 561 case NFS_RPC_SYSTEM_ERR: 562 default: /* Unknown error on 'accept state' flag */ 563 debug("*** ERROR: accept state error (%d)\n", 564 ntohl(rpc_pkt.u.reply.astatus)); 565 break; 566 } 567 return -1; 568 } 569 570 if (supported_nfs_versions & NFSV2_FLAG) { 571 memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 572 } else { /* NFSV3_FLAG */ 573 filefh3_length = ntohl(rpc_pkt.u.reply.data[1]); 574 if (filefh3_length > NFS3_FHSIZE) 575 filefh3_length = NFS3_FHSIZE; 576 memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length); 577 } 578 579 return 0; 580 } 581 582 static int nfs3_get_attributes_offset(uint32_t *data) 583 { 584 if (ntohl(data[1]) != 0) { 585 /* 'attributes_follow' flag is TRUE, 586 * so we have attributes on 21 dwords */ 587 /* Skip unused values : 588 type; 32 bits value, 589 mode; 32 bits value, 590 nlink; 32 bits value, 591 uid; 32 bits value, 592 gid; 32 bits value, 593 size; 64 bits value, 594 used; 64 bits value, 595 rdev; 64 bits value, 596 fsid; 64 bits value, 597 fileid; 64 bits value, 598 atime; 64 bits value, 599 mtime; 64 bits value, 600 ctime; 64 bits value, 601 */ 602 return 22; 603 } else { 604 /* 'attributes_follow' flag is FALSE, 605 * so we don't have any attributes */ 606 return 1; 607 } 608 } 609 610 static int nfs_readlink_reply(uchar *pkt, unsigned len) 611 { 612 struct rpc_t rpc_pkt; 613 int rlen; 614 int nfsv3_data_offset = 0; 615 616 debug("%s\n", __func__); 617 618 memcpy((unsigned char *)&rpc_pkt, pkt, len); 619 620 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 621 return -NFS_RPC_ERR; 622 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 623 return -NFS_RPC_DROP; 624 625 if (rpc_pkt.u.reply.rstatus || 626 rpc_pkt.u.reply.verifier || 627 rpc_pkt.u.reply.astatus || 628 rpc_pkt.u.reply.data[0]) 629 return -1; 630 631 if (!(supported_nfs_versions & NFSV2_FLAG)) { /* NFSV3_FLAG */ 632 nfsv3_data_offset = 633 nfs3_get_attributes_offset(rpc_pkt.u.reply.data); 634 } 635 636 /* new path length */ 637 rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); 638 639 if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') { 640 int pathlen; 641 642 strcat(nfs_path, "/"); 643 pathlen = strlen(nfs_path); 644 memcpy(nfs_path + pathlen, 645 (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), 646 rlen); 647 nfs_path[pathlen + rlen] = 0; 648 } else { 649 memcpy(nfs_path, 650 (uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]), 651 rlen); 652 nfs_path[rlen] = 0; 653 } 654 return 0; 655 } 656 657 static int nfs_read_reply(uchar *pkt, unsigned len) 658 { 659 struct rpc_t rpc_pkt; 660 int rlen; 661 uchar *data_ptr; 662 663 debug("%s\n", __func__); 664 665 memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply)); 666 667 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 668 return -NFS_RPC_ERR; 669 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 670 return -NFS_RPC_DROP; 671 672 if (rpc_pkt.u.reply.rstatus || 673 rpc_pkt.u.reply.verifier || 674 rpc_pkt.u.reply.astatus || 675 rpc_pkt.u.reply.data[0]) { 676 if (rpc_pkt.u.reply.rstatus) 677 return -9999; 678 if (rpc_pkt.u.reply.astatus) 679 return -9999; 680 return -ntohl(rpc_pkt.u.reply.data[0]); 681 } 682 683 if ((nfs_offset != 0) && !((nfs_offset) % 684 (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) 685 puts("\n\t "); 686 if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) 687 putc('#'); 688 689 if (supported_nfs_versions & NFSV2_FLAG) { 690 rlen = ntohl(rpc_pkt.u.reply.data[18]); 691 data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]); 692 } else { /* NFSV3_FLAG */ 693 int nfsv3_data_offset = 694 nfs3_get_attributes_offset(rpc_pkt.u.reply.data); 695 696 /* count value */ 697 rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]); 698 /* Skip unused values : 699 EOF: 32 bits value, 700 data_size: 32 bits value, 701 */ 702 data_ptr = (uchar *) 703 &(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]); 704 } 705 706 if (store_block(data_ptr, nfs_offset, rlen)) 707 return -9999; 708 709 return rlen; 710 } 711 712 /************************************************************************** 713 Interfaces of U-BOOT 714 **************************************************************************/ 715 static void nfs_timeout_handler(void) 716 { 717 if (++nfs_timeout_count > NFS_RETRY_COUNT) { 718 puts("\nRetry count exceeded; starting again\n"); 719 net_start_again(); 720 } else { 721 puts("T "); 722 net_set_timeout_handler(nfs_timeout + 723 NFS_TIMEOUT * nfs_timeout_count, 724 nfs_timeout_handler); 725 nfs_send(); 726 } 727 } 728 729 static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, 730 unsigned src, unsigned len) 731 { 732 int rlen; 733 int reply; 734 735 debug("%s\n", __func__); 736 737 if (dest != nfs_our_port) 738 return; 739 740 switch (nfs_state) { 741 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 742 if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) 743 break; 744 nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; 745 nfs_send(); 746 break; 747 748 case STATE_PRCLOOKUP_PROG_NFS_REQ: 749 if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) 750 break; 751 nfs_state = STATE_MOUNT_REQ; 752 nfs_send(); 753 break; 754 755 case STATE_MOUNT_REQ: 756 reply = nfs_mount_reply(pkt, len); 757 if (reply == -NFS_RPC_DROP) { 758 break; 759 } else if (reply == -NFS_RPC_ERR) { 760 puts("*** ERROR: Cannot mount\n"); 761 /* just to be sure... */ 762 nfs_state = STATE_UMOUNT_REQ; 763 nfs_send(); 764 } else { 765 nfs_state = STATE_LOOKUP_REQ; 766 nfs_send(); 767 } 768 break; 769 770 case STATE_UMOUNT_REQ: 771 reply = nfs_umountall_reply(pkt, len); 772 if (reply == -NFS_RPC_DROP) { 773 break; 774 } else if (reply == -NFS_RPC_ERR) { 775 debug("*** ERROR: Cannot umount\n"); 776 net_set_state(NETLOOP_FAIL); 777 } else { 778 puts("\ndone\n"); 779 net_set_state(nfs_download_state); 780 } 781 break; 782 783 case STATE_LOOKUP_REQ: 784 reply = nfs_lookup_reply(pkt, len); 785 if (reply == -NFS_RPC_DROP) { 786 break; 787 } else if (reply == -NFS_RPC_ERR) { 788 puts("*** ERROR: File lookup fail\n"); 789 nfs_state = STATE_UMOUNT_REQ; 790 nfs_send(); 791 } else if (reply == -NFS_RPC_PROG_MISMATCH && 792 supported_nfs_versions != 0) { 793 /* umount */ 794 nfs_state = STATE_UMOUNT_REQ; 795 nfs_send(); 796 /* And retry with another supported version */ 797 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 798 nfs_send(); 799 } else { 800 nfs_state = STATE_READ_REQ; 801 nfs_offset = 0; 802 nfs_len = NFS_READ_SIZE; 803 nfs_send(); 804 } 805 break; 806 807 case STATE_READLINK_REQ: 808 reply = nfs_readlink_reply(pkt, len); 809 if (reply == -NFS_RPC_DROP) { 810 break; 811 } else if (reply == -NFS_RPC_ERR) { 812 puts("*** ERROR: Symlink fail\n"); 813 nfs_state = STATE_UMOUNT_REQ; 814 nfs_send(); 815 } else { 816 debug("Symlink --> %s\n", nfs_path); 817 nfs_filename = basename(nfs_path); 818 nfs_path = dirname(nfs_path); 819 820 nfs_state = STATE_MOUNT_REQ; 821 nfs_send(); 822 } 823 break; 824 825 case STATE_READ_REQ: 826 rlen = nfs_read_reply(pkt, len); 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