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