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