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 *nfs_filename; 69 static char *nfs_path; 70 static char nfs_path_buff[2048]; 71 72 static inline int store_block(uchar *src, unsigned offset, unsigned len) 73 { 74 ulong newsize = offset + len; 75 #ifdef CONFIG_SYS_DIRECT_FLASH_NFS 76 int i, rc = 0; 77 78 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 79 /* start address in flash? */ 80 if (load_addr + offset >= flash_info[i].start[0]) { 81 rc = 1; 82 break; 83 } 84 } 85 86 if (rc) { /* Flash is destination for this packet */ 87 rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len); 88 if (rc) { 89 flash_perror(rc); 90 return -1; 91 } 92 } else 93 #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ 94 { 95 void *ptr = map_sysmem(load_addr + offset, len); 96 97 memcpy(ptr, src, len); 98 unmap_sysmem(ptr); 99 } 100 101 if (net_boot_file_size < (offset + len)) 102 net_boot_file_size = newsize; 103 return 0; 104 } 105 106 static char *basename(char *path) 107 { 108 char *fname; 109 110 fname = path + strlen(path) - 1; 111 while (fname >= path) { 112 if (*fname == '/') { 113 fname++; 114 break; 115 } 116 fname--; 117 } 118 return fname; 119 } 120 121 static char *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 uint32_t *rpc_add_credentials(uint32_t *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 rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) 178 { 179 struct rpc_t pkt; 180 unsigned long id; 181 uint32_t *p; 182 int pktlen; 183 int sport; 184 185 id = ++rpc_id; 186 pkt.u.call.id = htonl(id); 187 pkt.u.call.type = htonl(MSG_CALL); 188 pkt.u.call.rpcvers = htonl(2); /* use RPC version 2 */ 189 pkt.u.call.prog = htonl(rpc_prog); 190 pkt.u.call.vers = htonl(2); /* portmapper is version 2 */ 191 pkt.u.call.proc = htonl(rpc_proc); 192 p = (uint32_t *)&(pkt.u.call.data); 193 194 if (datalen) 195 memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t)); 196 197 pktlen = (char *)p + datalen*sizeof(uint32_t) - (char *)&pkt; 198 199 memcpy((char *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE, 200 (char *)&pkt, pktlen); 201 202 if (rpc_prog == PROG_PORTMAP) 203 sport = SUNRPC_PORT; 204 else if (rpc_prog == PROG_MOUNT) 205 sport = nfs_server_mount_port; 206 else 207 sport = nfs_server_port; 208 209 net_send_udp_packet(net_server_ethaddr, nfs_server_ip, sport, 210 nfs_our_port, pktlen); 211 } 212 213 /************************************************************************** 214 RPC_LOOKUP - Lookup RPC Port numbers 215 **************************************************************************/ 216 static void rpc_lookup_req(int prog, int ver) 217 { 218 uint32_t data[16]; 219 220 data[0] = 0; data[1] = 0; /* auth credential */ 221 data[2] = 0; data[3] = 0; /* auth verifier */ 222 data[4] = htonl(prog); 223 data[5] = htonl(ver); 224 data[6] = htonl(17); /* IP_UDP */ 225 data[7] = 0; 226 227 rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8); 228 } 229 230 /************************************************************************** 231 NFS_MOUNT - Mount an NFS Filesystem 232 **************************************************************************/ 233 static void nfs_mount_req(char *path) 234 { 235 uint32_t data[1024]; 236 uint32_t *p; 237 int len; 238 int pathlen; 239 240 pathlen = strlen(path); 241 242 p = &(data[0]); 243 p = rpc_add_credentials(p); 244 245 *p++ = htonl(pathlen); 246 if (pathlen & 3) 247 *(p + pathlen / 4) = 0; 248 memcpy(p, path, pathlen); 249 p += (pathlen + 3) / 4; 250 251 len = (uint32_t *)p - (uint32_t *)&(data[0]); 252 253 rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len); 254 } 255 256 /************************************************************************** 257 NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server 258 **************************************************************************/ 259 static void nfs_umountall_req(void) 260 { 261 uint32_t data[1024]; 262 uint32_t *p; 263 int len; 264 265 if ((nfs_server_mount_port == -1) || (!fs_mounted)) 266 /* Nothing mounted, nothing to umount */ 267 return; 268 269 p = &(data[0]); 270 p = rpc_add_credentials(p); 271 272 len = (uint32_t *)p - (uint32_t *)&(data[0]); 273 274 rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); 275 } 276 277 /*************************************************************************** 278 * NFS_READLINK (AH 2003-07-14) 279 * This procedure is called when read of the first block fails - 280 * this probably happens when it's a directory or a symlink 281 * In case of successful readlink(), the dirname is manipulated, 282 * so that inside the nfs() function a recursion can be done. 283 **************************************************************************/ 284 static void nfs_readlink_req(void) 285 { 286 uint32_t data[1024]; 287 uint32_t *p; 288 int len; 289 290 p = &(data[0]); 291 p = rpc_add_credentials(p); 292 293 memcpy(p, filefh, NFS_FHSIZE); 294 p += (NFS_FHSIZE / 4); 295 296 len = (uint32_t *)p - (uint32_t *)&(data[0]); 297 298 rpc_req(PROG_NFS, NFS_READLINK, data, len); 299 } 300 301 /************************************************************************** 302 NFS_LOOKUP - Lookup Pathname 303 **************************************************************************/ 304 static void nfs_lookup_req(char *fname) 305 { 306 uint32_t data[1024]; 307 uint32_t *p; 308 int len; 309 int fnamelen; 310 311 fnamelen = strlen(fname); 312 313 p = &(data[0]); 314 p = rpc_add_credentials(p); 315 316 memcpy(p, dirfh, NFS_FHSIZE); 317 p += (NFS_FHSIZE / 4); 318 *p++ = htonl(fnamelen); 319 if (fnamelen & 3) 320 *(p + fnamelen / 4) = 0; 321 memcpy(p, fname, fnamelen); 322 p += (fnamelen + 3) / 4; 323 324 len = (uint32_t *)p - (uint32_t *)&(data[0]); 325 326 rpc_req(PROG_NFS, NFS_LOOKUP, data, len); 327 } 328 329 /************************************************************************** 330 NFS_READ - Read File on NFS Server 331 **************************************************************************/ 332 static void nfs_read_req(int offset, int readlen) 333 { 334 uint32_t data[1024]; 335 uint32_t *p; 336 int len; 337 338 p = &(data[0]); 339 p = rpc_add_credentials(p); 340 341 memcpy(p, filefh, NFS_FHSIZE); 342 p += (NFS_FHSIZE / 4); 343 *p++ = htonl(offset); 344 *p++ = htonl(readlen); 345 *p++ = 0; 346 347 len = (uint32_t *)p - (uint32_t *)&(data[0]); 348 349 rpc_req(PROG_NFS, NFS_READ, data, len); 350 } 351 352 /************************************************************************** 353 RPC request dispatcher 354 **************************************************************************/ 355 static void nfs_send(void) 356 { 357 debug("%s\n", __func__); 358 359 switch (nfs_state) { 360 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 361 rpc_lookup_req(PROG_MOUNT, 1); 362 break; 363 case STATE_PRCLOOKUP_PROG_NFS_REQ: 364 rpc_lookup_req(PROG_NFS, 2); 365 break; 366 case STATE_MOUNT_REQ: 367 nfs_mount_req(nfs_path); 368 break; 369 case STATE_UMOUNT_REQ: 370 nfs_umountall_req(); 371 break; 372 case STATE_LOOKUP_REQ: 373 nfs_lookup_req(nfs_filename); 374 break; 375 case STATE_READ_REQ: 376 nfs_read_req(nfs_offset, nfs_len); 377 break; 378 case STATE_READLINK_REQ: 379 nfs_readlink_req(); 380 break; 381 } 382 } 383 384 /************************************************************************** 385 Handlers for the reply from server 386 **************************************************************************/ 387 388 static int rpc_lookup_reply(int prog, uchar *pkt, unsigned len) 389 { 390 struct rpc_t rpc_pkt; 391 392 memcpy((unsigned char *)&rpc_pkt, pkt, len); 393 394 debug("%s\n", __func__); 395 396 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 397 return -NFS_RPC_ERR; 398 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 399 return -NFS_RPC_DROP; 400 401 if (rpc_pkt.u.reply.rstatus || 402 rpc_pkt.u.reply.verifier || 403 rpc_pkt.u.reply.astatus) 404 return -1; 405 406 switch (prog) { 407 case PROG_MOUNT: 408 nfs_server_mount_port = ntohl(rpc_pkt.u.reply.data[0]); 409 break; 410 case PROG_NFS: 411 nfs_server_port = ntohl(rpc_pkt.u.reply.data[0]); 412 break; 413 } 414 415 return 0; 416 } 417 418 static int nfs_mount_reply(uchar *pkt, unsigned len) 419 { 420 struct rpc_t rpc_pkt; 421 422 debug("%s\n", __func__); 423 424 memcpy((unsigned char *)&rpc_pkt, pkt, len); 425 426 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 427 return -NFS_RPC_ERR; 428 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 429 return -NFS_RPC_DROP; 430 431 if (rpc_pkt.u.reply.rstatus || 432 rpc_pkt.u.reply.verifier || 433 rpc_pkt.u.reply.astatus || 434 rpc_pkt.u.reply.data[0]) 435 return -1; 436 437 fs_mounted = 1; 438 memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 439 440 return 0; 441 } 442 443 static int nfs_umountall_reply(uchar *pkt, unsigned len) 444 { 445 struct rpc_t rpc_pkt; 446 447 debug("%s\n", __func__); 448 449 memcpy((unsigned char *)&rpc_pkt, pkt, len); 450 451 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 452 return -NFS_RPC_ERR; 453 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 454 return -NFS_RPC_DROP; 455 456 if (rpc_pkt.u.reply.rstatus || 457 rpc_pkt.u.reply.verifier || 458 rpc_pkt.u.reply.astatus) 459 return -1; 460 461 fs_mounted = 0; 462 memset(dirfh, 0, sizeof(dirfh)); 463 464 return 0; 465 } 466 467 static int nfs_lookup_reply(uchar *pkt, unsigned len) 468 { 469 struct rpc_t rpc_pkt; 470 471 debug("%s\n", __func__); 472 473 memcpy((unsigned char *)&rpc_pkt, pkt, len); 474 475 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 476 return -NFS_RPC_ERR; 477 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 478 return -NFS_RPC_DROP; 479 480 if (rpc_pkt.u.reply.rstatus || 481 rpc_pkt.u.reply.verifier || 482 rpc_pkt.u.reply.astatus || 483 rpc_pkt.u.reply.data[0]) { 484 switch (ntohl(rpc_pkt.u.reply.astatus)) { 485 case 0: /* Not an error */ 486 break; 487 case 2: /* Remote can't support NFS version */ 488 printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n", 489 2, 490 ntohl(rpc_pkt.u.reply.data[0]), 491 ntohl(rpc_pkt.u.reply.data[1])); 492 break; 493 default: /* Unknown error on 'accept state' flag */ 494 printf("*** ERROR: accept state error (%d)\n", 495 ntohl(rpc_pkt.u.reply.astatus)); 496 break; 497 } 498 return -1; 499 } 500 501 memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 502 503 return 0; 504 } 505 506 static int nfs_readlink_reply(uchar *pkt, unsigned len) 507 { 508 struct rpc_t rpc_pkt; 509 int rlen; 510 511 debug("%s\n", __func__); 512 513 memcpy((unsigned char *)&rpc_pkt, pkt, len); 514 515 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 516 return -NFS_RPC_ERR; 517 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 518 return -NFS_RPC_DROP; 519 520 if (rpc_pkt.u.reply.rstatus || 521 rpc_pkt.u.reply.verifier || 522 rpc_pkt.u.reply.astatus || 523 rpc_pkt.u.reply.data[0]) 524 return -1; 525 526 rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */ 527 528 if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') { 529 int pathlen; 530 strcat(nfs_path, "/"); 531 pathlen = strlen(nfs_path); 532 memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]), 533 rlen); 534 nfs_path[pathlen + rlen] = 0; 535 } else { 536 memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen); 537 nfs_path[rlen] = 0; 538 } 539 return 0; 540 } 541 542 static int 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 static void nfs_timeout_handler(void) 585 { 586 if (++nfs_timeout_count > NFS_RETRY_COUNT) { 587 puts("\nRetry count exceeded; starting again\n"); 588 net_start_again(); 589 } else { 590 puts("T "); 591 net_set_timeout_handler(nfs_timeout + 592 NFS_TIMEOUT * nfs_timeout_count, 593 nfs_timeout_handler); 594 nfs_send(); 595 } 596 } 597 598 static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, 599 unsigned src, unsigned len) 600 { 601 int rlen; 602 int reply; 603 604 debug("%s\n", __func__); 605 606 if (dest != nfs_our_port) 607 return; 608 609 switch (nfs_state) { 610 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 611 if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) 612 break; 613 nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; 614 nfs_send(); 615 break; 616 617 case STATE_PRCLOOKUP_PROG_NFS_REQ: 618 if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) 619 break; 620 nfs_state = STATE_MOUNT_REQ; 621 nfs_send(); 622 break; 623 624 case STATE_MOUNT_REQ: 625 reply = nfs_mount_reply(pkt, len); 626 if (reply == -NFS_RPC_DROP) { 627 break; 628 } else if (reply == -NFS_RPC_ERR) { 629 puts("*** ERROR: Cannot mount\n"); 630 /* just to be sure... */ 631 nfs_state = STATE_UMOUNT_REQ; 632 nfs_send(); 633 } else { 634 nfs_state = STATE_LOOKUP_REQ; 635 nfs_send(); 636 } 637 break; 638 639 case STATE_UMOUNT_REQ: 640 reply = nfs_umountall_reply(pkt, len); 641 if (reply == -NFS_RPC_DROP) { 642 break; 643 } else if (reply == -NFS_RPC_ERR) { 644 puts("*** ERROR: Cannot umount\n"); 645 net_set_state(NETLOOP_FAIL); 646 } else { 647 puts("\ndone\n"); 648 net_set_state(nfs_download_state); 649 } 650 break; 651 652 case STATE_LOOKUP_REQ: 653 reply = nfs_lookup_reply(pkt, len); 654 if (reply == -NFS_RPC_DROP) { 655 break; 656 } else if (reply == -NFS_RPC_ERR) { 657 puts("*** ERROR: File lookup fail\n"); 658 nfs_state = STATE_UMOUNT_REQ; 659 nfs_send(); 660 } else { 661 nfs_state = STATE_READ_REQ; 662 nfs_offset = 0; 663 nfs_len = NFS_READ_SIZE; 664 nfs_send(); 665 } 666 break; 667 668 case STATE_READLINK_REQ: 669 reply = nfs_readlink_reply(pkt, len); 670 if (reply == -NFS_RPC_DROP) { 671 break; 672 } else if (reply == -NFS_RPC_ERR) { 673 puts("*** ERROR: Symlink fail\n"); 674 nfs_state = STATE_UMOUNT_REQ; 675 nfs_send(); 676 } else { 677 debug("Symlink --> %s\n", nfs_path); 678 nfs_filename = basename(nfs_path); 679 nfs_path = dirname(nfs_path); 680 681 nfs_state = STATE_MOUNT_REQ; 682 nfs_send(); 683 } 684 break; 685 686 case STATE_READ_REQ: 687 rlen = nfs_read_reply(pkt, len); 688 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 689 if (rlen > 0) { 690 nfs_offset += rlen; 691 nfs_send(); 692 } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { 693 /* symbolic link */ 694 nfs_state = STATE_READLINK_REQ; 695 nfs_send(); 696 } else { 697 if (!rlen) 698 nfs_download_state = NETLOOP_SUCCESS; 699 nfs_state = STATE_UMOUNT_REQ; 700 nfs_send(); 701 } 702 break; 703 } 704 } 705 706 707 void nfs_start(void) 708 { 709 debug("%s\n", __func__); 710 nfs_download_state = NETLOOP_FAIL; 711 712 nfs_server_ip = net_server_ip; 713 nfs_path = (char *)nfs_path_buff; 714 715 if (nfs_path == NULL) { 716 net_set_state(NETLOOP_FAIL); 717 puts("*** ERROR: Fail allocate memory\n"); 718 return; 719 } 720 721 if (net_boot_file_name[0] == '\0') { 722 sprintf(nfs_path, "/nfsroot/%02X%02X%02X%02X.img", 723 net_ip.s_addr & 0xFF, 724 (net_ip.s_addr >> 8) & 0xFF, 725 (net_ip.s_addr >> 16) & 0xFF, 726 (net_ip.s_addr >> 24) & 0xFF); 727 728 printf("*** Warning: no boot file name; using '%s'\n", 729 nfs_path); 730 } else { 731 char *p = net_boot_file_name; 732 733 p = strchr(p, ':'); 734 735 if (p != NULL) { 736 nfs_server_ip = string_to_ip(net_boot_file_name); 737 ++p; 738 strcpy(nfs_path, p); 739 } else { 740 strcpy(nfs_path, net_boot_file_name); 741 } 742 } 743 744 nfs_filename = basename(nfs_path); 745 nfs_path = dirname(nfs_path); 746 747 printf("Using %s device\n", eth_get_name()); 748 749 printf("File transfer via NFS from server %pI4; our IP address is %pI4", 750 &nfs_server_ip, &net_ip); 751 752 /* Check if we need to send across this subnet */ 753 if (net_gateway.s_addr && net_netmask.s_addr) { 754 struct in_addr our_net; 755 struct in_addr server_net; 756 757 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; 758 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr; 759 if (our_net.s_addr != server_net.s_addr) 760 printf("; sending through gateway %pI4", 761 &net_gateway); 762 } 763 printf("\nFilename '%s/%s'.", nfs_path, nfs_filename); 764 765 if (net_boot_file_expected_size_in_blocks) { 766 printf(" Size is 0x%x Bytes = ", 767 net_boot_file_expected_size_in_blocks << 9); 768 print_size(net_boot_file_expected_size_in_blocks << 9, ""); 769 } 770 printf("\nLoad address: 0x%lx\n" 771 "Loading: *\b", load_addr); 772 773 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 774 net_set_udp_handler(nfs_handler); 775 776 nfs_timeout_count = 0; 777 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 778 779 /*nfs_our_port = 4096 + (get_ticks() % 3072);*/ 780 /*FIX ME !!!*/ 781 nfs_our_port = 1000; 782 783 /* zero out server ether in case the server ip has changed */ 784 memset(net_server_ethaddr, 0, 6); 785 786 nfs_send(); 787 } 788