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 #include <common.h> 26 #include <command.h> 27 #include <net.h> 28 #include <malloc.h> 29 #include "nfs.h" 30 #include "bootp.h" 31 32 #define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */ 33 #define NFS_RETRY_COUNT 30 34 #ifndef CONFIG_NFS_TIMEOUT 35 # define NFS_TIMEOUT 2000UL 36 #else 37 # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT 38 #endif 39 40 #define NFS_RPC_ERR 1 41 #define NFS_RPC_DROP 124 42 43 static int fs_mounted; 44 static unsigned long rpc_id; 45 static int nfs_offset = -1; 46 static int nfs_len; 47 static ulong nfs_timeout = NFS_TIMEOUT; 48 49 static char dirfh[NFS_FHSIZE]; /* file handle of directory */ 50 static char filefh[NFS_FHSIZE]; /* file handle of kernel image */ 51 52 static enum net_loop_state nfs_download_state; 53 static IPaddr_t NfsServerIP; 54 static int NfsSrvMountPort; 55 static int NfsSrvNfsPort; 56 static int NfsOurPort; 57 static int NfsTimeoutCount; 58 static int NfsState; 59 #define STATE_PRCLOOKUP_PROG_MOUNT_REQ 1 60 #define STATE_PRCLOOKUP_PROG_NFS_REQ 2 61 #define STATE_MOUNT_REQ 3 62 #define STATE_UMOUNT_REQ 4 63 #define STATE_LOOKUP_REQ 5 64 #define STATE_READ_REQ 6 65 #define STATE_READLINK_REQ 7 66 67 static char default_filename[64]; 68 static char *nfs_filename; 69 static char *nfs_path; 70 static char nfs_path_buff[2048]; 71 72 static inline int 73 store_block(uchar *src, unsigned offset, unsigned len) 74 { 75 ulong newsize = offset + len; 76 #ifdef CONFIG_SYS_DIRECT_FLASH_NFS 77 int i, rc = 0; 78 79 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 80 /* start address in flash? */ 81 if (load_addr + offset >= flash_info[i].start[0]) { 82 rc = 1; 83 break; 84 } 85 } 86 87 if (rc) { /* Flash is destination for this packet */ 88 rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len); 89 if (rc) { 90 flash_perror(rc); 91 return -1; 92 } 93 } else 94 #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ 95 { 96 (void)memcpy((void *)(load_addr + offset), src, len); 97 } 98 99 if (NetBootFileXferSize < (offset+len)) 100 NetBootFileXferSize = newsize; 101 return 0; 102 } 103 104 static char* 105 basename(char *path) 106 { 107 char *fname; 108 109 fname = path + strlen(path) - 1; 110 while (fname >= path) { 111 if (*fname == '/') { 112 fname++; 113 break; 114 } 115 fname--; 116 } 117 return fname; 118 } 119 120 static char* 121 dirname(char *path) 122 { 123 char *fname; 124 125 fname = basename(path); 126 --fname; 127 *fname = '\0'; 128 return path; 129 } 130 131 /************************************************************************** 132 RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries 133 **************************************************************************/ 134 static long *rpc_add_credentials(long *p) 135 { 136 int hl; 137 int hostnamelen; 138 char hostname[256]; 139 140 strcpy(hostname, ""); 141 hostnamelen = strlen(hostname); 142 143 /* Here's the executive summary on authentication requirements of the 144 * various NFS server implementations: Linux accepts both AUTH_NONE 145 * and AUTH_UNIX authentication (also accepts an empty hostname field 146 * in the AUTH_UNIX scheme). *BSD refuses AUTH_NONE, but accepts 147 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX 148 * scheme). To be safe, use AUTH_UNIX and pass the hostname if we have 149 * it (if the BOOTP/DHCP reply didn't give one, just use an empty 150 * hostname). */ 151 152 hl = (hostnamelen + 3) & ~3; 153 154 /* Provide an AUTH_UNIX credential. */ 155 *p++ = htonl(1); /* AUTH_UNIX */ 156 *p++ = htonl(hl+20); /* auth length */ 157 *p++ = htonl(0); /* stamp */ 158 *p++ = htonl(hostnamelen); /* hostname string */ 159 if (hostnamelen & 3) 160 *(p + hostnamelen / 4) = 0; /* add zero padding */ 161 memcpy(p, hostname, hostnamelen); 162 p += hl / 4; 163 *p++ = 0; /* uid */ 164 *p++ = 0; /* gid */ 165 *p++ = 0; /* auxiliary gid list */ 166 167 /* Provide an AUTH_NONE verifier. */ 168 *p++ = 0; /* AUTH_NONE */ 169 *p++ = 0; /* auth length */ 170 171 return p; 172 } 173 174 /************************************************************************** 175 RPC_LOOKUP - Lookup RPC Port numbers 176 **************************************************************************/ 177 static void 178 rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) 179 { 180 struct rpc_t pkt; 181 unsigned long id; 182 uint32_t *p; 183 int pktlen; 184 int sport; 185 186 id = ++rpc_id; 187 pkt.u.call.id = htonl(id); 188 pkt.u.call.type = htonl(MSG_CALL); 189 pkt.u.call.rpcvers = htonl(2); /* use RPC version 2 */ 190 pkt.u.call.prog = htonl(rpc_prog); 191 pkt.u.call.vers = htonl(2); /* portmapper is version 2 */ 192 pkt.u.call.proc = htonl(rpc_proc); 193 p = (uint32_t *)&(pkt.u.call.data); 194 195 if (datalen) 196 memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t)); 197 198 pktlen = (char *)p + datalen*sizeof(uint32_t) - (char *)&pkt; 199 200 memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE, 201 (char *)&pkt, pktlen); 202 203 if (rpc_prog == PROG_PORTMAP) 204 sport = SUNRPC_PORT; 205 else if (rpc_prog == PROG_MOUNT) 206 sport = NfsSrvMountPort; 207 else 208 sport = NfsSrvNfsPort; 209 210 NetSendUDPPacket(NetServerEther, NfsServerIP, sport, NfsOurPort, 211 pktlen); 212 } 213 214 /************************************************************************** 215 RPC_LOOKUP - Lookup RPC Port numbers 216 **************************************************************************/ 217 static void 218 rpc_lookup_req(int prog, int ver) 219 { 220 uint32_t data[16]; 221 222 data[0] = 0; data[1] = 0; /* auth credential */ 223 data[2] = 0; data[3] = 0; /* auth verifier */ 224 data[4] = htonl(prog); 225 data[5] = htonl(ver); 226 data[6] = htonl(17); /* IP_UDP */ 227 data[7] = 0; 228 229 rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8); 230 } 231 232 /************************************************************************** 233 NFS_MOUNT - Mount an NFS Filesystem 234 **************************************************************************/ 235 static void 236 nfs_mount_req(char *path) 237 { 238 uint32_t data[1024]; 239 uint32_t *p; 240 int len; 241 int pathlen; 242 243 pathlen = strlen(path); 244 245 p = &(data[0]); 246 p = (uint32_t *)rpc_add_credentials((long *)p); 247 248 *p++ = htonl(pathlen); 249 if (pathlen & 3) 250 *(p + pathlen / 4) = 0; 251 memcpy(p, path, pathlen); 252 p += (pathlen + 3) / 4; 253 254 len = (uint32_t *)p - (uint32_t *)&(data[0]); 255 256 rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len); 257 } 258 259 /************************************************************************** 260 NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server 261 **************************************************************************/ 262 static void 263 nfs_umountall_req(void) 264 { 265 uint32_t data[1024]; 266 uint32_t *p; 267 int len; 268 269 if ((NfsSrvMountPort == -1) || (!fs_mounted)) 270 /* Nothing mounted, nothing to umount */ 271 return; 272 273 p = &(data[0]); 274 p = (uint32_t *)rpc_add_credentials((long *)p); 275 276 len = (uint32_t *)p - (uint32_t *)&(data[0]); 277 278 rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); 279 } 280 281 /*************************************************************************** 282 * NFS_READLINK (AH 2003-07-14) 283 * This procedure is called when read of the first block fails - 284 * this probably happens when it's a directory or a symlink 285 * In case of successful readlink(), the dirname is manipulated, 286 * so that inside the nfs() function a recursion can be done. 287 **************************************************************************/ 288 static void 289 nfs_readlink_req(void) 290 { 291 uint32_t data[1024]; 292 uint32_t *p; 293 int len; 294 295 p = &(data[0]); 296 p = (uint32_t *)rpc_add_credentials((long *)p); 297 298 memcpy(p, filefh, NFS_FHSIZE); 299 p += (NFS_FHSIZE / 4); 300 301 len = (uint32_t *)p - (uint32_t *)&(data[0]); 302 303 rpc_req(PROG_NFS, NFS_READLINK, data, len); 304 } 305 306 /************************************************************************** 307 NFS_LOOKUP - Lookup Pathname 308 **************************************************************************/ 309 static void 310 nfs_lookup_req(char *fname) 311 { 312 uint32_t data[1024]; 313 uint32_t *p; 314 int len; 315 int fnamelen; 316 317 fnamelen = strlen(fname); 318 319 p = &(data[0]); 320 p = (uint32_t *)rpc_add_credentials((long *)p); 321 322 memcpy(p, dirfh, NFS_FHSIZE); 323 p += (NFS_FHSIZE / 4); 324 *p++ = htonl(fnamelen); 325 if (fnamelen & 3) 326 *(p + fnamelen / 4) = 0; 327 memcpy(p, fname, fnamelen); 328 p += (fnamelen + 3) / 4; 329 330 len = (uint32_t *)p - (uint32_t *)&(data[0]); 331 332 rpc_req(PROG_NFS, NFS_LOOKUP, data, len); 333 } 334 335 /************************************************************************** 336 NFS_READ - Read File on NFS Server 337 **************************************************************************/ 338 static void 339 nfs_read_req(int offset, int readlen) 340 { 341 uint32_t data[1024]; 342 uint32_t *p; 343 int len; 344 345 p = &(data[0]); 346 p = (uint32_t *)rpc_add_credentials((long *)p); 347 348 memcpy(p, filefh, NFS_FHSIZE); 349 p += (NFS_FHSIZE / 4); 350 *p++ = htonl(offset); 351 *p++ = htonl(readlen); 352 *p++ = 0; 353 354 len = (uint32_t *)p - (uint32_t *)&(data[0]); 355 356 rpc_req(PROG_NFS, NFS_READ, data, len); 357 } 358 359 /************************************************************************** 360 RPC request dispatcher 361 **************************************************************************/ 362 363 static void 364 NfsSend(void) 365 { 366 debug("%s\n", __func__); 367 368 switch (NfsState) { 369 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 370 rpc_lookup_req(PROG_MOUNT, 1); 371 break; 372 case STATE_PRCLOOKUP_PROG_NFS_REQ: 373 rpc_lookup_req(PROG_NFS, 2); 374 break; 375 case STATE_MOUNT_REQ: 376 nfs_mount_req(nfs_path); 377 break; 378 case STATE_UMOUNT_REQ: 379 nfs_umountall_req(); 380 break; 381 case STATE_LOOKUP_REQ: 382 nfs_lookup_req(nfs_filename); 383 break; 384 case STATE_READ_REQ: 385 nfs_read_req(nfs_offset, nfs_len); 386 break; 387 case STATE_READLINK_REQ: 388 nfs_readlink_req(); 389 break; 390 } 391 } 392 393 /************************************************************************** 394 Handlers for the reply from server 395 **************************************************************************/ 396 397 static int 398 rpc_lookup_reply(int prog, uchar *pkt, unsigned len) 399 { 400 struct rpc_t rpc_pkt; 401 402 memcpy((unsigned char *)&rpc_pkt, pkt, len); 403 404 debug("%s\n", __func__); 405 406 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 407 return -NFS_RPC_ERR; 408 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 409 return -NFS_RPC_DROP; 410 411 if (rpc_pkt.u.reply.rstatus || 412 rpc_pkt.u.reply.verifier || 413 rpc_pkt.u.reply.astatus) 414 return -1; 415 416 switch (prog) { 417 case PROG_MOUNT: 418 NfsSrvMountPort = ntohl(rpc_pkt.u.reply.data[0]); 419 break; 420 case PROG_NFS: 421 NfsSrvNfsPort = ntohl(rpc_pkt.u.reply.data[0]); 422 break; 423 } 424 425 return 0; 426 } 427 428 static int 429 nfs_mount_reply(uchar *pkt, unsigned len) 430 { 431 struct rpc_t rpc_pkt; 432 433 debug("%s\n", __func__); 434 435 memcpy((unsigned char *)&rpc_pkt, pkt, len); 436 437 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 438 return -NFS_RPC_ERR; 439 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 440 return -NFS_RPC_DROP; 441 442 if (rpc_pkt.u.reply.rstatus || 443 rpc_pkt.u.reply.verifier || 444 rpc_pkt.u.reply.astatus || 445 rpc_pkt.u.reply.data[0]) 446 return -1; 447 448 fs_mounted = 1; 449 memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 450 451 return 0; 452 } 453 454 static int 455 nfs_umountall_reply(uchar *pkt, unsigned len) 456 { 457 struct rpc_t rpc_pkt; 458 459 debug("%s\n", __func__); 460 461 memcpy((unsigned char *)&rpc_pkt, pkt, len); 462 463 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 464 return -NFS_RPC_ERR; 465 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 466 return -NFS_RPC_DROP; 467 468 if (rpc_pkt.u.reply.rstatus || 469 rpc_pkt.u.reply.verifier || 470 rpc_pkt.u.reply.astatus) 471 return -1; 472 473 fs_mounted = 0; 474 memset(dirfh, 0, sizeof(dirfh)); 475 476 return 0; 477 } 478 479 static int 480 nfs_lookup_reply(uchar *pkt, unsigned len) 481 { 482 struct rpc_t rpc_pkt; 483 484 debug("%s\n", __func__); 485 486 memcpy((unsigned char *)&rpc_pkt, pkt, len); 487 488 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 489 return -NFS_RPC_ERR; 490 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 491 return -NFS_RPC_DROP; 492 493 if (rpc_pkt.u.reply.rstatus || 494 rpc_pkt.u.reply.verifier || 495 rpc_pkt.u.reply.astatus || 496 rpc_pkt.u.reply.data[0]) 497 return -1; 498 499 memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 500 501 return 0; 502 } 503 504 static int 505 nfs_readlink_reply(uchar *pkt, unsigned len) 506 { 507 struct rpc_t rpc_pkt; 508 int rlen; 509 510 debug("%s\n", __func__); 511 512 memcpy((unsigned char *)&rpc_pkt, pkt, len); 513 514 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 515 return -NFS_RPC_ERR; 516 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 517 return -NFS_RPC_DROP; 518 519 if (rpc_pkt.u.reply.rstatus || 520 rpc_pkt.u.reply.verifier || 521 rpc_pkt.u.reply.astatus || 522 rpc_pkt.u.reply.data[0]) 523 return -1; 524 525 rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */ 526 527 if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') { 528 int pathlen; 529 strcat(nfs_path, "/"); 530 pathlen = strlen(nfs_path); 531 memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]), 532 rlen); 533 nfs_path[pathlen + rlen] = 0; 534 } else { 535 memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen); 536 nfs_path[rlen] = 0; 537 } 538 return 0; 539 } 540 541 static int 542 nfs_read_reply(uchar *pkt, unsigned len) 543 { 544 struct rpc_t rpc_pkt; 545 int rlen; 546 547 debug("%s\n", __func__); 548 549 memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply)); 550 551 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 552 return -NFS_RPC_ERR; 553 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 554 return -NFS_RPC_DROP; 555 556 if (rpc_pkt.u.reply.rstatus || 557 rpc_pkt.u.reply.verifier || 558 rpc_pkt.u.reply.astatus || 559 rpc_pkt.u.reply.data[0]) { 560 if (rpc_pkt.u.reply.rstatus) 561 return -9999; 562 if (rpc_pkt.u.reply.astatus) 563 return -9999; 564 return -ntohl(rpc_pkt.u.reply.data[0]); 565 } 566 567 if ((nfs_offset != 0) && !((nfs_offset) % 568 (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) 569 puts("\n\t "); 570 if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) 571 putc('#'); 572 573 rlen = ntohl(rpc_pkt.u.reply.data[18]); 574 if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply), 575 nfs_offset, rlen)) 576 return -9999; 577 578 return rlen; 579 } 580 581 /************************************************************************** 582 Interfaces of U-BOOT 583 **************************************************************************/ 584 585 static void 586 NfsTimeout(void) 587 { 588 if (++NfsTimeoutCount > NFS_RETRY_COUNT) { 589 puts("\nRetry count exceeded; starting again\n"); 590 NetStartAgain(); 591 } else { 592 puts("T "); 593 NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount, 594 NfsTimeout); 595 NfsSend(); 596 } 597 } 598 599 static void 600 NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) 601 { 602 int rlen; 603 int reply; 604 605 debug("%s\n", __func__); 606 607 if (dest != NfsOurPort) 608 return; 609 610 switch (NfsState) { 611 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 612 if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) 613 break; 614 NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ; 615 NfsSend(); 616 break; 617 618 case STATE_PRCLOOKUP_PROG_NFS_REQ: 619 if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) 620 break; 621 NfsState = STATE_MOUNT_REQ; 622 NfsSend(); 623 break; 624 625 case STATE_MOUNT_REQ: 626 reply = nfs_mount_reply(pkt, len); 627 if (reply == -NFS_RPC_DROP) 628 break; 629 else if (reply == -NFS_RPC_ERR) { 630 puts("*** ERROR: Cannot mount\n"); 631 /* just to be sure... */ 632 NfsState = STATE_UMOUNT_REQ; 633 NfsSend(); 634 } else { 635 NfsState = STATE_LOOKUP_REQ; 636 NfsSend(); 637 } 638 break; 639 640 case STATE_UMOUNT_REQ: 641 reply = nfs_umountall_reply(pkt, len); 642 if (reply == -NFS_RPC_DROP) 643 break; 644 else if (reply == -NFS_RPC_ERR) { 645 puts("*** ERROR: Cannot umount\n"); 646 net_set_state(NETLOOP_FAIL); 647 } else { 648 puts("\ndone\n"); 649 net_set_state(nfs_download_state); 650 } 651 break; 652 653 case STATE_LOOKUP_REQ: 654 reply = nfs_lookup_reply(pkt, len); 655 if (reply == -NFS_RPC_DROP) 656 break; 657 else if (reply == -NFS_RPC_ERR) { 658 puts("*** ERROR: File lookup fail\n"); 659 NfsState = STATE_UMOUNT_REQ; 660 NfsSend(); 661 } else { 662 NfsState = STATE_READ_REQ; 663 nfs_offset = 0; 664 nfs_len = NFS_READ_SIZE; 665 NfsSend(); 666 } 667 break; 668 669 case STATE_READLINK_REQ: 670 reply = nfs_readlink_reply(pkt, len); 671 if (reply == -NFS_RPC_DROP) 672 break; 673 else if (reply == -NFS_RPC_ERR) { 674 puts("*** ERROR: Symlink fail\n"); 675 NfsState = STATE_UMOUNT_REQ; 676 NfsSend(); 677 } else { 678 debug("Symlink --> %s\n", nfs_path); 679 nfs_filename = basename(nfs_path); 680 nfs_path = dirname(nfs_path); 681 682 NfsState = STATE_MOUNT_REQ; 683 NfsSend(); 684 } 685 break; 686 687 case STATE_READ_REQ: 688 rlen = nfs_read_reply(pkt, len); 689 NetSetTimeout(nfs_timeout, NfsTimeout); 690 if (rlen > 0) { 691 nfs_offset += rlen; 692 NfsSend(); 693 } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { 694 /* symbolic link */ 695 NfsState = STATE_READLINK_REQ; 696 NfsSend(); 697 } else { 698 if (!rlen) 699 nfs_download_state = NETLOOP_SUCCESS; 700 NfsState = STATE_UMOUNT_REQ; 701 NfsSend(); 702 } 703 break; 704 } 705 } 706 707 708 void 709 NfsStart(void) 710 { 711 debug("%s\n", __func__); 712 nfs_download_state = NETLOOP_FAIL; 713 714 NfsServerIP = NetServerIP; 715 nfs_path = (char *)nfs_path_buff; 716 717 if (nfs_path == NULL) { 718 net_set_state(NETLOOP_FAIL); 719 puts("*** ERROR: Fail allocate memory\n"); 720 return; 721 } 722 723 if (BootFile[0] == '\0') { 724 sprintf(default_filename, "/nfsroot/%02X%02X%02X%02X.img", 725 NetOurIP & 0xFF, 726 (NetOurIP >> 8) & 0xFF, 727 (NetOurIP >> 16) & 0xFF, 728 (NetOurIP >> 24) & 0xFF); 729 strcpy(nfs_path, default_filename); 730 731 printf("*** Warning: no boot file name; using '%s'\n", 732 nfs_path); 733 } else { 734 char *p = BootFile; 735 736 p = strchr(p, ':'); 737 738 if (p != NULL) { 739 NfsServerIP = string_to_ip(BootFile); 740 ++p; 741 strcpy(nfs_path, p); 742 } else { 743 strcpy(nfs_path, BootFile); 744 } 745 } 746 747 nfs_filename = basename(nfs_path); 748 nfs_path = dirname(nfs_path); 749 750 printf("Using %s device\n", eth_get_name()); 751 752 printf("File transfer via NFS from server %pI4" 753 "; our IP address is %pI4", &NfsServerIP, &NetOurIP); 754 755 /* Check if we need to send across this subnet */ 756 if (NetOurGatewayIP && NetOurSubnetMask) { 757 IPaddr_t OurNet = NetOurIP & NetOurSubnetMask; 758 IPaddr_t ServerNet = NetServerIP & NetOurSubnetMask; 759 760 if (OurNet != ServerNet) 761 printf("; sending through gateway %pI4", 762 &NetOurGatewayIP); 763 } 764 printf("\nFilename '%s/%s'.", nfs_path, nfs_filename); 765 766 if (NetBootFileSize) { 767 printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9); 768 print_size(NetBootFileSize<<9, ""); 769 } 770 printf("\nLoad address: 0x%lx\n" 771 "Loading: *\b", load_addr); 772 773 NetSetTimeout(nfs_timeout, NfsTimeout); 774 net_set_udp_handler(NfsHandler); 775 776 NfsTimeoutCount = 0; 777 NfsState = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 778 779 /*NfsOurPort = 4096 + (get_ticks() % 3072);*/ 780 /*FIX ME !!!*/ 781 NfsOurPort = 1000; 782 783 /* zero out server ether in case the server ip has changed */ 784 memset(NetServerEther, 0, 6); 785 786 NfsSend(); 787 } 788