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 uint32_t *rpc_add_credentials(uint32_t *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 = rpc_add_credentials(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 = rpc_add_credentials(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 = rpc_add_credentials(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 = rpc_add_credentials(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 = rpc_add_credentials(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 switch (ntohl(rpc_pkt.u.reply.astatus)) { 486 case 0: /* Not an error */ 487 break; 488 case 2: /* Remote can't support NFS version */ 489 printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n", 490 2, 491 ntohl(rpc_pkt.u.reply.data[0]), 492 ntohl(rpc_pkt.u.reply.data[1])); 493 break; 494 default: /* Unknown error on 'accept state' flag */ 495 printf("*** ERROR: accept state error (%d)\n", 496 ntohl(rpc_pkt.u.reply.astatus)); 497 break; 498 } 499 return -1; 500 } 501 502 memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE); 503 504 return 0; 505 } 506 507 static int nfs_readlink_reply(uchar *pkt, unsigned len) 508 { 509 struct rpc_t rpc_pkt; 510 int rlen; 511 512 debug("%s\n", __func__); 513 514 memcpy((unsigned char *)&rpc_pkt, pkt, len); 515 516 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 517 return -NFS_RPC_ERR; 518 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 519 return -NFS_RPC_DROP; 520 521 if (rpc_pkt.u.reply.rstatus || 522 rpc_pkt.u.reply.verifier || 523 rpc_pkt.u.reply.astatus || 524 rpc_pkt.u.reply.data[0]) 525 return -1; 526 527 rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */ 528 529 if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') { 530 int pathlen; 531 strcat(nfs_path, "/"); 532 pathlen = strlen(nfs_path); 533 memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]), 534 rlen); 535 nfs_path[pathlen + rlen] = 0; 536 } else { 537 memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen); 538 nfs_path[rlen] = 0; 539 } 540 return 0; 541 } 542 543 static int nfs_read_reply(uchar *pkt, unsigned len) 544 { 545 struct rpc_t rpc_pkt; 546 int rlen; 547 548 debug("%s\n", __func__); 549 550 memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply)); 551 552 if (ntohl(rpc_pkt.u.reply.id) > rpc_id) 553 return -NFS_RPC_ERR; 554 else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) 555 return -NFS_RPC_DROP; 556 557 if (rpc_pkt.u.reply.rstatus || 558 rpc_pkt.u.reply.verifier || 559 rpc_pkt.u.reply.astatus || 560 rpc_pkt.u.reply.data[0]) { 561 if (rpc_pkt.u.reply.rstatus) 562 return -9999; 563 if (rpc_pkt.u.reply.astatus) 564 return -9999; 565 return -ntohl(rpc_pkt.u.reply.data[0]); 566 } 567 568 if ((nfs_offset != 0) && !((nfs_offset) % 569 (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE))) 570 puts("\n\t "); 571 if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10))) 572 putc('#'); 573 574 rlen = ntohl(rpc_pkt.u.reply.data[18]); 575 if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply), 576 nfs_offset, rlen)) 577 return -9999; 578 579 return rlen; 580 } 581 582 /************************************************************************** 583 Interfaces of U-BOOT 584 **************************************************************************/ 585 static void nfs_timeout_handler(void) 586 { 587 if (++nfs_timeout_count > NFS_RETRY_COUNT) { 588 puts("\nRetry count exceeded; starting again\n"); 589 net_start_again(); 590 } else { 591 puts("T "); 592 net_set_timeout_handler(nfs_timeout + 593 NFS_TIMEOUT * nfs_timeout_count, 594 nfs_timeout_handler); 595 nfs_send(); 596 } 597 } 598 599 static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, 600 unsigned src, unsigned len) 601 { 602 int rlen; 603 int reply; 604 605 debug("%s\n", __func__); 606 607 if (dest != nfs_our_port) 608 return; 609 610 switch (nfs_state) { 611 case STATE_PRCLOOKUP_PROG_MOUNT_REQ: 612 if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) 613 break; 614 nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; 615 nfs_send(); 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 nfs_state = STATE_MOUNT_REQ; 622 nfs_send(); 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 nfs_state = STATE_UMOUNT_REQ; 633 nfs_send(); 634 } else { 635 nfs_state = STATE_LOOKUP_REQ; 636 nfs_send(); 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 nfs_state = STATE_UMOUNT_REQ; 660 nfs_send(); 661 } else { 662 nfs_state = STATE_READ_REQ; 663 nfs_offset = 0; 664 nfs_len = NFS_READ_SIZE; 665 nfs_send(); 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 nfs_state = STATE_UMOUNT_REQ; 676 nfs_send(); 677 } else { 678 debug("Symlink --> %s\n", nfs_path); 679 nfs_filename = basename(nfs_path); 680 nfs_path = dirname(nfs_path); 681 682 nfs_state = STATE_MOUNT_REQ; 683 nfs_send(); 684 } 685 break; 686 687 case STATE_READ_REQ: 688 rlen = nfs_read_reply(pkt, len); 689 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 690 if (rlen > 0) { 691 nfs_offset += rlen; 692 nfs_send(); 693 } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) { 694 /* symbolic link */ 695 nfs_state = STATE_READLINK_REQ; 696 nfs_send(); 697 } else { 698 if (!rlen) 699 nfs_download_state = NETLOOP_SUCCESS; 700 nfs_state = STATE_UMOUNT_REQ; 701 nfs_send(); 702 } 703 break; 704 } 705 } 706 707 708 void nfs_start(void) 709 { 710 debug("%s\n", __func__); 711 nfs_download_state = NETLOOP_FAIL; 712 713 nfs_server_ip = net_server_ip; 714 nfs_path = (char *)nfs_path_buff; 715 716 if (nfs_path == NULL) { 717 net_set_state(NETLOOP_FAIL); 718 puts("*** ERROR: Fail allocate memory\n"); 719 return; 720 } 721 722 if (net_boot_file_name[0] == '\0') { 723 sprintf(default_filename, "/nfsroot/%02X%02X%02X%02X.img", 724 net_ip.s_addr & 0xFF, 725 (net_ip.s_addr >> 8) & 0xFF, 726 (net_ip.s_addr >> 16) & 0xFF, 727 (net_ip.s_addr >> 24) & 0xFF); 728 strcpy(nfs_path, default_filename); 729 730 printf("*** Warning: no boot file name; using '%s'\n", 731 nfs_path); 732 } else { 733 char *p = net_boot_file_name; 734 735 p = strchr(p, ':'); 736 737 if (p != NULL) { 738 nfs_server_ip = string_to_ip(net_boot_file_name); 739 ++p; 740 strcpy(nfs_path, p); 741 } else { 742 strcpy(nfs_path, net_boot_file_name); 743 } 744 } 745 746 nfs_filename = basename(nfs_path); 747 nfs_path = dirname(nfs_path); 748 749 printf("Using %s device\n", eth_get_name()); 750 751 printf("File transfer via NFS from server %pI4; our IP address is %pI4", 752 &nfs_server_ip, &net_ip); 753 754 /* Check if we need to send across this subnet */ 755 if (net_gateway.s_addr && net_netmask.s_addr) { 756 struct in_addr our_net; 757 struct in_addr server_net; 758 759 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; 760 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr; 761 if (our_net.s_addr != server_net.s_addr) 762 printf("; sending through gateway %pI4", 763 &net_gateway); 764 } 765 printf("\nFilename '%s/%s'.", nfs_path, nfs_filename); 766 767 if (net_boot_file_expected_size_in_blocks) { 768 printf(" Size is 0x%x Bytes = ", 769 net_boot_file_expected_size_in_blocks << 9); 770 print_size(net_boot_file_expected_size_in_blocks << 9, ""); 771 } 772 printf("\nLoad address: 0x%lx\n" 773 "Loading: *\b", load_addr); 774 775 net_set_timeout_handler(nfs_timeout, nfs_timeout_handler); 776 net_set_udp_handler(nfs_handler); 777 778 nfs_timeout_count = 0; 779 nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ; 780 781 /*nfs_our_port = 4096 + (get_ticks() % 3072);*/ 782 /*FIX ME !!!*/ 783 nfs_our_port = 1000; 784 785 /* zero out server ether in case the server ip has changed */ 786 memset(net_server_ethaddr, 0, 6); 787 788 nfs_send(); 789 } 790