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