1 /* 2 * Copied from Linux Monitor (LiMon) - Networking. 3 * 4 * Copyright 1994 - 2000 Neil Russell. 5 * (See License) 6 * Copyright 2000 Roland Borde 7 * Copyright 2000 Paolo Scaffardi 8 * Copyright 2000-2002 Wolfgang Denk, wd@denx.de 9 * SPDX-License-Identifier: GPL-2.0 10 */ 11 12 /* 13 * General Desription: 14 * 15 * The user interface supports commands for BOOTP, RARP, and TFTP. 16 * Also, we support ARP internally. Depending on available data, 17 * these interact as follows: 18 * 19 * BOOTP: 20 * 21 * Prerequisites: - own ethernet address 22 * We want: - own IP address 23 * - TFTP server IP address 24 * - name of bootfile 25 * Next step: ARP 26 * 27 * LINK_LOCAL: 28 * 29 * Prerequisites: - own ethernet address 30 * We want: - own IP address 31 * Next step: ARP 32 * 33 * RARP: 34 * 35 * Prerequisites: - own ethernet address 36 * We want: - own IP address 37 * - TFTP server IP address 38 * Next step: ARP 39 * 40 * ARP: 41 * 42 * Prerequisites: - own ethernet address 43 * - own IP address 44 * - TFTP server IP address 45 * We want: - TFTP server ethernet address 46 * Next step: TFTP 47 * 48 * DHCP: 49 * 50 * Prerequisites: - own ethernet address 51 * We want: - IP, Netmask, ServerIP, Gateway IP 52 * - bootfilename, lease time 53 * Next step: - TFTP 54 * 55 * TFTP: 56 * 57 * Prerequisites: - own ethernet address 58 * - own IP address 59 * - TFTP server IP address 60 * - TFTP server ethernet address 61 * - name of bootfile (if unknown, we use a default name 62 * derived from our own IP address) 63 * We want: - load the boot file 64 * Next step: none 65 * 66 * NFS: 67 * 68 * Prerequisites: - own ethernet address 69 * - own IP address 70 * - name of bootfile (if unknown, we use a default name 71 * derived from our own IP address) 72 * We want: - load the boot file 73 * Next step: none 74 * 75 * SNTP: 76 * 77 * Prerequisites: - own ethernet address 78 * - own IP address 79 * We want: - network time 80 * Next step: none 81 */ 82 83 84 #include <common.h> 85 #include <command.h> 86 #include <environment.h> 87 #include <errno.h> 88 #include <net.h> 89 #if defined(CONFIG_STATUS_LED) 90 #include <miiphy.h> 91 #include <status_led.h> 92 #endif 93 #include <watchdog.h> 94 #include <linux/compiler.h> 95 #include "arp.h" 96 #include "bootp.h" 97 #include "cdp.h" 98 #if defined(CONFIG_CMD_DNS) 99 #include "dns.h" 100 #endif 101 #include "link_local.h" 102 #include "nfs.h" 103 #include "ping.h" 104 #include "rarp.h" 105 #if defined(CONFIG_CMD_SNTP) 106 #include "sntp.h" 107 #endif 108 #include "tftp.h" 109 110 DECLARE_GLOBAL_DATA_PTR; 111 112 /** BOOTP EXTENTIONS **/ 113 114 /* Our subnet mask (0=unknown) */ 115 IPaddr_t NetOurSubnetMask; 116 /* Our gateways IP address */ 117 IPaddr_t NetOurGatewayIP; 118 /* Our DNS IP address */ 119 IPaddr_t NetOurDNSIP; 120 #if defined(CONFIG_BOOTP_DNS2) 121 /* Our 2nd DNS IP address */ 122 IPaddr_t NetOurDNS2IP; 123 #endif 124 /* Our NIS domain */ 125 char NetOurNISDomain[32] = {0,}; 126 /* Our hostname */ 127 char NetOurHostName[32] = {0,}; 128 /* Our bootpath */ 129 char NetOurRootPath[64] = {0,}; 130 /* Our bootfile size in blocks */ 131 ushort NetBootFileSize; 132 133 #ifdef CONFIG_MCAST_TFTP /* Multicast TFTP */ 134 IPaddr_t Mcast_addr; 135 #endif 136 137 /** END OF BOOTP EXTENTIONS **/ 138 139 /* The actual transferred size of the bootfile (in bytes) */ 140 ulong NetBootFileXferSize; 141 /* Our ethernet address */ 142 uchar NetOurEther[6]; 143 /* Boot server enet address */ 144 uchar NetServerEther[6]; 145 /* Our IP addr (0 = unknown) */ 146 IPaddr_t NetOurIP; 147 /* Server IP addr (0 = unknown) */ 148 IPaddr_t NetServerIP; 149 /* Current receive packet */ 150 uchar *NetRxPacket; 151 /* Current rx packet length */ 152 int NetRxPacketLen; 153 /* IP packet ID */ 154 unsigned NetIPID; 155 /* Ethernet bcast address */ 156 uchar NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 157 uchar NetEtherNullAddr[6]; 158 #ifdef CONFIG_API 159 void (*push_packet)(void *, int len) = 0; 160 #endif 161 /* Network loop state */ 162 enum net_loop_state net_state; 163 /* Tried all network devices */ 164 int NetRestartWrap; 165 /* Network loop restarted */ 166 static int NetRestarted; 167 /* At least one device configured */ 168 static int NetDevExists; 169 170 /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */ 171 /* default is without VLAN */ 172 ushort NetOurVLAN = 0xFFFF; 173 /* ditto */ 174 ushort NetOurNativeVLAN = 0xFFFF; 175 176 /* Boot File name */ 177 char BootFile[128]; 178 179 #if defined(CONFIG_CMD_SNTP) 180 /* NTP server IP address */ 181 IPaddr_t NetNtpServerIP; 182 /* offset time from UTC */ 183 int NetTimeOffset; 184 #endif 185 186 static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN]; 187 #ifdef CONFIG_DM_ETH 188 /* Receive packets */ 189 uchar *net_rx_packets[PKTBUFSRX]; 190 #else 191 /* Receive packet */ 192 uchar *NetRxPackets[PKTBUFSRX]; 193 #endif 194 /* Current UDP RX packet handler */ 195 static rxhand_f *udp_packet_handler; 196 /* Current ARP RX packet handler */ 197 static rxhand_f *arp_packet_handler; 198 #ifdef CONFIG_CMD_TFTPPUT 199 /* Current ICMP rx handler */ 200 static rxhand_icmp_f *packet_icmp_handler; 201 #endif 202 /* Current timeout handler */ 203 static thand_f *timeHandler; 204 /* Time base value */ 205 static ulong timeStart; 206 /* Current timeout value */ 207 static ulong timeDelta; 208 /* THE transmit packet */ 209 uchar *NetTxPacket; 210 211 static int net_check_prereq(enum proto_t protocol); 212 213 static int NetTryCount; 214 215 int __maybe_unused net_busy_flag; 216 217 /**********************************************************************/ 218 219 static int on_bootfile(const char *name, const char *value, enum env_op op, 220 int flags) 221 { 222 switch (op) { 223 case env_op_create: 224 case env_op_overwrite: 225 copy_filename(BootFile, value, sizeof(BootFile)); 226 break; 227 default: 228 break; 229 } 230 231 return 0; 232 } 233 U_BOOT_ENV_CALLBACK(bootfile, on_bootfile); 234 235 /* 236 * Check if autoload is enabled. If so, use either NFS or TFTP to download 237 * the boot file. 238 */ 239 void net_auto_load(void) 240 { 241 #if defined(CONFIG_CMD_NFS) 242 const char *s = getenv("autoload"); 243 244 if (s != NULL && strcmp(s, "NFS") == 0) { 245 /* 246 * Use NFS to load the bootfile. 247 */ 248 NfsStart(); 249 return; 250 } 251 #endif 252 if (getenv_yesno("autoload") == 0) { 253 /* 254 * Just use BOOTP/RARP to configure system; 255 * Do not use TFTP to load the bootfile. 256 */ 257 net_set_state(NETLOOP_SUCCESS); 258 return; 259 } 260 TftpStart(TFTPGET); 261 } 262 263 static void NetInitLoop(void) 264 { 265 static int env_changed_id; 266 int env_id = get_env_id(); 267 268 /* update only when the environment has changed */ 269 if (env_changed_id != env_id) { 270 NetOurIP = getenv_IPaddr("ipaddr"); 271 NetOurGatewayIP = getenv_IPaddr("gatewayip"); 272 NetOurSubnetMask = getenv_IPaddr("netmask"); 273 NetServerIP = getenv_IPaddr("serverip"); 274 NetOurNativeVLAN = getenv_VLAN("nvlan"); 275 NetOurVLAN = getenv_VLAN("vlan"); 276 #if defined(CONFIG_CMD_DNS) 277 NetOurDNSIP = getenv_IPaddr("dnsip"); 278 #endif 279 env_changed_id = env_id; 280 } 281 if (eth_get_dev()) 282 memcpy(NetOurEther, eth_get_ethaddr(), 6); 283 284 return; 285 } 286 287 static void net_clear_handlers(void) 288 { 289 net_set_udp_handler(NULL); 290 net_set_arp_handler(NULL); 291 NetSetTimeout(0, NULL); 292 } 293 294 static void net_cleanup_loop(void) 295 { 296 net_clear_handlers(); 297 } 298 299 void net_init(void) 300 { 301 static int first_call = 1; 302 303 if (first_call) { 304 /* 305 * Setup packet buffers, aligned correctly. 306 */ 307 int i; 308 309 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); 310 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; 311 #ifdef CONFIG_DM_ETH 312 for (i = 0; i < PKTBUFSRX; i++) { 313 net_rx_packets[i] = NetTxPacket + (i + 1) * 314 PKTSIZE_ALIGN; 315 } 316 #else 317 for (i = 0; i < PKTBUFSRX; i++) 318 NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN; 319 #endif 320 ArpInit(); 321 net_clear_handlers(); 322 323 /* Only need to setup buffer pointers once. */ 324 first_call = 0; 325 } 326 327 NetInitLoop(); 328 } 329 330 /**********************************************************************/ 331 /* 332 * Main network processing loop. 333 */ 334 335 int NetLoop(enum proto_t protocol) 336 { 337 int ret = -EINVAL; 338 339 NetRestarted = 0; 340 NetDevExists = 0; 341 NetTryCount = 1; 342 debug_cond(DEBUG_INT_STATE, "--- NetLoop Entry\n"); 343 344 bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); 345 net_init(); 346 if (eth_is_on_demand_init() || protocol != NETCONS) { 347 eth_halt(); 348 eth_set_current(); 349 ret = eth_init(); 350 if (ret < 0) { 351 eth_halt(); 352 return ret; 353 } 354 } else 355 eth_init_state_only(); 356 357 restart: 358 #ifdef CONFIG_USB_KEYBOARD 359 net_busy_flag = 0; 360 #endif 361 net_set_state(NETLOOP_CONTINUE); 362 363 /* 364 * Start the ball rolling with the given start function. From 365 * here on, this code is a state machine driven by received 366 * packets and timer events. 367 */ 368 debug_cond(DEBUG_INT_STATE, "--- NetLoop Init\n"); 369 NetInitLoop(); 370 371 switch (net_check_prereq(protocol)) { 372 case 1: 373 /* network not configured */ 374 eth_halt(); 375 return -ENODEV; 376 377 case 2: 378 /* network device not configured */ 379 break; 380 381 case 0: 382 NetDevExists = 1; 383 NetBootFileXferSize = 0; 384 switch (protocol) { 385 case TFTPGET: 386 #ifdef CONFIG_CMD_TFTPPUT 387 case TFTPPUT: 388 #endif 389 /* always use ARP to get server ethernet address */ 390 TftpStart(protocol); 391 break; 392 #ifdef CONFIG_CMD_TFTPSRV 393 case TFTPSRV: 394 TftpStartServer(); 395 break; 396 #endif 397 #if defined(CONFIG_CMD_DHCP) 398 case DHCP: 399 BootpReset(); 400 NetOurIP = 0; 401 DhcpRequest(); /* Basically same as BOOTP */ 402 break; 403 #endif 404 405 case BOOTP: 406 BootpReset(); 407 NetOurIP = 0; 408 BootpRequest(); 409 break; 410 411 #if defined(CONFIG_CMD_RARP) 412 case RARP: 413 RarpTry = 0; 414 NetOurIP = 0; 415 RarpRequest(); 416 break; 417 #endif 418 #if defined(CONFIG_CMD_PING) 419 case PING: 420 ping_start(); 421 break; 422 #endif 423 #if defined(CONFIG_CMD_NFS) 424 case NFS: 425 NfsStart(); 426 break; 427 #endif 428 #if defined(CONFIG_CMD_CDP) 429 case CDP: 430 CDPStart(); 431 break; 432 #endif 433 #if defined (CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD) 434 case NETCONS: 435 NcStart(); 436 break; 437 #endif 438 #if defined(CONFIG_CMD_SNTP) 439 case SNTP: 440 SntpStart(); 441 break; 442 #endif 443 #if defined(CONFIG_CMD_DNS) 444 case DNS: 445 DnsStart(); 446 break; 447 #endif 448 #if defined(CONFIG_CMD_LINK_LOCAL) 449 case LINKLOCAL: 450 link_local_start(); 451 break; 452 #endif 453 default: 454 break; 455 } 456 457 break; 458 } 459 460 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 461 #if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \ 462 defined(CONFIG_STATUS_LED) && \ 463 defined(STATUS_LED_RED) 464 /* 465 * Echo the inverted link state to the fault LED. 466 */ 467 if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) 468 status_led_set(STATUS_LED_RED, STATUS_LED_OFF); 469 else 470 status_led_set(STATUS_LED_RED, STATUS_LED_ON); 471 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */ 472 #endif /* CONFIG_MII, ... */ 473 #ifdef CONFIG_USB_KEYBOARD 474 net_busy_flag = 1; 475 #endif 476 477 /* 478 * Main packet reception loop. Loop receiving packets until 479 * someone sets `net_state' to a state that terminates. 480 */ 481 for (;;) { 482 WATCHDOG_RESET(); 483 #ifdef CONFIG_SHOW_ACTIVITY 484 show_activity(1); 485 #endif 486 /* 487 * Check the ethernet for a new packet. The ethernet 488 * receive routine will process it. 489 * Most drivers return the most recent packet size, but not 490 * errors that may have happened. 491 */ 492 eth_rx(); 493 494 /* 495 * Abort if ctrl-c was pressed. 496 */ 497 if (ctrlc()) { 498 /* cancel any ARP that may not have completed */ 499 NetArpWaitPacketIP = 0; 500 501 net_cleanup_loop(); 502 eth_halt(); 503 /* Invalidate the last protocol */ 504 eth_set_last_protocol(BOOTP); 505 506 puts("\nAbort\n"); 507 /* include a debug print as well incase the debug 508 messages are directed to stderr */ 509 debug_cond(DEBUG_INT_STATE, "--- NetLoop Abort!\n"); 510 goto done; 511 } 512 513 ArpTimeoutCheck(); 514 515 /* 516 * Check for a timeout, and run the timeout handler 517 * if we have one. 518 */ 519 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) { 520 thand_f *x; 521 522 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 523 #if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \ 524 defined(CONFIG_STATUS_LED) && \ 525 defined(STATUS_LED_RED) 526 /* 527 * Echo the inverted link state to the fault LED. 528 */ 529 if (miiphy_link(eth_get_dev()->name, 530 CONFIG_SYS_FAULT_MII_ADDR)) { 531 status_led_set(STATUS_LED_RED, STATUS_LED_OFF); 532 } else { 533 status_led_set(STATUS_LED_RED, STATUS_LED_ON); 534 } 535 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */ 536 #endif /* CONFIG_MII, ... */ 537 debug_cond(DEBUG_INT_STATE, "--- NetLoop timeout\n"); 538 x = timeHandler; 539 timeHandler = (thand_f *)0; 540 (*x)(); 541 } 542 543 if (net_state == NETLOOP_FAIL) 544 ret = NetStartAgain(); 545 546 switch (net_state) { 547 548 case NETLOOP_RESTART: 549 NetRestarted = 1; 550 goto restart; 551 552 case NETLOOP_SUCCESS: 553 net_cleanup_loop(); 554 if (NetBootFileXferSize > 0) { 555 printf("Bytes transferred = %ld (%lx hex)\n", 556 NetBootFileXferSize, 557 NetBootFileXferSize); 558 setenv_hex("filesize", NetBootFileXferSize); 559 setenv_hex("fileaddr", load_addr); 560 } 561 if (protocol != NETCONS) 562 eth_halt(); 563 else 564 eth_halt_state_only(); 565 566 eth_set_last_protocol(protocol); 567 568 ret = NetBootFileXferSize; 569 debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n"); 570 goto done; 571 572 case NETLOOP_FAIL: 573 net_cleanup_loop(); 574 /* Invalidate the last protocol */ 575 eth_set_last_protocol(BOOTP); 576 debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n"); 577 goto done; 578 579 case NETLOOP_CONTINUE: 580 continue; 581 } 582 } 583 584 done: 585 #ifdef CONFIG_USB_KEYBOARD 586 net_busy_flag = 0; 587 #endif 588 #ifdef CONFIG_CMD_TFTPPUT 589 /* Clear out the handlers */ 590 net_set_udp_handler(NULL); 591 net_set_icmp_handler(NULL); 592 #endif 593 return ret; 594 } 595 596 /**********************************************************************/ 597 598 static void 599 startAgainTimeout(void) 600 { 601 net_set_state(NETLOOP_RESTART); 602 } 603 604 int NetStartAgain(void) 605 { 606 char *nretry; 607 int retry_forever = 0; 608 unsigned long retrycnt = 0; 609 int ret; 610 611 nretry = getenv("netretry"); 612 if (nretry) { 613 if (!strcmp(nretry, "yes")) 614 retry_forever = 1; 615 else if (!strcmp(nretry, "no")) 616 retrycnt = 0; 617 else if (!strcmp(nretry, "once")) 618 retrycnt = 1; 619 else 620 retrycnt = simple_strtoul(nretry, NULL, 0); 621 } else { 622 retrycnt = 0; 623 retry_forever = 0; 624 } 625 626 if ((!retry_forever) && (NetTryCount >= retrycnt)) { 627 eth_halt(); 628 net_set_state(NETLOOP_FAIL); 629 /* 630 * We don't provide a way for the protocol to return an error, 631 * but this is almost always the reason. 632 */ 633 return -ETIMEDOUT; 634 } 635 636 NetTryCount++; 637 638 eth_halt(); 639 #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) 640 eth_try_another(!NetRestarted); 641 #endif 642 ret = eth_init(); 643 if (NetRestartWrap) { 644 NetRestartWrap = 0; 645 if (NetDevExists) { 646 NetSetTimeout(10000UL, startAgainTimeout); 647 net_set_udp_handler(NULL); 648 } else { 649 net_set_state(NETLOOP_FAIL); 650 } 651 } else { 652 net_set_state(NETLOOP_RESTART); 653 } 654 return ret; 655 } 656 657 /**********************************************************************/ 658 /* 659 * Miscelaneous bits. 660 */ 661 662 static void dummy_handler(uchar *pkt, unsigned dport, 663 IPaddr_t sip, unsigned sport, 664 unsigned len) 665 { 666 } 667 668 rxhand_f *net_get_udp_handler(void) 669 { 670 return udp_packet_handler; 671 } 672 673 void net_set_udp_handler(rxhand_f *f) 674 { 675 debug_cond(DEBUG_INT_STATE, "--- NetLoop UDP handler set (%p)\n", f); 676 if (f == NULL) 677 udp_packet_handler = dummy_handler; 678 else 679 udp_packet_handler = f; 680 } 681 682 rxhand_f *net_get_arp_handler(void) 683 { 684 return arp_packet_handler; 685 } 686 687 void net_set_arp_handler(rxhand_f *f) 688 { 689 debug_cond(DEBUG_INT_STATE, "--- NetLoop ARP handler set (%p)\n", f); 690 if (f == NULL) 691 arp_packet_handler = dummy_handler; 692 else 693 arp_packet_handler = f; 694 } 695 696 #ifdef CONFIG_CMD_TFTPPUT 697 void net_set_icmp_handler(rxhand_icmp_f *f) 698 { 699 packet_icmp_handler = f; 700 } 701 #endif 702 703 void 704 NetSetTimeout(ulong iv, thand_f *f) 705 { 706 if (iv == 0) { 707 debug_cond(DEBUG_INT_STATE, 708 "--- NetLoop timeout handler cancelled\n"); 709 timeHandler = (thand_f *)0; 710 } else { 711 debug_cond(DEBUG_INT_STATE, 712 "--- NetLoop timeout handler set (%p)\n", f); 713 timeHandler = f; 714 timeStart = get_timer(0); 715 timeDelta = iv * CONFIG_SYS_HZ / 1000; 716 } 717 } 718 719 int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, 720 int payload_len) 721 { 722 uchar *pkt; 723 int eth_hdr_size; 724 int pkt_hdr_size; 725 726 /* make sure the NetTxPacket is initialized (NetInit() was called) */ 727 assert(NetTxPacket != NULL); 728 if (NetTxPacket == NULL) 729 return -1; 730 731 /* convert to new style broadcast */ 732 if (dest == 0) 733 dest = 0xFFFFFFFF; 734 735 /* if broadcast, make the ether address a broadcast and don't do ARP */ 736 if (dest == 0xFFFFFFFF) 737 ether = NetBcastAddr; 738 739 pkt = (uchar *)NetTxPacket; 740 741 eth_hdr_size = NetSetEther(pkt, ether, PROT_IP); 742 pkt += eth_hdr_size; 743 net_set_udp_header(pkt, dest, dport, sport, payload_len); 744 pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE; 745 746 /* if MAC address was not discovered yet, do an ARP request */ 747 if (memcmp(ether, NetEtherNullAddr, 6) == 0) { 748 debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest); 749 750 /* save the ip and eth addr for the packet to send after arp */ 751 NetArpWaitPacketIP = dest; 752 NetArpWaitPacketMAC = ether; 753 754 /* size of the waiting packet */ 755 NetArpWaitTxPacketSize = pkt_hdr_size + payload_len; 756 757 /* and do the ARP request */ 758 NetArpWaitTry = 1; 759 NetArpWaitTimerStart = get_timer(0); 760 ArpRequest(); 761 return 1; /* waiting */ 762 } else { 763 debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n", 764 &dest, ether); 765 NetSendPacket(NetTxPacket, pkt_hdr_size + payload_len); 766 return 0; /* transmitted */ 767 } 768 } 769 770 #ifdef CONFIG_IP_DEFRAG 771 /* 772 * This function collects fragments in a single packet, according 773 * to the algorithm in RFC815. It returns NULL or the pointer to 774 * a complete packet, in static storage 775 */ 776 #ifndef CONFIG_NET_MAXDEFRAG 777 #define CONFIG_NET_MAXDEFRAG 16384 778 #endif 779 /* 780 * MAXDEFRAG, above, is chosen in the config file and is real data 781 * so we need to add the NFS overhead, which is more than TFTP. 782 * To use sizeof in the internal unnamed structures, we need a real 783 * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately). 784 * The compiler doesn't complain nor allocates the actual structure 785 */ 786 static struct rpc_t rpc_specimen; 787 #define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply)) 788 789 #define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE) 790 791 /* 792 * this is the packet being assembled, either data or frag control. 793 * Fragments go by 8 bytes, so this union must be 8 bytes long 794 */ 795 struct hole { 796 /* first_byte is address of this structure */ 797 u16 last_byte; /* last byte in this hole + 1 (begin of next hole) */ 798 u16 next_hole; /* index of next (in 8-b blocks), 0 == none */ 799 u16 prev_hole; /* index of prev, 0 == none */ 800 u16 unused; 801 }; 802 803 static struct ip_udp_hdr *__NetDefragment(struct ip_udp_hdr *ip, int *lenp) 804 { 805 static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN); 806 static u16 first_hole, total_len; 807 struct hole *payload, *thisfrag, *h, *newh; 808 struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff; 809 uchar *indata = (uchar *)ip; 810 int offset8, start, len, done = 0; 811 u16 ip_off = ntohs(ip->ip_off); 812 813 /* payload starts after IP header, this fragment is in there */ 814 payload = (struct hole *)(pkt_buff + IP_HDR_SIZE); 815 offset8 = (ip_off & IP_OFFS); 816 thisfrag = payload + offset8; 817 start = offset8 * 8; 818 len = ntohs(ip->ip_len) - IP_HDR_SIZE; 819 820 if (start + len > IP_MAXUDP) /* fragment extends too far */ 821 return NULL; 822 823 if (!total_len || localip->ip_id != ip->ip_id) { 824 /* new (or different) packet, reset structs */ 825 total_len = 0xffff; 826 payload[0].last_byte = ~0; 827 payload[0].next_hole = 0; 828 payload[0].prev_hole = 0; 829 first_hole = 0; 830 /* any IP header will work, copy the first we received */ 831 memcpy(localip, ip, IP_HDR_SIZE); 832 } 833 834 /* 835 * What follows is the reassembly algorithm. We use the payload 836 * array as a linked list of hole descriptors, as each hole starts 837 * at a multiple of 8 bytes. However, last byte can be whatever value, 838 * so it is represented as byte count, not as 8-byte blocks. 839 */ 840 841 h = payload + first_hole; 842 while (h->last_byte < start) { 843 if (!h->next_hole) { 844 /* no hole that far away */ 845 return NULL; 846 } 847 h = payload + h->next_hole; 848 } 849 850 /* last fragment may be 1..7 bytes, the "+7" forces acceptance */ 851 if (offset8 + ((len + 7) / 8) <= h - payload) { 852 /* no overlap with holes (dup fragment?) */ 853 return NULL; 854 } 855 856 if (!(ip_off & IP_FLAGS_MFRAG)) { 857 /* no more fragmentss: truncate this (last) hole */ 858 total_len = start + len; 859 h->last_byte = start + len; 860 } 861 862 /* 863 * There is some overlap: fix the hole list. This code doesn't 864 * deal with a fragment that overlaps with two different holes 865 * (thus being a superset of a previously-received fragment). 866 */ 867 868 if ((h >= thisfrag) && (h->last_byte <= start + len)) { 869 /* complete overlap with hole: remove hole */ 870 if (!h->prev_hole && !h->next_hole) { 871 /* last remaining hole */ 872 done = 1; 873 } else if (!h->prev_hole) { 874 /* first hole */ 875 first_hole = h->next_hole; 876 payload[h->next_hole].prev_hole = 0; 877 } else if (!h->next_hole) { 878 /* last hole */ 879 payload[h->prev_hole].next_hole = 0; 880 } else { 881 /* in the middle of the list */ 882 payload[h->next_hole].prev_hole = h->prev_hole; 883 payload[h->prev_hole].next_hole = h->next_hole; 884 } 885 886 } else if (h->last_byte <= start + len) { 887 /* overlaps with final part of the hole: shorten this hole */ 888 h->last_byte = start; 889 890 } else if (h >= thisfrag) { 891 /* overlaps with initial part of the hole: move this hole */ 892 newh = thisfrag + (len / 8); 893 *newh = *h; 894 h = newh; 895 if (h->next_hole) 896 payload[h->next_hole].prev_hole = (h - payload); 897 if (h->prev_hole) 898 payload[h->prev_hole].next_hole = (h - payload); 899 else 900 first_hole = (h - payload); 901 902 } else { 903 /* fragment sits in the middle: split the hole */ 904 newh = thisfrag + (len / 8); 905 *newh = *h; 906 h->last_byte = start; 907 h->next_hole = (newh - payload); 908 newh->prev_hole = (h - payload); 909 if (newh->next_hole) 910 payload[newh->next_hole].prev_hole = (newh - payload); 911 } 912 913 /* finally copy this fragment and possibly return whole packet */ 914 memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len); 915 if (!done) 916 return NULL; 917 918 localip->ip_len = htons(total_len); 919 *lenp = total_len + IP_HDR_SIZE; 920 return localip; 921 } 922 923 static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp) 924 { 925 u16 ip_off = ntohs(ip->ip_off); 926 if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG))) 927 return ip; /* not a fragment */ 928 return __NetDefragment(ip, lenp); 929 } 930 931 #else /* !CONFIG_IP_DEFRAG */ 932 933 static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp) 934 { 935 u16 ip_off = ntohs(ip->ip_off); 936 if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG))) 937 return ip; /* not a fragment */ 938 return NULL; 939 } 940 #endif 941 942 /** 943 * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently 944 * drop others. 945 * 946 * @parma ip IP packet containing the ICMP 947 */ 948 static void receive_icmp(struct ip_udp_hdr *ip, int len, 949 IPaddr_t src_ip, struct ethernet_hdr *et) 950 { 951 struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; 952 953 switch (icmph->type) { 954 case ICMP_REDIRECT: 955 if (icmph->code != ICMP_REDIR_HOST) 956 return; 957 printf(" ICMP Host Redirect to %pI4 ", 958 &icmph->un.gateway); 959 break; 960 default: 961 #if defined(CONFIG_CMD_PING) 962 ping_receive(et, ip, len); 963 #endif 964 #ifdef CONFIG_CMD_TFTPPUT 965 if (packet_icmp_handler) 966 packet_icmp_handler(icmph->type, icmph->code, 967 ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src), 968 icmph->un.data, ntohs(ip->udp_len)); 969 #endif 970 break; 971 } 972 } 973 974 void net_process_received_packet(uchar *in_packet, int len) 975 { 976 struct ethernet_hdr *et; 977 struct ip_udp_hdr *ip; 978 IPaddr_t dst_ip; 979 IPaddr_t src_ip; 980 int eth_proto; 981 #if defined(CONFIG_CMD_CDP) 982 int iscdp; 983 #endif 984 ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid; 985 986 debug_cond(DEBUG_NET_PKT, "packet received\n"); 987 988 NetRxPacket = in_packet; 989 NetRxPacketLen = len; 990 et = (struct ethernet_hdr *)in_packet; 991 992 /* too small packet? */ 993 if (len < ETHER_HDR_SIZE) 994 return; 995 996 #ifdef CONFIG_API 997 if (push_packet) { 998 (*push_packet)(in_packet, len); 999 return; 1000 } 1001 #endif 1002 1003 #if defined(CONFIG_CMD_CDP) 1004 /* keep track if packet is CDP */ 1005 iscdp = is_cdp_packet(et->et_dest); 1006 #endif 1007 1008 myvlanid = ntohs(NetOurVLAN); 1009 if (myvlanid == (ushort)-1) 1010 myvlanid = VLAN_NONE; 1011 mynvlanid = ntohs(NetOurNativeVLAN); 1012 if (mynvlanid == (ushort)-1) 1013 mynvlanid = VLAN_NONE; 1014 1015 eth_proto = ntohs(et->et_protlen); 1016 1017 if (eth_proto < 1514) { 1018 struct e802_hdr *et802 = (struct e802_hdr *)et; 1019 /* 1020 * Got a 802.2 packet. Check the other protocol field. 1021 * XXX VLAN over 802.2+SNAP not implemented! 1022 */ 1023 eth_proto = ntohs(et802->et_prot); 1024 1025 ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE); 1026 len -= E802_HDR_SIZE; 1027 1028 } else if (eth_proto != PROT_VLAN) { /* normal packet */ 1029 ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE); 1030 len -= ETHER_HDR_SIZE; 1031 1032 } else { /* VLAN packet */ 1033 struct vlan_ethernet_hdr *vet = 1034 (struct vlan_ethernet_hdr *)et; 1035 1036 debug_cond(DEBUG_NET_PKT, "VLAN packet received\n"); 1037 1038 /* too small packet? */ 1039 if (len < VLAN_ETHER_HDR_SIZE) 1040 return; 1041 1042 /* if no VLAN active */ 1043 if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE 1044 #if defined(CONFIG_CMD_CDP) 1045 && iscdp == 0 1046 #endif 1047 ) 1048 return; 1049 1050 cti = ntohs(vet->vet_tag); 1051 vlanid = cti & VLAN_IDMASK; 1052 eth_proto = ntohs(vet->vet_type); 1053 1054 ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE); 1055 len -= VLAN_ETHER_HDR_SIZE; 1056 } 1057 1058 debug_cond(DEBUG_NET_PKT, "Receive from protocol 0x%x\n", eth_proto); 1059 1060 #if defined(CONFIG_CMD_CDP) 1061 if (iscdp) { 1062 cdp_receive((uchar *)ip, len); 1063 return; 1064 } 1065 #endif 1066 1067 if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) { 1068 if (vlanid == VLAN_NONE) 1069 vlanid = (mynvlanid & VLAN_IDMASK); 1070 /* not matched? */ 1071 if (vlanid != (myvlanid & VLAN_IDMASK)) 1072 return; 1073 } 1074 1075 switch (eth_proto) { 1076 1077 case PROT_ARP: 1078 ArpReceive(et, ip, len); 1079 break; 1080 1081 #ifdef CONFIG_CMD_RARP 1082 case PROT_RARP: 1083 rarp_receive(ip, len); 1084 break; 1085 #endif 1086 case PROT_IP: 1087 debug_cond(DEBUG_NET_PKT, "Got IP\n"); 1088 /* Before we start poking the header, make sure it is there */ 1089 if (len < IP_UDP_HDR_SIZE) { 1090 debug("len bad %d < %lu\n", len, 1091 (ulong)IP_UDP_HDR_SIZE); 1092 return; 1093 } 1094 /* Check the packet length */ 1095 if (len < ntohs(ip->ip_len)) { 1096 debug("len bad %d < %d\n", len, ntohs(ip->ip_len)); 1097 return; 1098 } 1099 len = ntohs(ip->ip_len); 1100 debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n", 1101 len, ip->ip_hl_v & 0xff); 1102 1103 /* Can't deal with anything except IPv4 */ 1104 if ((ip->ip_hl_v & 0xf0) != 0x40) 1105 return; 1106 /* Can't deal with IP options (headers != 20 bytes) */ 1107 if ((ip->ip_hl_v & 0x0f) > 0x05) 1108 return; 1109 /* Check the Checksum of the header */ 1110 if (!ip_checksum_ok((uchar *)ip, IP_HDR_SIZE)) { 1111 debug("checksum bad\n"); 1112 return; 1113 } 1114 /* If it is not for us, ignore it */ 1115 dst_ip = NetReadIP(&ip->ip_dst); 1116 if (NetOurIP && dst_ip != NetOurIP && dst_ip != 0xFFFFFFFF) { 1117 #ifdef CONFIG_MCAST_TFTP 1118 if (Mcast_addr != dst_ip) 1119 #endif 1120 return; 1121 } 1122 /* Read source IP address for later use */ 1123 src_ip = NetReadIP(&ip->ip_src); 1124 /* 1125 * The function returns the unchanged packet if it's not 1126 * a fragment, and either the complete packet or NULL if 1127 * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL) 1128 */ 1129 ip = NetDefragment(ip, &len); 1130 if (!ip) 1131 return; 1132 /* 1133 * watch for ICMP host redirects 1134 * 1135 * There is no real handler code (yet). We just watch 1136 * for ICMP host redirect messages. In case anybody 1137 * sees these messages: please contact me 1138 * (wd@denx.de), or - even better - send me the 1139 * necessary fixes :-) 1140 * 1141 * Note: in all cases where I have seen this so far 1142 * it was a problem with the router configuration, 1143 * for instance when a router was configured in the 1144 * BOOTP reply, but the TFTP server was on the same 1145 * subnet. So this is probably a warning that your 1146 * configuration might be wrong. But I'm not really 1147 * sure if there aren't any other situations. 1148 * 1149 * Simon Glass <sjg@chromium.org>: We get an ICMP when 1150 * we send a tftp packet to a dead connection, or when 1151 * there is no server at the other end. 1152 */ 1153 if (ip->ip_p == IPPROTO_ICMP) { 1154 receive_icmp(ip, len, src_ip, et); 1155 return; 1156 } else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */ 1157 return; 1158 } 1159 1160 debug_cond(DEBUG_DEV_PKT, 1161 "received UDP (to=%pI4, from=%pI4, len=%d)\n", 1162 &dst_ip, &src_ip, len); 1163 1164 #ifdef CONFIG_UDP_CHECKSUM 1165 if (ip->udp_xsum != 0) { 1166 ulong xsum; 1167 ushort *sumptr; 1168 ushort sumlen; 1169 1170 xsum = ip->ip_p; 1171 xsum += (ntohs(ip->udp_len)); 1172 xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff; 1173 xsum += (ntohl(ip->ip_src) >> 0) & 0x0000ffff; 1174 xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff; 1175 xsum += (ntohl(ip->ip_dst) >> 0) & 0x0000ffff; 1176 1177 sumlen = ntohs(ip->udp_len); 1178 sumptr = (ushort *) &(ip->udp_src); 1179 1180 while (sumlen > 1) { 1181 ushort sumdata; 1182 1183 sumdata = *sumptr++; 1184 xsum += ntohs(sumdata); 1185 sumlen -= 2; 1186 } 1187 if (sumlen > 0) { 1188 ushort sumdata; 1189 1190 sumdata = *(unsigned char *) sumptr; 1191 sumdata = (sumdata << 8) & 0xff00; 1192 xsum += sumdata; 1193 } 1194 while ((xsum >> 16) != 0) { 1195 xsum = (xsum & 0x0000ffff) + 1196 ((xsum >> 16) & 0x0000ffff); 1197 } 1198 if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) { 1199 printf(" UDP wrong checksum %08lx %08x\n", 1200 xsum, ntohs(ip->udp_xsum)); 1201 return; 1202 } 1203 } 1204 #endif 1205 1206 1207 #if defined (CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD) 1208 nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE, 1209 src_ip, 1210 ntohs(ip->udp_dst), 1211 ntohs(ip->udp_src), 1212 ntohs(ip->udp_len) - UDP_HDR_SIZE); 1213 #endif 1214 /* 1215 * IP header OK. Pass the packet to the current handler. 1216 */ 1217 (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE, 1218 ntohs(ip->udp_dst), 1219 src_ip, 1220 ntohs(ip->udp_src), 1221 ntohs(ip->udp_len) - UDP_HDR_SIZE); 1222 break; 1223 } 1224 } 1225 1226 1227 /**********************************************************************/ 1228 1229 static int net_check_prereq(enum proto_t protocol) 1230 { 1231 switch (protocol) { 1232 /* Fall through */ 1233 #if defined(CONFIG_CMD_PING) 1234 case PING: 1235 if (NetPingIP == 0) { 1236 puts("*** ERROR: ping address not given\n"); 1237 return 1; 1238 } 1239 goto common; 1240 #endif 1241 #if defined(CONFIG_CMD_SNTP) 1242 case SNTP: 1243 if (NetNtpServerIP == 0) { 1244 puts("*** ERROR: NTP server address not given\n"); 1245 return 1; 1246 } 1247 goto common; 1248 #endif 1249 #if defined(CONFIG_CMD_DNS) 1250 case DNS: 1251 if (NetOurDNSIP == 0) { 1252 puts("*** ERROR: DNS server address not given\n"); 1253 return 1; 1254 } 1255 goto common; 1256 #endif 1257 #if defined(CONFIG_CMD_NFS) 1258 case NFS: 1259 #endif 1260 case TFTPGET: 1261 case TFTPPUT: 1262 if (NetServerIP == 0) { 1263 puts("*** ERROR: `serverip' not set\n"); 1264 return 1; 1265 } 1266 #if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \ 1267 defined(CONFIG_CMD_DNS) 1268 common: 1269 #endif 1270 /* Fall through */ 1271 1272 case NETCONS: 1273 case TFTPSRV: 1274 if (NetOurIP == 0) { 1275 puts("*** ERROR: `ipaddr' not set\n"); 1276 return 1; 1277 } 1278 /* Fall through */ 1279 1280 #ifdef CONFIG_CMD_RARP 1281 case RARP: 1282 #endif 1283 case BOOTP: 1284 case CDP: 1285 case DHCP: 1286 case LINKLOCAL: 1287 if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) { 1288 int num = eth_get_dev_index(); 1289 1290 switch (num) { 1291 case -1: 1292 puts("*** ERROR: No ethernet found.\n"); 1293 return 1; 1294 case 0: 1295 puts("*** ERROR: `ethaddr' not set\n"); 1296 break; 1297 default: 1298 printf("*** ERROR: `eth%daddr' not set\n", 1299 num); 1300 break; 1301 } 1302 1303 NetStartAgain(); 1304 return 2; 1305 } 1306 /* Fall through */ 1307 default: 1308 return 0; 1309 } 1310 return 0; /* OK */ 1311 } 1312 /**********************************************************************/ 1313 1314 int 1315 NetEthHdrSize(void) 1316 { 1317 ushort myvlanid; 1318 1319 myvlanid = ntohs(NetOurVLAN); 1320 if (myvlanid == (ushort)-1) 1321 myvlanid = VLAN_NONE; 1322 1323 return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : 1324 VLAN_ETHER_HDR_SIZE; 1325 } 1326 1327 int 1328 NetSetEther(uchar *xet, uchar * addr, uint prot) 1329 { 1330 struct ethernet_hdr *et = (struct ethernet_hdr *)xet; 1331 ushort myvlanid; 1332 1333 myvlanid = ntohs(NetOurVLAN); 1334 if (myvlanid == (ushort)-1) 1335 myvlanid = VLAN_NONE; 1336 1337 memcpy(et->et_dest, addr, 6); 1338 memcpy(et->et_src, NetOurEther, 6); 1339 if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) { 1340 et->et_protlen = htons(prot); 1341 return ETHER_HDR_SIZE; 1342 } else { 1343 struct vlan_ethernet_hdr *vet = 1344 (struct vlan_ethernet_hdr *)xet; 1345 1346 vet->vet_vlan_type = htons(PROT_VLAN); 1347 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK)); 1348 vet->vet_type = htons(prot); 1349 return VLAN_ETHER_HDR_SIZE; 1350 } 1351 } 1352 1353 int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot) 1354 { 1355 ushort protlen; 1356 1357 memcpy(et->et_dest, addr, 6); 1358 memcpy(et->et_src, NetOurEther, 6); 1359 protlen = ntohs(et->et_protlen); 1360 if (protlen == PROT_VLAN) { 1361 struct vlan_ethernet_hdr *vet = 1362 (struct vlan_ethernet_hdr *)et; 1363 vet->vet_type = htons(prot); 1364 return VLAN_ETHER_HDR_SIZE; 1365 } else if (protlen > 1514) { 1366 et->et_protlen = htons(prot); 1367 return ETHER_HDR_SIZE; 1368 } else { 1369 /* 802.2 + SNAP */ 1370 struct e802_hdr *et802 = (struct e802_hdr *)et; 1371 et802->et_prot = htons(prot); 1372 return E802_HDR_SIZE; 1373 } 1374 } 1375 1376 void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source) 1377 { 1378 struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt; 1379 1380 /* 1381 * Construct an IP header. 1382 */ 1383 /* IP_HDR_SIZE / 4 (not including UDP) */ 1384 ip->ip_hl_v = 0x45; 1385 ip->ip_tos = 0; 1386 ip->ip_len = htons(IP_HDR_SIZE); 1387 ip->ip_id = htons(NetIPID++); 1388 ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */ 1389 ip->ip_ttl = 255; 1390 ip->ip_sum = 0; 1391 /* already in network byte order */ 1392 NetCopyIP((void *)&ip->ip_src, &source); 1393 /* already in network byte order */ 1394 NetCopyIP((void *)&ip->ip_dst, &dest); 1395 } 1396 1397 void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, 1398 int len) 1399 { 1400 struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt; 1401 1402 /* 1403 * If the data is an odd number of bytes, zero the 1404 * byte after the last byte so that the checksum 1405 * will work. 1406 */ 1407 if (len & 1) 1408 pkt[IP_UDP_HDR_SIZE + len] = 0; 1409 1410 net_set_ip_header(pkt, dest, NetOurIP); 1411 ip->ip_len = htons(IP_UDP_HDR_SIZE + len); 1412 ip->ip_p = IPPROTO_UDP; 1413 ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); 1414 1415 ip->udp_src = htons(sport); 1416 ip->udp_dst = htons(dport); 1417 ip->udp_len = htons(UDP_HDR_SIZE + len); 1418 ip->udp_xsum = 0; 1419 } 1420 1421 void copy_filename(char *dst, const char *src, int size) 1422 { 1423 if (*src && (*src == '"')) { 1424 ++src; 1425 --size; 1426 } 1427 1428 while ((--size > 0) && *src && (*src != '"')) 1429 *dst++ = *src++; 1430 *dst = '\0'; 1431 } 1432 1433 #if defined(CONFIG_CMD_NFS) || \ 1434 defined(CONFIG_CMD_SNTP) || \ 1435 defined(CONFIG_CMD_DNS) 1436 /* 1437 * make port a little random (1024-17407) 1438 * This keeps the math somewhat trivial to compute, and seems to work with 1439 * all supported protocols/clients/servers 1440 */ 1441 unsigned int random_port(void) 1442 { 1443 return 1024 + (get_timer(0) % 0x4000); 1444 } 1445 #endif 1446 1447 void ip_to_string(IPaddr_t x, char *s) 1448 { 1449 x = ntohl(x); 1450 sprintf(s, "%d.%d.%d.%d", 1451 (int) ((x >> 24) & 0xff), 1452 (int) ((x >> 16) & 0xff), 1453 (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff) 1454 ); 1455 } 1456 1457 void VLAN_to_string(ushort x, char *s) 1458 { 1459 x = ntohs(x); 1460 1461 if (x == (ushort)-1) 1462 x = VLAN_NONE; 1463 1464 if (x == VLAN_NONE) 1465 strcpy(s, "none"); 1466 else 1467 sprintf(s, "%d", x & VLAN_IDMASK); 1468 } 1469 1470 ushort string_to_VLAN(const char *s) 1471 { 1472 ushort id; 1473 1474 if (s == NULL) 1475 return htons(VLAN_NONE); 1476 1477 if (*s < '0' || *s > '9') 1478 id = VLAN_NONE; 1479 else 1480 id = (ushort)simple_strtoul(s, NULL, 10); 1481 1482 return htons(id); 1483 } 1484 1485 ushort getenv_VLAN(char *var) 1486 { 1487 return string_to_VLAN(getenv(var)); 1488 } 1489