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