1 /* 2 * Copyright 1994, 1995, 2000 Neil Russell. 3 * (See License) 4 * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de 5 */ 6 7 #include <common.h> 8 #include <command.h> 9 #include <net.h> 10 #include "tftp.h" 11 #include "bootp.h" 12 13 #define WELL_KNOWN_PORT 69 /* Well known TFTP port # */ 14 #define TIMEOUT 5000UL /* Millisecs to timeout for lost pkt */ 15 #ifndef CONFIG_NET_RETRY_COUNT 16 # define TIMEOUT_COUNT 10 /* # of timeouts before giving up */ 17 #else 18 # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2) 19 #endif 20 /* (for checking the image size) */ 21 #define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */ 22 23 /* 24 * TFTP operations. 25 */ 26 #define TFTP_RRQ 1 27 #define TFTP_WRQ 2 28 #define TFTP_DATA 3 29 #define TFTP_ACK 4 30 #define TFTP_ERROR 5 31 #define TFTP_OACK 6 32 33 static ulong TftpTimeoutMSecs = TIMEOUT; 34 static int TftpTimeoutCountMax = TIMEOUT_COUNT; 35 36 /* 37 * These globals govern the timeout behavior when attempting a connection to a 38 * TFTP server. TftpRRQTimeoutMSecs specifies the number of milliseconds to 39 * wait for the server to respond to initial connection. Second global, 40 * TftpRRQTimeoutCountMax, gives the number of such connection retries. 41 * TftpRRQTimeoutCountMax must be non-negative and TftpRRQTimeoutMSecs must be 42 * positive. The globals are meant to be set (and restored) by code needing 43 * non-standard timeout behavior when initiating a TFTP transfer. 44 */ 45 ulong TftpRRQTimeoutMSecs = TIMEOUT; 46 int TftpRRQTimeoutCountMax = TIMEOUT_COUNT; 47 48 static IPaddr_t TftpServerIP; 49 static int TftpServerPort; /* The UDP port at their end */ 50 static int TftpOurPort; /* The UDP port at our end */ 51 static int TftpTimeoutCount; 52 static ulong TftpBlock; /* packet sequence number */ 53 static ulong TftpLastBlock; /* last packet sequence number received */ 54 static ulong TftpBlockWrap; /* count of sequence number wraparounds */ 55 static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */ 56 static int TftpState; 57 #ifdef CONFIG_TFTP_TSIZE 58 static int TftpTsize; /* The file size reported by the server */ 59 static short TftpNumchars; /* The number of hashes we printed */ 60 #endif 61 62 #define STATE_RRQ 1 63 #define STATE_DATA 2 64 #define STATE_TOO_LARGE 3 65 #define STATE_BAD_MAGIC 4 66 #define STATE_OACK 5 67 68 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */ 69 #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */ 70 71 #define DEFAULT_NAME_LEN (8 + 4 + 1) 72 static char default_filename[DEFAULT_NAME_LEN]; 73 74 #ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN 75 #define MAX_LEN 128 76 #else 77 #define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN 78 #endif 79 80 static char tftp_filename[MAX_LEN]; 81 82 #ifdef CONFIG_SYS_DIRECT_FLASH_TFTP 83 extern flash_info_t flash_info[]; 84 #endif 85 86 /* 512 is poor choice for ethernet, MTU is typically 1500. 87 * Minus eth.hdrs thats 1468. Can get 2x better throughput with 88 * almost-MTU block sizes. At least try... fall back to 512 if need be. 89 * (but those using CONFIG_IP_DEFRAG may want to set a larger block in cfg file) 90 */ 91 #ifdef CONFIG_TFTP_BLOCKSIZE 92 #define TFTP_MTU_BLOCKSIZE CONFIG_TFTP_BLOCKSIZE 93 #else 94 #define TFTP_MTU_BLOCKSIZE 1468 95 #endif 96 97 static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE; 98 static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE; 99 100 #ifdef CONFIG_MCAST_TFTP 101 #include <malloc.h> 102 #define MTFTP_BITMAPSIZE 0x1000 103 static unsigned *Bitmap; 104 static int PrevBitmapHole,Mapsize=MTFTP_BITMAPSIZE; 105 static uchar ProhibitMcast=0, MasterClient=0; 106 static uchar Multicast=0; 107 extern IPaddr_t Mcast_addr; 108 static int Mcast_port; 109 static ulong TftpEndingBlock; /* can get 'last' block before done..*/ 110 111 static void parse_multicast_oack(char *pkt,int len); 112 113 static void 114 mcast_cleanup(void) 115 { 116 if (Mcast_addr) eth_mcast_join(Mcast_addr, 0); 117 if (Bitmap) free(Bitmap); 118 Bitmap=NULL; 119 Mcast_addr = Multicast = Mcast_port = 0; 120 TftpEndingBlock = -1; 121 } 122 123 #endif /* CONFIG_MCAST_TFTP */ 124 125 static __inline__ void 126 store_block (unsigned block, uchar * src, unsigned len) 127 { 128 ulong offset = block * TftpBlkSize + TftpBlockWrapOffset; 129 ulong newsize = offset + len; 130 #ifdef CONFIG_SYS_DIRECT_FLASH_TFTP 131 int i, rc = 0; 132 133 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; i++) { 134 /* start address in flash? */ 135 if (flash_info[i].flash_id == FLASH_UNKNOWN) 136 continue; 137 if (load_addr + offset >= flash_info[i].start[0]) { 138 rc = 1; 139 break; 140 } 141 } 142 143 if (rc) { /* Flash is destination for this packet */ 144 rc = flash_write ((char *)src, (ulong)(load_addr+offset), len); 145 if (rc) { 146 flash_perror (rc); 147 NetState = NETLOOP_FAIL; 148 return; 149 } 150 } 151 else 152 #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ 153 { 154 (void)memcpy((void *)(load_addr + offset), src, len); 155 } 156 #ifdef CONFIG_MCAST_TFTP 157 if (Multicast) 158 ext2_set_bit(block, Bitmap); 159 #endif 160 161 if (NetBootFileXferSize < newsize) 162 NetBootFileXferSize = newsize; 163 } 164 165 static void TftpSend (void); 166 static void TftpTimeout (void); 167 168 /**********************************************************************/ 169 170 static void 171 TftpSend (void) 172 { 173 volatile uchar * pkt; 174 volatile uchar * xp; 175 int len = 0; 176 volatile ushort *s; 177 178 #ifdef CONFIG_MCAST_TFTP 179 /* Multicast TFTP.. non-MasterClients do not ACK data. */ 180 if (Multicast 181 && (TftpState == STATE_DATA) 182 && (MasterClient == 0)) 183 return; 184 #endif 185 /* 186 * We will always be sending some sort of packet, so 187 * cobble together the packet headers now. 188 */ 189 pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE; 190 191 switch (TftpState) { 192 193 case STATE_RRQ: 194 xp = pkt; 195 s = (ushort *)pkt; 196 *s++ = htons(TFTP_RRQ); 197 pkt = (uchar *)s; 198 strcpy ((char *)pkt, tftp_filename); 199 pkt += strlen(tftp_filename) + 1; 200 strcpy ((char *)pkt, "octet"); 201 pkt += 5 /*strlen("octet")*/ + 1; 202 strcpy ((char *)pkt, "timeout"); 203 pkt += 7 /*strlen("timeout")*/ + 1; 204 sprintf((char *)pkt, "%lu", TIMEOUT / 1000); 205 debug("send option \"timeout %s\"\n", (char *)pkt); 206 pkt += strlen((char *)pkt) + 1; 207 #ifdef CONFIG_TFTP_TSIZE 208 memcpy((char *)pkt, "tsize\0000\0", 8); 209 pkt += 8; 210 #endif 211 /* try for more effic. blk size */ 212 pkt += sprintf((char *)pkt,"blksize%c%d%c", 213 0,TftpBlkSizeOption,0); 214 #ifdef CONFIG_MCAST_TFTP 215 /* Check all preconditions before even trying the option */ 216 if (!ProhibitMcast 217 && (Bitmap=malloc(Mapsize)) 218 && eth_get_dev()->mcast) { 219 free(Bitmap); 220 Bitmap=NULL; 221 pkt += sprintf((char *)pkt,"multicast%c%c",0,0); 222 } 223 #endif /* CONFIG_MCAST_TFTP */ 224 len = pkt - xp; 225 break; 226 227 case STATE_OACK: 228 #ifdef CONFIG_MCAST_TFTP 229 /* My turn! Start at where I need blocks I missed.*/ 230 if (Multicast) 231 TftpBlock=ext2_find_next_zero_bit(Bitmap,(Mapsize*8),0); 232 /*..falling..*/ 233 #endif 234 case STATE_DATA: 235 xp = pkt; 236 s = (ushort *)pkt; 237 *s++ = htons(TFTP_ACK); 238 *s++ = htons(TftpBlock); 239 pkt = (uchar *)s; 240 len = pkt - xp; 241 break; 242 243 case STATE_TOO_LARGE: 244 xp = pkt; 245 s = (ushort *)pkt; 246 *s++ = htons(TFTP_ERROR); 247 *s++ = htons(3); 248 pkt = (uchar *)s; 249 strcpy ((char *)pkt, "File too large"); 250 pkt += 14 /*strlen("File too large")*/ + 1; 251 len = pkt - xp; 252 break; 253 254 case STATE_BAD_MAGIC: 255 xp = pkt; 256 s = (ushort *)pkt; 257 *s++ = htons(TFTP_ERROR); 258 *s++ = htons(2); 259 pkt = (uchar *)s; 260 strcpy ((char *)pkt, "File has bad magic"); 261 pkt += 18 /*strlen("File has bad magic")*/ + 1; 262 len = pkt - xp; 263 break; 264 } 265 266 NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, TftpOurPort, len); 267 } 268 269 270 static void 271 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) 272 { 273 ushort proto; 274 ushort *s; 275 int i; 276 277 if (dest != TftpOurPort) { 278 #ifdef CONFIG_MCAST_TFTP 279 if (Multicast 280 && (!Mcast_port || (dest != Mcast_port))) 281 #endif 282 return; 283 } 284 if (TftpState != STATE_RRQ && src != TftpServerPort) { 285 return; 286 } 287 288 if (len < 2) { 289 return; 290 } 291 len -= 2; 292 /* warning: don't use increment (++) in ntohs() macros!! */ 293 s = (ushort *)pkt; 294 proto = *s++; 295 pkt = (uchar *)s; 296 switch (ntohs(proto)) { 297 298 case TFTP_RRQ: 299 case TFTP_WRQ: 300 case TFTP_ACK: 301 break; 302 default: 303 break; 304 305 case TFTP_OACK: 306 debug("Got OACK: %s %s\n", 307 pkt, 308 pkt + strlen((char *)pkt) + 1); 309 TftpState = STATE_OACK; 310 TftpServerPort = src; 311 /* 312 * Check for 'blksize' option. 313 * Careful: "i" is signed, "len" is unsigned, thus 314 * something like "len-8" may give a *huge* number 315 */ 316 for (i=0; i+8<len; i++) { 317 if (strcmp ((char*)pkt+i,"blksize") == 0) { 318 TftpBlkSize = (unsigned short) 319 simple_strtoul((char*)pkt+i+8,NULL,10); 320 debug("Blocksize ack: %s, %d\n", 321 (char*)pkt+i+8,TftpBlkSize); 322 } 323 #ifdef CONFIG_TFTP_TSIZE 324 if (strcmp ((char*)pkt+i,"tsize") == 0) { 325 TftpTsize = simple_strtoul((char*)pkt+i+6,NULL,10); 326 debug("size = %s, %d\n", 327 (char*)pkt+i+6, TftpTsize); 328 } 329 #endif 330 } 331 #ifdef CONFIG_MCAST_TFTP 332 parse_multicast_oack((char *)pkt,len-1); 333 if ((Multicast) && (!MasterClient)) 334 TftpState = STATE_DATA; /* passive.. */ 335 else 336 #endif 337 TftpSend (); /* Send ACK */ 338 break; 339 case TFTP_DATA: 340 if (len < 2) 341 return; 342 len -= 2; 343 TftpBlock = ntohs(*(ushort *)pkt); 344 345 /* 346 * RFC1350 specifies that the first data packet will 347 * have sequence number 1. If we receive a sequence 348 * number of 0 this means that there was a wrap 349 * around of the (16 bit) counter. 350 */ 351 if (TftpBlock == 0) { 352 TftpBlockWrap++; 353 TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE; 354 printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20); 355 } 356 #ifdef CONFIG_TFTP_TSIZE 357 else if (TftpTsize) { 358 while (TftpNumchars < NetBootFileXferSize * 50 / TftpTsize) { 359 putc('#'); 360 TftpNumchars++; 361 } 362 } 363 #endif 364 else { 365 if (((TftpBlock - 1) % 10) == 0) { 366 putc ('#'); 367 } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) { 368 puts ("\n\t "); 369 } 370 } 371 372 if (TftpState == STATE_RRQ) 373 debug("Server did not acknowledge timeout option!\n"); 374 375 if (TftpState == STATE_RRQ || TftpState == STATE_OACK) { 376 /* first block received */ 377 TftpState = STATE_DATA; 378 TftpServerPort = src; 379 TftpLastBlock = 0; 380 TftpBlockWrap = 0; 381 TftpBlockWrapOffset = 0; 382 383 #ifdef CONFIG_MCAST_TFTP 384 if (Multicast) { /* start!=1 common if mcast */ 385 TftpLastBlock = TftpBlock - 1; 386 } else 387 #endif 388 if (TftpBlock != 1) { /* Assertion */ 389 printf ("\nTFTP error: " 390 "First block is not block 1 (%ld)\n" 391 "Starting again\n\n", 392 TftpBlock); 393 NetStartAgain (); 394 break; 395 } 396 } 397 398 if (TftpBlock == TftpLastBlock) { 399 /* 400 * Same block again; ignore it. 401 */ 402 break; 403 } 404 405 TftpLastBlock = TftpBlock; 406 TftpTimeoutMSecs = TIMEOUT; 407 TftpTimeoutCountMax = TIMEOUT_COUNT; 408 NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); 409 410 store_block (TftpBlock - 1, pkt + 2, len); 411 412 /* 413 * Acknoledge the block just received, which will prompt 414 * the server for the next one. 415 */ 416 #ifdef CONFIG_MCAST_TFTP 417 /* if I am the MasterClient, actively calculate what my next 418 * needed block is; else I'm passive; not ACKING 419 */ 420 if (Multicast) { 421 if (len < TftpBlkSize) { 422 TftpEndingBlock = TftpBlock; 423 } else if (MasterClient) { 424 TftpBlock = PrevBitmapHole = 425 ext2_find_next_zero_bit( 426 Bitmap, 427 (Mapsize*8), 428 PrevBitmapHole); 429 if (TftpBlock > ((Mapsize*8) - 1)) { 430 printf ("tftpfile too big\n"); 431 /* try to double it and retry */ 432 Mapsize<<=1; 433 mcast_cleanup(); 434 NetStartAgain (); 435 return; 436 } 437 TftpLastBlock = TftpBlock; 438 } 439 } 440 #endif 441 TftpSend (); 442 443 #ifdef CONFIG_MCAST_TFTP 444 if (Multicast) { 445 if (MasterClient && (TftpBlock >= TftpEndingBlock)) { 446 puts ("\nMulticast tftp done\n"); 447 mcast_cleanup(); 448 NetState = NETLOOP_SUCCESS; 449 } 450 } 451 else 452 #endif 453 if (len < TftpBlkSize) { 454 /* 455 * We received the whole thing. Try to 456 * run it. 457 */ 458 #ifdef CONFIG_TFTP_TSIZE 459 /* Print out the hash marks for the last packet received */ 460 while (TftpTsize && TftpNumchars < 49) { 461 putc('#'); 462 TftpNumchars++; 463 } 464 #endif 465 puts ("\ndone\n"); 466 NetState = NETLOOP_SUCCESS; 467 } 468 break; 469 470 case TFTP_ERROR: 471 printf ("\nTFTP error: '%s' (%d)\n", 472 pkt + 2, ntohs(*(ushort *)pkt)); 473 puts ("Starting again\n\n"); 474 #ifdef CONFIG_MCAST_TFTP 475 mcast_cleanup(); 476 #endif 477 NetStartAgain (); 478 break; 479 } 480 } 481 482 483 static void 484 TftpTimeout (void) 485 { 486 if (++TftpTimeoutCount > TftpTimeoutCountMax) { 487 puts ("\nRetry count exceeded; starting again\n"); 488 #ifdef CONFIG_MCAST_TFTP 489 mcast_cleanup(); 490 #endif 491 NetStartAgain (); 492 } else { 493 puts ("T "); 494 NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); 495 TftpSend (); 496 } 497 } 498 499 500 void 501 TftpStart (void) 502 { 503 char *ep; /* Environment pointer */ 504 505 /* Allow the user to choose tftpblocksize */ 506 if ((ep = getenv("tftpblocksize")) != NULL) 507 TftpBlkSizeOption = simple_strtol(ep, NULL, 10); 508 debug("tftp block size is %i\n", TftpBlkSizeOption); 509 510 TftpServerIP = NetServerIP; 511 if (BootFile[0] == '\0') { 512 sprintf(default_filename, "%02lX%02lX%02lX%02lX.img", 513 NetOurIP & 0xFF, 514 (NetOurIP >> 8) & 0xFF, 515 (NetOurIP >> 16) & 0xFF, 516 (NetOurIP >> 24) & 0xFF ); 517 518 strncpy(tftp_filename, default_filename, MAX_LEN); 519 tftp_filename[MAX_LEN-1] = 0; 520 521 printf ("*** Warning: no boot file name; using '%s'\n", 522 tftp_filename); 523 } else { 524 char *p = strchr (BootFile, ':'); 525 526 if (p == NULL) { 527 strncpy(tftp_filename, BootFile, MAX_LEN); 528 tftp_filename[MAX_LEN-1] = 0; 529 } else { 530 TftpServerIP = string_to_ip (BootFile); 531 strncpy(tftp_filename, p + 1, MAX_LEN); 532 tftp_filename[MAX_LEN-1] = 0; 533 } 534 } 535 536 #if defined(CONFIG_NET_MULTI) 537 printf ("Using %s device\n", eth_get_name()); 538 #endif 539 printf("TFTP from server %pI4" 540 "; our IP address is %pI4", &TftpServerIP, &NetOurIP); 541 542 /* Check if we need to send across this subnet */ 543 if (NetOurGatewayIP && NetOurSubnetMask) { 544 IPaddr_t OurNet = NetOurIP & NetOurSubnetMask; 545 IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask; 546 547 if (OurNet != ServerNet) 548 printf("; sending through gateway %pI4", &NetOurGatewayIP); 549 } 550 putc ('\n'); 551 552 printf ("Filename '%s'.", tftp_filename); 553 554 if (NetBootFileSize) { 555 printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9); 556 print_size (NetBootFileSize<<9, ""); 557 } 558 559 putc ('\n'); 560 561 printf ("Load address: 0x%lx\n", load_addr); 562 563 puts ("Loading: *\b"); 564 565 TftpTimeoutMSecs = TftpRRQTimeoutMSecs; 566 TftpTimeoutCountMax = TftpRRQTimeoutCountMax; 567 568 NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); 569 NetSetHandler (TftpHandler); 570 571 TftpServerPort = WELL_KNOWN_PORT; 572 TftpTimeoutCount = 0; 573 TftpState = STATE_RRQ; 574 /* Use a pseudo-random port unless a specific port is set */ 575 TftpOurPort = 1024 + (get_timer(0) % 3072); 576 577 #ifdef CONFIG_TFTP_PORT 578 if ((ep = getenv("tftpdstp")) != NULL) { 579 TftpServerPort = simple_strtol(ep, NULL, 10); 580 } 581 if ((ep = getenv("tftpsrcp")) != NULL) { 582 TftpOurPort= simple_strtol(ep, NULL, 10); 583 } 584 #endif 585 TftpBlock = 0; 586 587 /* zero out server ether in case the server ip has changed */ 588 memset(NetServerEther, 0, 6); 589 /* Revert TftpBlkSize to dflt */ 590 TftpBlkSize = TFTP_BLOCK_SIZE; 591 #ifdef CONFIG_MCAST_TFTP 592 mcast_cleanup(); 593 #endif 594 #ifdef CONFIG_TFTP_TSIZE 595 TftpTsize = 0; 596 TftpNumchars = 0; 597 #endif 598 599 TftpSend (); 600 } 601 602 #ifdef CONFIG_MCAST_TFTP 603 /* Credits: atftp project. 604 */ 605 606 /* pick up BcastAddr, Port, and whether I am [now] the master-client. * 607 * Frame: 608 * +-------+-----------+---+-------~~-------+---+ 609 * | opc | multicast | 0 | addr, port, mc | 0 | 610 * +-------+-----------+---+-------~~-------+---+ 611 * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then 612 * I am the new master-client so must send ACKs to DataBlocks. If I am not 613 * master-client, I'm a passive client, gathering what DataBlocks I may and 614 * making note of which ones I got in my bitmask. 615 * In theory, I never go from master->passive.. 616 * .. this comes in with pkt already pointing just past opc 617 */ 618 static void parse_multicast_oack(char *pkt, int len) 619 { 620 int i; 621 IPaddr_t addr; 622 char *mc_adr, *port, *mc; 623 624 mc_adr=port=mc=NULL; 625 /* march along looking for 'multicast\0', which has to start at least 626 * 14 bytes back from the end. 627 */ 628 for (i=0;i<len-14;i++) 629 if (strcmp (pkt+i,"multicast") == 0) 630 break; 631 if (i >= (len-14)) /* non-Multicast OACK, ign. */ 632 return; 633 634 i+=10; /* strlen multicast */ 635 mc_adr = pkt+i; 636 for (;i<len;i++) { 637 if (*(pkt+i) == ',') { 638 *(pkt+i) = '\0'; 639 if (port) { 640 mc = pkt+i+1; 641 break; 642 } else { 643 port = pkt+i+1; 644 } 645 } 646 } 647 if (!port || !mc_adr || !mc ) return; 648 if (Multicast && MasterClient) { 649 printf ("I got a OACK as master Client, WRONG!\n"); 650 return; 651 } 652 /* ..I now accept packets destined for this MCAST addr, port */ 653 if (!Multicast) { 654 if (Bitmap) { 655 printf ("Internal failure! no mcast.\n"); 656 free(Bitmap); 657 Bitmap=NULL; 658 ProhibitMcast=1; 659 return ; 660 } 661 /* I malloc instead of pre-declare; so that if the file ends 662 * up being too big for this bitmap I can retry 663 */ 664 if (!(Bitmap = malloc (Mapsize))) { 665 printf ("No Bitmap, no multicast. Sorry.\n"); 666 ProhibitMcast=1; 667 return; 668 } 669 memset (Bitmap,0,Mapsize); 670 PrevBitmapHole = 0; 671 Multicast = 1; 672 } 673 addr = string_to_ip(mc_adr); 674 if (Mcast_addr != addr) { 675 if (Mcast_addr) 676 eth_mcast_join(Mcast_addr, 0); 677 if (eth_mcast_join(Mcast_addr=addr, 1)) { 678 printf ("Fail to set mcast, revert to TFTP\n"); 679 ProhibitMcast=1; 680 mcast_cleanup(); 681 NetStartAgain(); 682 } 683 } 684 MasterClient = (unsigned char)simple_strtoul((char *)mc,NULL,10); 685 Mcast_port = (unsigned short)simple_strtoul(port,NULL,10); 686 printf ("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient); 687 return; 688 } 689 690 #endif /* Multicast TFTP */ 691