]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - net/net.c
net: Make sure IPaddr_t is 32 bits in size
[karo-tx-uboot.git] / net / net.c
index 459baf4ea69da201933d0f26612381236b93d75d..045405b7a89742c1d1933f73d5a977cb82d3b270 100644 (file)
--- a/net/net.c
+++ b/net/net.c
@@ -80,7 +80,9 @@
 #include <net.h>
 #include "bootp.h"
 #include "tftp.h"
+#ifdef CONFIG_CMD_RARP
 #include "rarp.h"
+#endif
 #include "nfs.h"
 #ifdef CONFIG_STATUS_LED
 #include <status_led.h>
 #if defined(CONFIG_CDP_VERSION)
 #include <timestamp.h>
 #endif
-
-#if defined(CONFIG_CMD_NET)
+#if defined(CONFIG_CMD_DNS)
+#include "dns.h"
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef        CONFIG_ARP_TIMEOUT
-# define ARP_TIMEOUT           5000UL  /* Milliseconds before trying ARP again */
+/* Milliseconds before trying ARP again */
+# define ARP_TIMEOUT           5000UL
 #else
 # define ARP_TIMEOUT           CONFIG_ARP_TIMEOUT
 #endif
@@ -110,22 +114,26 @@ DECLARE_GLOBAL_DATA_PTR;
 # define ARP_TIMEOUT_COUNT     CONFIG_NET_RETRY_COUNT
 #endif
 
-#if 0
-#define ET_DEBUG
-#endif
-
 /** BOOTP EXTENTIONS **/
 
-IPaddr_t       NetOurSubnetMask=0;             /* Our subnet mask (0=unknown)  */
-IPaddr_t       NetOurGatewayIP=0;              /* Our gateways IP address      */
-IPaddr_t       NetOurDNSIP=0;                  /* Our DNS IP address           */
+/* Our subnet mask (0=unknown) */
+IPaddr_t       NetOurSubnetMask;
+/* Our gateways IP address */
+IPaddr_t       NetOurGatewayIP;
+/* Our DNS IP address */
+IPaddr_t       NetOurDNSIP;
 #if defined(CONFIG_BOOTP_DNS2)
-IPaddr_t       NetOurDNS2IP=0;                 /* Our 2nd DNS IP address       */
-#endif
-char           NetOurNISDomain[32]={0,};       /* Our NIS domain               */
-char           NetOurHostName[32]={0,};        /* Our hostname                 */
-char           NetOurRootPath[64]={0,};        /* Our bootpath                 */
-ushort         NetBootFileSize=0;              /* Our bootfile size in blocks  */
+/* Our 2nd DNS IP address */
+IPaddr_t       NetOurDNS2IP;
+#endif
+/* Our NIS domain */
+char           NetOurNISDomain[32] = {0,};
+/* Our hostname */
+char           NetOurHostName[32] = {0,};
+/* Our bootpath */
+char           NetOurRootPath[64] = {0,};
+/* Our bootfile size in blocks */
+ushort         NetBootFileSize;
 
 #ifdef CONFIG_MCAST_TFTP       /* Multicast TFTP */
 IPaddr_t Mcast_addr;
@@ -133,41 +141,53 @@ IPaddr_t Mcast_addr;
 
 /** END OF BOOTP EXTENTIONS **/
 
-ulong          NetBootFileXferSize;    /* The actual transferred size of the bootfile (in bytes) */
-uchar          NetOurEther[6];         /* Our ethernet address                 */
-uchar          NetServerEther[6] =     /* Boot server enet address             */
-                       { 0, 0, 0, 0, 0, 0 };
-IPaddr_t       NetOurIP;               /* Our IP addr (0 = unknown)            */
-IPaddr_t       NetServerIP;            /* Server IP addr (0 = unknown)         */
-volatile uchar *NetRxPkt;              /* Current receive packet               */
-int            NetRxPktLen;            /* Current rx packet length             */
-unsigned       NetIPID;                /* IP packet ID                         */
-uchar          NetBcastAddr[6] =       /* Ethernet bcast address               */
-                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-uchar          NetEtherNullAddr[6] =
-                       { 0, 0, 0, 0, 0, 0 };
+/* The actual transferred size of the bootfile (in bytes) */
+ulong          NetBootFileXferSize;
+/* Our ethernet address */
+uchar          NetOurEther[6];
+/* Boot server enet address */
+uchar          NetServerEther[6];
+/* Our IP addr (0 = unknown) */
+IPaddr_t       NetOurIP;
+/* Server IP addr (0 = unknown) */
+IPaddr_t       NetServerIP;
+/* Current receive packet */
+volatile uchar *NetRxPacket;
+/* Current rx packet length */
+int            NetRxPacketLen;
+/* IP packet ID */
+unsigned       NetIPID;
+/* Ethernet bcast address */
+uchar          NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar          NetEtherNullAddr[6];
 #ifdef CONFIG_API
 void           (*push_packet)(volatile void *, int len) = 0;
 #endif
 #if defined(CONFIG_CMD_CDP)
-uchar          NetCDPAddr[6] =         /* Ethernet bcast address               */
-                       { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
-#endif
-int            NetState;               /* Network loop state                   */
-#ifdef CONFIG_NET_MULTI
-int            NetRestartWrap = 0;     /* Tried all network devices            */
-static int     NetRestarted = 0;       /* Network loop restarted               */
-static int     NetDevExists = 0;       /* At least one device configured       */
-#endif
+/* Ethernet bcast address */
+uchar          NetCDPAddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
+#endif
+/* Network loop state */
+int            NetState;
+/* Tried all network devices */
+int            NetRestartWrap;
+/* Network loop restarted */
+static int     NetRestarted;
+/* At least one device configured */
+static int     NetDevExists;
 
 /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
-ushort         NetOurVLAN = 0xFFFF;            /* default is without VLAN      */
-ushort         NetOurNativeVLAN = 0xFFFF;      /* ditto                        */
+/* default is without VLAN */
+ushort         NetOurVLAN = 0xFFFF;
+/* ditto */
+ushort         NetOurNativeVLAN = 0xFFFF;
 
-char           BootFile[128];          /* Boot File name                       */
+/* Boot File name */
+char           BootFile[128];
 
 #if defined(CONFIG_CMD_PING)
-IPaddr_t       NetPingIP;              /* the ip address to ping               */
+/* the ip address to ping */
+IPaddr_t       NetPingIP;
 
 static void PingStart(void);
 #endif
@@ -177,8 +197,10 @@ static void CDPStart(void);
 #endif
 
 #if defined(CONFIG_CMD_SNTP)
-IPaddr_t       NetNtpServerIP;         /* NTP server IP address                */
-int            NetTimeOffset=0;        /* offset time from UTC                 */
+/* NTP server IP address */
+IPaddr_t       NetNtpServerIP;
+/* offset time from UTC */
+int            NetTimeOffset;
 #endif
 
 #ifdef CONFIG_NETCONSOLE
@@ -188,58 +210,69 @@ int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
 
 volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
 
-volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets                    */
+/* Receive packet */
+volatile uchar *NetRxPackets[PKTBUFSRX];
+
+/* Current RX packet handler */
+static rxhand_f *packetHandler;
+#ifdef CONFIG_CMD_TFTPPUT
+static rxhand_icmp_f *packet_icmp_handler;     /* Current ICMP rx handler */
+#endif
+/* Current timeout handler */
+static thand_f *timeHandler;
+/* Time base value */
+static ulong   timeStart;
+/* Current timeout value */
+static ulong   timeDelta;
+/* THE transmit packet */
+volatile uchar *NetTxPacket;
 
-static rxhand_f *packetHandler;                /* Current RX packet handler            */
-static thand_f *timeHandler;           /* Current timeout handler              */
-static ulong   timeStart;              /* Time base value                      */
-static ulong   timeDelta;              /* Current timeout value                */
-volatile uchar *NetTxPacket = 0;       /* THE transmit packet                  */
+static int net_check_prereq(enum proto_t protocol);
 
-static int net_check_prereq (proto_t protocol);
+static int NetTryCount;
 
 /**********************************************************************/
 
 IPaddr_t       NetArpWaitPacketIP;
 IPaddr_t       NetArpWaitReplyIP;
-uchar         *NetArpWaitPacketMAC;    /* MAC address of waiting packet's destination  */
-uchar         *NetArpWaitTxPacket;     /* THE transmit packet                  */
+/* MAC address of waiting packet's destination */
+uchar         *NetArpWaitPacketMAC;
+/* THE transmit packet */
+uchar         *NetArpWaitTxPacket;
 int            NetArpWaitTxPacketSize;
 uchar          NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
 ulong          NetArpWaitTimerStart;
 int            NetArpWaitTry;
 
-void ArpRequest (void)
+void ArpRequest(void)
 {
-       int i;
        volatile uchar *pkt;
        ARP_t *arp;
 
-#ifdef ET_DEBUG
-       printf ("ARP broadcast %d\n", NetArpWaitTry);
-#endif
+       debug("ARP broadcast %d\n", NetArpWaitTry);
+
        pkt = NetTxPacket;
 
-       pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
+       pkt += NetSetEther(pkt, NetBcastAddr, PROT_ARP);
 
        arp = (ARP_t *) pkt;
 
-       arp->ar_hrd = htons (ARP_ETHER);
-       arp->ar_pro = htons (PROT_IP);
+       arp->ar_hrd = htons(ARP_ETHER);
+       arp->ar_pro = htons(PROT_IP);
        arp->ar_hln = 6;
        arp->ar_pln = 4;
-       arp->ar_op = htons (ARPOP_REQUEST);
-
-       memcpy (&arp->ar_data[0], NetOurEther, 6);              /* source ET addr       */
-       NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP);     /* source IP addr       */
-       for (i = 10; i < 16; ++i) {
-               arp->ar_data[i] = 0;                            /* dest ET addr = 0     */
-       }
-
+       arp->ar_op = htons(ARPOP_REQUEST);
+
+       /* source ET addr */
+       memcpy(&arp->ar_data[0], NetOurEther, 6);
+       /* source IP addr */
+       NetWriteIP((uchar *) &arp->ar_data[6], NetOurIP);
+       /* dest ET addr = 0 */
+       memset(&arp->ar_data[10], '\0', 6);
        if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
            (NetOurIP & NetOurSubnetMask)) {
                if (NetOurGatewayIP == 0) {
-                       puts ("## Warning: gatewayip needed but not set\n");
+                       puts("## Warning: gatewayip needed but not set\n");
                        NetArpWaitReplyIP = NetArpWaitPacketIP;
                } else {
                        NetArpWaitReplyIP = NetOurGatewayIP;
@@ -248,8 +281,8 @@ void ArpRequest (void)
                NetArpWaitReplyIP = NetArpWaitPacketIP;
        }
 
-       NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
-       (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
+       NetWriteIP((uchar *) &arp->ar_data[16], NetArpWaitReplyIP);
+       (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
 }
 
 void ArpTimeoutCheck(void)
@@ -266,7 +299,7 @@ void ArpTimeoutCheck(void)
                NetArpWaitTry++;
 
                if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
-                       puts ("\nARP Retry count exceeded; starting again\n");
+                       puts("\nARP Retry count exceeded; starting again\n");
                        NetArpWaitTry = 0;
                        NetStartAgain();
                } else {
@@ -276,20 +309,72 @@ void ArpTimeoutCheck(void)
        }
 }
 
+/*
+ * Check if autoload is enabled. If so, use either NFS or TFTP to download
+ * the boot file.
+ */
+void net_auto_load(void)
+{
+       const char *s = getenv("autoload");
+
+       if (s != NULL) {
+               if (*s == 'n') {
+                       /*
+                        * Just use BOOTP/RARP to configure system;
+                        * Do not use TFTP to load the bootfile.
+                        */
+                       NetState = NETLOOP_SUCCESS;
+                       return;
+               }
+#if defined(CONFIG_CMD_NFS)
+               if (strcmp(s, "NFS") == 0) {
+                       /*
+                        * Use NFS to load the bootfile.
+                        */
+                       NfsStart();
+                       return;
+               }
+#endif
+       }
+       TftpStart(TFTPGET);
+}
+
+static void NetInitLoop(enum proto_t protocol)
+{
+       static int env_changed_id;
+       bd_t *bd = gd->bd;
+       int env_id = get_env_id();
+
+       /* update only when the environment has changed */
+       if (env_changed_id != env_id) {
+               NetOurIP = getenv_IPaddr("ipaddr");
+               NetCopyIP(&bd->bi_ip_addr, &NetOurIP);
+               NetOurGatewayIP = getenv_IPaddr("gatewayip");
+               NetOurSubnetMask = getenv_IPaddr("netmask");
+               NetServerIP = getenv_IPaddr("serverip");
+               NetOurNativeVLAN = getenv_VLAN("nvlan");
+               NetOurVLAN = getenv_VLAN("vlan");
+#if defined(CONFIG_CMD_DNS)
+               NetOurDNSIP = getenv_IPaddr("dnsip");
+#endif
+               env_changed_id = env_id;
+       }
+
+       return;
+}
+
 /**********************************************************************/
 /*
  *     Main network processing loop.
  */
 
-int
-NetLoop(proto_t protocol)
+int NetLoop(enum proto_t protocol)
 {
        bd_t *bd = gd->bd;
+       int ret = -1;
 
-#ifdef CONFIG_NET_MULTI
        NetRestarted = 0;
        NetDevExists = 0;
-#endif
 
        /* XXX problem with bss workaround */
        NetArpWaitPacketMAC = NULL;
@@ -298,6 +383,7 @@ NetLoop(proto_t protocol)
        NetArpWaitReplyIP = 0;
        NetArpWaitTxPacket = NULL;
        NetTxPacket = NULL;
+       NetTryCount = 1;
 
        if (!NetTxPacket) {
                int     i;
@@ -306,9 +392,8 @@ NetLoop(proto_t protocol)
                 */
                NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
                NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
-               for (i = 0; i < PKTBUFSRX; i++) {
+               for (i = 0; i < PKTBUFSRX; i++)
                        NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
-               }
        }
 
        if (!NetArpWaitTxPacket) {
@@ -318,20 +403,14 @@ NetLoop(proto_t protocol)
        }
 
        eth_halt();
-#ifdef CONFIG_NET_MULTI
        eth_set_current();
-#endif
        if (eth_init(bd) < 0) {
                eth_halt();
-               return(-1);
+               return -1;
        }
 
 restart:
-#ifdef CONFIG_NET_MULTI
-       memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
-#else
-       memcpy (NetOurEther, bd->bi_enetaddr, 6);
-#endif
+       memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
 
        NetState = NETLOOP_CONTINUE;
 
@@ -340,107 +419,55 @@ restart:
         *      here on, this code is a state machine driven by received
         *      packets and timer events.
         */
+       NetInitLoop(protocol);
 
-       switch (protocol) {
-#if defined(CONFIG_CMD_NFS)
-       case NFS:
-#endif
-#if defined(CONFIG_CMD_PING)
-       case PING:
-#endif
-#if defined(CONFIG_CMD_SNTP)
-       case SNTP:
-#endif
-       case NETCONS:
-       case TFTP:
-               NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
-               NetOurGatewayIP = getenv_IPaddr ("gatewayip");
-               NetOurSubnetMask= getenv_IPaddr ("netmask");
-               NetOurVLAN = getenv_VLAN("vlan");
-               NetOurNativeVLAN = getenv_VLAN("nvlan");
-
-               switch (protocol) {
-#if defined(CONFIG_CMD_NFS)
-               case NFS:
-#endif
-               case NETCONS:
-               case TFTP:
-                       NetServerIP = getenv_IPaddr ("serverip");
-                       break;
-#if defined(CONFIG_CMD_PING)
-               case PING:
-                       /* nothing */
-                       break;
-#endif
-#if defined(CONFIG_CMD_SNTP)
-               case SNTP:
-                       /* nothing */
-                       break;
-#endif
-               default:
-                       break;
-               }
-
-               break;
-       case BOOTP:
-       case RARP:
-               /*
-                * initialize our IP addr to 0 in order to accept ANY
-                * IP addr assigned to us by the BOOTP / RARP server
-                */
-               NetOurIP = 0;
-               NetServerIP = getenv_IPaddr ("serverip");
-               NetOurVLAN = getenv_VLAN("vlan");       /* VLANs must be read */
-               NetOurNativeVLAN = getenv_VLAN("nvlan");
-       case CDP:
-               NetOurVLAN = getenv_VLAN("vlan");       /* VLANs must be read */
-               NetOurNativeVLAN = getenv_VLAN("nvlan");
-               break;
-       default:
-               break;
-       }
-
-       switch (net_check_prereq (protocol)) {
+       switch (net_check_prereq(protocol)) {
        case 1:
                /* network not configured */
                eth_halt();
-               return (-1);
+               return -1;
 
-#ifdef CONFIG_NET_MULTI
        case 2:
                /* network device not configured */
                break;
-#endif /* CONFIG_NET_MULTI */
 
        case 0:
-#ifdef CONFIG_NET_MULTI
                NetDevExists = 1;
-#endif
+               NetBootFileXferSize = 0;
                switch (protocol) {
-               case TFTP:
+               case TFTPGET:
+#ifdef CONFIG_CMD_TFTPPUT
+               case TFTPPUT:
+#endif
                        /* always use ARP to get server ethernet address */
-                       TftpStart();
+                       TftpStart(protocol);
                        break;
-
+#ifdef CONFIG_CMD_TFTPSRV
+               case TFTPSRV:
+                       TftpStartServer();
+                       break;
+#endif
 #if defined(CONFIG_CMD_DHCP)
                case DHCP:
-                       /* Start with a clean slate... */
                        BootpTry = 0;
                        NetOurIP = 0;
-                       NetServerIP = getenv_IPaddr ("serverip");
                        DhcpRequest();          /* Basically same as BOOTP */
                        break;
 #endif
 
                case BOOTP:
                        BootpTry = 0;
-                       BootpRequest ();
+                       NetOurIP = 0;
+                       BootpRequest();
                        break;
 
+#if defined(CONFIG_CMD_RARP)
                case RARP:
                        RarpTry = 0;
-                       RarpRequest ();
+                       NetOurIP = 0;
+                       RarpRequest();
                        break;
+#endif
 #if defined(CONFIG_CMD_PING)
                case PING:
                        PingStart();
@@ -465,25 +492,30 @@ restart:
                case SNTP:
                        SntpStart();
                        break;
+#endif
+#if defined(CONFIG_CMD_DNS)
+               case DNS:
+                       DnsStart();
+                       break;
 #endif
                default:
                        break;
                }
 
-               NetBootFileXferSize = 0;
                break;
        }
 
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
+#if    defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
+       defined(CONFIG_STATUS_LED)                      && \
+       defined(STATUS_LED_RED)
        /*
         * Echo the inverted link state to the fault LED.
         */
-       if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
-               status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
-       } else {
-               status_led_set (STATUS_LED_RED, STATUS_LED_ON);
-       }
+       if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
+               status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
+       else
+               status_led_set(STATUS_LED_RED, STATUS_LED_ON);
 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
 #endif /* CONFIG_MII, ... */
 
@@ -510,8 +542,8 @@ restart:
                 */
                if (ctrlc()) {
                        eth_halt();
-                       puts ("\nAbort\n");
-                       return (-1);
+                       puts("\nAbort\n");
+                       goto done;
                }
 
                ArpTimeoutCheck();
@@ -524,18 +556,19 @@ restart:
                        thand_f *x;
 
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-#  if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
-      defined(CONFIG_STATUS_LED) &&       \
-      defined(STATUS_LED_RED)
+#if    defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
+       defined(CONFIG_STATUS_LED)                      && \
+       defined(STATUS_LED_RED)
                        /*
                         * Echo the inverted link state to the fault LED.
                         */
-                       if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
-                               status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
+                       if (miiphy_link(eth_get_dev()->name,
+                                      CONFIG_SYS_FAULT_MII_ADDR)) {
+                               status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
                        } else {
-                               status_led_set (STATUS_LED_RED, STATUS_LED_ON);
+                               status_led_set(STATUS_LED_RED, STATUS_LED_ON);
                        }
-#  endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
+#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
 #endif /* CONFIG_MII, ... */
                        x = timeHandler;
                        timeHandler = (thand_f *)0;
@@ -546,9 +579,7 @@ restart:
                switch (NetState) {
 
                case NETLOOP_RESTART:
-#ifdef CONFIG_NET_MULTI
                        NetRestarted = 1;
-#endif
                        goto restart;
 
                case NETLOOP_SUCCESS:
@@ -564,12 +595,21 @@ restart:
                                setenv("fileaddr", buf);
                        }
                        eth_halt();
-                       return NetBootFileXferSize;
+                       ret = NetBootFileXferSize;
+                       goto done;
 
                case NETLOOP_FAIL:
-                       return (-1);
+                       goto done;
                }
        }
+
+done:
+#ifdef CONFIG_CMD_TFTPPUT
+       /* Clear out the handlers */
+       NetSetHandler(NULL);
+       net_set_icmp_handler(NULL);
+#endif
+       return ret;
 }
 
 /**********************************************************************/
@@ -581,46 +621,55 @@ startAgainTimeout(void)
 }
 
 static void
-startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+startAgainHandler(uchar *pkt, unsigned dest, IPaddr_t sip,
+                 unsigned src, unsigned len)
 {
        /* Totally ignore the packet */
 }
 
-void NetStartAgain (void)
+void NetStartAgain(void)
 {
        char *nretry;
-       int noretry = 0, once = 0;
-
-       if ((nretry = getenv ("netretry")) != NULL) {
-               noretry = (strcmp (nretry, "no") == 0);
-               once = (strcmp (nretry, "once") == 0);
-       }
-       if (noretry) {
-               eth_halt ();
+       int retry_forever = 0;
+       unsigned long retrycnt = 0;
+
+       nretry = getenv("netretry");
+       if (nretry) {
+               if (!strcmp(nretry, "yes"))
+                       retry_forever = 1;
+               else if (!strcmp(nretry, "no"))
+                       retrycnt = 0;
+               else if (!strcmp(nretry, "once"))
+                       retrycnt = 1;
+               else
+                       retrycnt = simple_strtoul(nretry, NULL, 0);
+       } else
+               retry_forever = 1;
+
+       if ((!retry_forever) && (NetTryCount >= retrycnt)) {
+               eth_halt();
                NetState = NETLOOP_FAIL;
                return;
        }
-#ifndef CONFIG_NET_MULTI
-       NetSetTimeout (10000UL, startAgainTimeout);
-       NetSetHandler (startAgainHandler);
-#else  /* !CONFIG_NET_MULTI*/
-       eth_halt ();
+
+       NetTryCount++;
+
+       eth_halt();
 #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
-       eth_try_another (!NetRestarted);
+       eth_try_another(!NetRestarted);
 #endif
-       eth_init (gd->bd);
+       eth_init(gd->bd);
        if (NetRestartWrap) {
                NetRestartWrap = 0;
-               if (NetDevExists && !once) {
-                       NetSetTimeout (10000UL, startAgainTimeout);
-                       NetSetHandler (startAgainHandler);
+               if (NetDevExists) {
+                       NetSetTimeout(10000UL, startAgainTimeout);
+                       NetSetHandler(startAgainHandler);
                } else {
                        NetState = NETLOOP_FAIL;
                }
        } else {
                NetState = NETLOOP_RESTART;
        }
-#endif /* CONFIG_NET_MULTI */
 }
 
 /**********************************************************************/
@@ -629,14 +678,20 @@ void NetStartAgain (void)
  */
 
 void
-NetSetHandler(rxhand_f * f)
+NetSetHandler(rxhand_f *f)
 {
        packetHandler = f;
 }
 
+#ifdef CONFIG_CMD_TFTPPUT
+void net_set_icmp_handler(rxhand_icmp_f *f)
+{
+       packet_icmp_handler = f;
+}
+#endif
 
 void
-NetSetTimeout(ulong iv, thand_f * f)
+NetSetTimeout(ulong iv, thand_f *f)
 {
        if (iv == 0) {
                timeHandler = (thand_f *)0;
@@ -649,7 +704,7 @@ NetSetTimeout(ulong iv, thand_f * f)
 
 
 void
-NetSendPacket(volatile uchar * pkt, int len)
+NetSendPacket(volatile uchar *pkt, int len)
 {
        (void) eth_send(pkt, len);
 }
@@ -667,23 +722,27 @@ NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
        if (dest == 0xFFFFFFFF)
                ether = NetBcastAddr;
 
-       /* if MAC address was not discovered yet, save the packet and do an ARP request */
+       /*
+        * if MAC address was not discovered yet, save the packet and do
+        * an ARP request
+        */
        if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
 
-#ifdef ET_DEBUG
-               printf("sending ARP for %08lx\n", dest);
-#endif
+               debug("sending ARP for %08x\n", dest);
+
                NetArpWaitPacketIP = dest;
                NetArpWaitPacketMAC = ether;
 
                pkt = NetArpWaitTxPacket;
-               pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
+               pkt += NetSetEther(pkt, NetArpWaitPacketMAC, PROT_IP);
 
-               NetSetIP (pkt, dest, dport, sport, len);
-               memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
+               NetSetIP(pkt, dest, dport, sport, len);
+               memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket +
+                      (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
 
                /* size of the waiting packet */
-               NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
+               NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) +
+                       IP_HDR_SIZE + len;
 
                /* and do the ARP request */
                NetArpWaitTry = 1;
@@ -692,14 +751,11 @@ NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
                return 1;       /* waiting */
        }
 
-#ifdef ET_DEBUG
-       printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
-               dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
-#endif
+       debug("sending UDP to %08x/%pM\n", dest, ether);
 
        pkt = (uchar *)NetTxPacket;
-       pkt += NetSetEther (pkt, ether, PROT_IP);
-       NetSetIP (pkt, dest, dport, sport, len);
+       pkt += NetSetEther(pkt, ether, PROT_IP);
+       NetSetIP(pkt, dest, dport, sport, len);
        (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
 
        return 0;       /* transmitted */
@@ -719,9 +775,7 @@ int PingSend(void)
 
        memcpy(mac, NetEtherNullAddr, 6);
 
-#ifdef ET_DEBUG
-       printf("sending ARP for %08lx\n", NetPingIP);
-#endif
+       debug("sending ARP for %08x\n", NetPingIP);
 
        NetArpWaitPacketIP = NetPingIP;
        NetArpWaitPacketMAC = mac;
@@ -732,9 +786,11 @@ int PingSend(void)
        ip = (volatile IP_t *)pkt;
 
        /*
-        *      Construct an IP and ICMP header.  (need to set no fragment bit - XXX)
+        * Construct an IP and ICMP header.
+        * (need to set no fragment bit - XXX)
         */
-       ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
+       /* IP_HDR_SIZE / 4 (not including UDP) */
+       ip->ip_hl_v  = 0x45;
        ip->ip_tos   = 0;
        ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
        ip->ip_id    = htons(NetIPID++);
@@ -742,8 +798,10 @@ int PingSend(void)
        ip->ip_ttl   = 255;
        ip->ip_p     = 0x01;            /* ICMP */
        ip->ip_sum   = 0;
-       NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
-       NetCopyIP((void*)&ip->ip_dst, &NetPingIP);         /* - "" - */
+       /* already in network byte order */
+       NetCopyIP((void *)&ip->ip_src, &NetOurIP);
+       /* - "" - */
+       NetCopyIP((void *)&ip->ip_dst, &NetPingIP);
        ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
 
        s = &ip->udp_src;               /* XXX ICMP starts here */
@@ -754,7 +812,8 @@ int PingSend(void)
        s[1] = ~NetCksum((uchar *)s, 8/2);
 
        /* size of the waiting packet */
-       NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
+       NetArpWaitTxPacketSize =
+               (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
 
        /* and do the ARP request */
        NetArpWaitTry = 1;
@@ -764,20 +823,17 @@ int PingSend(void)
 }
 
 static void
-PingTimeout (void)
+PingTimeout(void)
 {
        eth_halt();
        NetState = NETLOOP_FAIL;        /* we did not get the reply */
 }
 
 static void
-PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+PingHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+           unsigned len)
 {
-       IPaddr_t tmp;
-       volatile IP_t *ip = (volatile IP_t *)pkt;
-
-       tmp = NetReadIP((void *)&ip->ip_src);
-       if (tmp != NetPingIP)
+       if (sip != NetPingIP)
                return;
 
        NetState = NETLOOP_SUCCESS;
@@ -785,11 +841,9 @@ PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 
 static void PingStart(void)
 {
-#if defined(CONFIG_NET_MULTI)
-       printf ("Using %s device\n", eth_get_name());
-#endif /* CONFIG_NET_MULTI */
-       NetSetTimeout (10000UL, PingTimeout);
-       NetSetHandler (PingHandler);
+       printf("Using %s device\n", eth_get_name());
+       NetSetTimeout(10000UL, PingTimeout);
+       NetSetHandler(PingHandler);
 
        PingSend();
 }
@@ -819,7 +873,8 @@ static int CDPOK;
 ushort CDPNativeVLAN;
 ushort CDPApplianceVLAN;
 
-static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
+static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20,
+                                      0x00 };
 
 static ushort CDP_compute_csum(const uchar *buff, ushort len)
 {
@@ -850,13 +905,15 @@ static ushort CDP_compute_csum(const uchar *buff, ushort len)
                         * CDP uses the IP checksum algorithm with a twist;
                         * for the last byte it *sign* extends and sums.
                         */
-                       result = (result & 0xffff0000) | ((result + leftover) & 0x0000ffff);
+                       result = (result & 0xffff0000) |
+                                ((result + leftover) & 0x0000ffff);
                }
                while (result >> 16)
                        result = (result & 0xFFFF) + (result >> 16);
 
                if (odd)
-                       result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+                       result = ((result >> 8) & 0xff) |
+                                ((result & 0xff) << 8);
        }
 
        /* add up 16-bit and 17-bit words for 17+c bits */
@@ -884,8 +941,8 @@ int CDPSendTrigger(void)
        Ethernet_t *et;
        int len;
        ushort chksum;
-#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID)   || \
-    defined(CONFIG_CDP_VERSION)   || defined(CONFIG_CDP_PLATFORM)
+#if    defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID)   || \
+       defined(CONFIG_CDP_VERSION)   || defined(CONFIG_CDP_PLATFORM)
        char buf[32];
 #endif
 
@@ -909,17 +966,14 @@ int CDPSendTrigger(void)
        *pkt++ = 180;                           /* TTL */
        s = (volatile ushort *)pkt;
        cp = s;
-       *s++ = htons(0);                        /* checksum (0 for later calculation) */
+       /* checksum (0 for later calculation) */
+       *s++ = htons(0);
 
        /* CDP fields */
 #ifdef CONFIG_CDP_DEVICE_ID
        *s++ = htons(CDP_DEVICE_ID_TLV);
        *s++ = htons(CONFIG_CDP_DEVICE_ID);
-       memset(buf, 0, sizeof(buf));
-       sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%02X%02X%02X%02X%02X%02X",
-               NetOurEther[0] & 0xff, NetOurEther[1] & 0xff,
-               NetOurEther[2] & 0xff, NetOurEther[3] & 0xff,
-               NetOurEther[4] & 0xff, NetOurEther[5] & 0xff);
+       sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
        memcpy((uchar *)s, buf, 16);
        s += 16 / 2;
 #endif
@@ -985,7 +1039,8 @@ int CDPSendTrigger(void)
        et->et_protlen = htons(len);
 
        len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
-       chksum = CDP_compute_csum((uchar *)NetTxPacket + len, (uchar *)s - (NetTxPacket + len));
+       chksum = CDP_compute_csum((uchar *)NetTxPacket + len,
+                                 (uchar *)s - (NetTxPacket + len));
        if (chksum == 0)
                chksum = 0xFFFF;
        *cp = htons(chksum);
@@ -995,12 +1050,12 @@ int CDPSendTrigger(void)
 }
 
 static void
-CDPTimeout (void)
+CDPTimeout(void)
 {
        CDPSeq++;
 
        if (CDPSeq < 3) {
-               NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
+               NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
                CDPSendTrigger();
                return;
        }
@@ -1013,18 +1068,18 @@ CDPTimeout (void)
 }
 
 static void
-CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+CDPDummyHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+               unsigned len)
 {
        /* nothing */
 }
 
 static void
-CDPHandler(const uchar * pkt, unsigned len)
+CDPHandler(const uchar *pkt, unsigned len)
 {
        const uchar *t;
        const ushort *ss;
        ushort type, tlen;
-       uchar applid;
        ushort vlan, nvlan;
 
        /* minimum size? */
@@ -1042,7 +1097,10 @@ CDPHandler(const uchar * pkt, unsigned len)
        if (pkt[0] < 0x02 || pkt[1] == 0)
                return;
 
-       /* if version is greater than 0x02 maybe we'll have a problem; output a warning */
+       /*
+        * if version is greater than 0x02 maybe we'll have a problem;
+        * output a warning
+        */
        if (pkt[0] != 0x02)
                printf("** WARNING: CDP packet received with a protocol version %d > 2\n",
                                pkt[0] & 0xff);
@@ -1062,9 +1120,8 @@ CDPHandler(const uchar * pkt, unsigned len)
                ss = (const ushort *)pkt;
                type = ntohs(ss[0]);
                tlen = ntohs(ss[1]);
-               if (tlen > len) {
+               if (tlen > len)
                        goto pkt_short;
-               }
 
                pkt += tlen;
                len -= tlen;
@@ -1073,49 +1130,49 @@ CDPHandler(const uchar * pkt, unsigned len)
                tlen -= 4;
 
                switch (type) {
-                       case CDP_DEVICE_ID_TLV:
-                               break;
-                       case CDP_ADDRESS_TLV:
-                               break;
-                       case CDP_PORT_ID_TLV:
-                               break;
-                       case CDP_CAPABILITIES_TLV:
-                               break;
-                       case CDP_VERSION_TLV:
-                               break;
-                       case CDP_PLATFORM_TLV:
-                               break;
-                       case CDP_NATIVE_VLAN_TLV:
-                               nvlan = *ss;
-                               break;
-                       case CDP_APPLIANCE_VLAN_TLV:
-                               t = (const uchar *)ss;
-                               while (tlen > 0) {
-                                       if (tlen < 3)
-                                               goto pkt_short;
+               case CDP_DEVICE_ID_TLV:
+                       break;
+               case CDP_ADDRESS_TLV:
+                       break;
+               case CDP_PORT_ID_TLV:
+                       break;
+               case CDP_CAPABILITIES_TLV:
+                       break;
+               case CDP_VERSION_TLV:
+                       break;
+               case CDP_PLATFORM_TLV:
+                       break;
+               case CDP_NATIVE_VLAN_TLV:
+                       nvlan = *ss;
+                       break;
+               case CDP_APPLIANCE_VLAN_TLV:
+                       t = (const uchar *)ss;
+                       while (tlen > 0) {
+                               if (tlen < 3)
+                                       goto pkt_short;
 
-                                       applid = t[0];
-                                       ss = (const ushort *)(t + 1);
+                               ss = (const ushort *)(t + 1);
 
 #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
-                                       if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
-                                               vlan = *ss;
+                               if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
+                                       vlan = *ss;
 #else
-                                       vlan = ntohs(*ss);      /* XXX will this work; dunno */
+                               /* XXX will this work; dunno */
+                               vlan = ntohs(*ss);
 #endif
-                                       t += 3; tlen -= 3;
-                               }
-                               break;
-                       case CDP_TRIGGER_TLV:
-                               break;
-                       case CDP_POWER_CONSUMPTION_TLV:
-                               break;
-                       case CDP_SYSNAME_TLV:
-                               break;
-                       case CDP_SYSOBJECT_TLV:
-                               break;
-                       case CDP_MANAGEMENT_ADDRESS_TLV:
-                               break;
+                               t += 3; tlen -= 3;
+                       }
+                       break;
+               case CDP_TRIGGER_TLV:
+                       break;
+               case CDP_POWER_CONSUMPTION_TLV:
+                       break;
+               case CDP_SYSNAME_TLV:
+                       break;
+               case CDP_SYSOBJECT_TLV:
+                       break;
+               case CDP_MANAGEMENT_ADDRESS_TLV:
+                       break;
                }
        }
 
@@ -1132,30 +1189,262 @@ CDPHandler(const uchar * pkt, unsigned len)
 
 static void CDPStart(void)
 {
-#if defined(CONFIG_NET_MULTI)
-       printf ("Using %s device\n", eth_get_name());
-#endif
+       printf("Using %s device\n", eth_get_name());
        CDPSeq = 0;
        CDPOK = 0;
 
        CDPNativeVLAN = htons(-1);
        CDPApplianceVLAN = htons(-1);
 
-       NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
-       NetSetHandler (CDPDummyHandler);
+       NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
+       NetSetHandler(CDPDummyHandler);
 
        CDPSendTrigger();
 }
 #endif
 
+#ifdef CONFIG_IP_DEFRAG
+/*
+ * This function collects fragments in a single packet, according
+ * to the algorithm in RFC815. It returns NULL or the pointer to
+ * a complete packet, in static storage
+ */
+#ifndef CONFIG_NET_MAXDEFRAG
+#define CONFIG_NET_MAXDEFRAG 16384
+#endif
+/*
+ * MAXDEFRAG, above, is chosen in the config file and  is real data
+ * so we need to add the NFS overhead, which is more than TFTP.
+ * To use sizeof in the internal unnamed structures, we need a real
+ * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately).
+ * The compiler doesn't complain nor allocates the actual structure
+ */
+static struct rpc_t rpc_specimen;
+#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))
+
+#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE_NO_UDP)
+
+/*
+ * this is the packet being assembled, either data or frag control.
+ * Fragments go by 8 bytes, so this union must be 8 bytes long
+ */
+struct hole {
+       /* first_byte is address of this structure */
+       u16 last_byte;  /* last byte in this hole + 1 (begin of next hole) */
+       u16 next_hole;  /* index of next (in 8-b blocks), 0 == none */
+       u16 prev_hole;  /* index of prev, 0 == none */
+       u16 unused;
+};
+
+static IP_t *__NetDefragment(IP_t *ip, int *lenp)
+{
+       static uchar pkt_buff[IP_PKTSIZE] __attribute__((aligned(PKTALIGN)));
+       static u16 first_hole, total_len;
+       struct hole *payload, *thisfrag, *h, *newh;
+       IP_t *localip = (IP_t *)pkt_buff;
+       uchar *indata = (uchar *)ip;
+       int offset8, start, len, done = 0;
+       u16 ip_off = ntohs(ip->ip_off);
+
+       /* payload starts after IP header, this fragment is in there */
+       payload = (struct hole *)(pkt_buff + IP_HDR_SIZE_NO_UDP);
+       offset8 =  (ip_off & IP_OFFS);
+       thisfrag = payload + offset8;
+       start = offset8 * 8;
+       len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
+
+       if (start + len > IP_MAXUDP) /* fragment extends too far */
+               return NULL;
+
+       if (!total_len || localip->ip_id != ip->ip_id) {
+               /* new (or different) packet, reset structs */
+               total_len = 0xffff;
+               payload[0].last_byte = ~0;
+               payload[0].next_hole = 0;
+               payload[0].prev_hole = 0;
+               first_hole = 0;
+               /* any IP header will work, copy the first we received */
+               memcpy(localip, ip, IP_HDR_SIZE_NO_UDP);
+       }
+
+       /*
+        * What follows is the reassembly algorithm. We use the payload
+        * array as a linked list of hole descriptors, as each hole starts
+        * at a multiple of 8 bytes. However, last byte can be whatever value,
+        * so it is represented as byte count, not as 8-byte blocks.
+        */
+
+       h = payload + first_hole;
+       while (h->last_byte < start) {
+               if (!h->next_hole) {
+                       /* no hole that far away */
+                       return NULL;
+               }
+               h = payload + h->next_hole;
+       }
+
+       /* last fragment may be 1..7 bytes, the "+7" forces acceptance */
+       if (offset8 + ((len + 7) / 8) <= h - payload) {
+               /* no overlap with holes (dup fragment?) */
+               return NULL;
+       }
+
+       if (!(ip_off & IP_FLAGS_MFRAG)) {
+               /* no more fragmentss: truncate this (last) hole */
+               total_len = start + len;
+               h->last_byte = start + len;
+       }
+
+       /*
+        * There is some overlap: fix the hole list. This code doesn't
+        * deal with a fragment that overlaps with two different holes
+        * (thus being a superset of a previously-received fragment).
+        */
+
+       if ((h >= thisfrag) && (h->last_byte <= start + len)) {
+               /* complete overlap with hole: remove hole */
+               if (!h->prev_hole && !h->next_hole) {
+                       /* last remaining hole */
+                       done = 1;
+               } else if (!h->prev_hole) {
+                       /* first hole */
+                       first_hole = h->next_hole;
+                       payload[h->next_hole].prev_hole = 0;
+               } else if (!h->next_hole) {
+                       /* last hole */
+                       payload[h->prev_hole].next_hole = 0;
+               } else {
+                       /* in the middle of the list */
+                       payload[h->next_hole].prev_hole = h->prev_hole;
+                       payload[h->prev_hole].next_hole = h->next_hole;
+               }
+
+       } else if (h->last_byte <= start + len) {
+               /* overlaps with final part of the hole: shorten this hole */
+               h->last_byte = start;
+
+       } else if (h >= thisfrag) {
+               /* overlaps with initial part of the hole: move this hole */
+               newh = thisfrag + (len / 8);
+               *newh = *h;
+               h = newh;
+               if (h->next_hole)
+                       payload[h->next_hole].prev_hole = (h - payload);
+               if (h->prev_hole)
+                       payload[h->prev_hole].next_hole = (h - payload);
+               else
+                       first_hole = (h - payload);
+
+       } else {
+               /* fragment sits in the middle: split the hole */
+               newh = thisfrag + (len / 8);
+               *newh = *h;
+               h->last_byte = start;
+               h->next_hole = (newh - payload);
+               newh->prev_hole = (h - payload);
+               if (newh->next_hole)
+                       payload[newh->next_hole].prev_hole = (newh - payload);
+       }
+
+       /* finally copy this fragment and possibly return whole packet */
+       memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE_NO_UDP, len);
+       if (!done)
+               return NULL;
+
+       localip->ip_len = htons(total_len);
+       *lenp = total_len + IP_HDR_SIZE_NO_UDP;
+       return localip;
+}
+
+static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
+{
+       u16 ip_off = ntohs(ip->ip_off);
+       if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
+               return ip; /* not a fragment */
+       return __NetDefragment(ip, lenp);
+}
+
+#else /* !CONFIG_IP_DEFRAG */
+
+static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
+{
+       u16 ip_off = ntohs(ip->ip_off);
+       if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
+               return ip; /* not a fragment */
+       return NULL;
+}
+#endif
+
+/**
+ * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
+ * drop others.
+ *
+ * @parma ip   IP packet containing the ICMP
+ */
+static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
+{
+       ICMP_t *icmph = (ICMP_t *)&ip->udp_src;
+
+       switch (icmph->type) {
+       case ICMP_REDIRECT:
+               if (icmph->code != ICMP_REDIR_HOST)
+                       return;
+               printf(" ICMP Host Redirect to %pI4 ",
+                       &icmph->un.gateway);
+               break;
+#if defined(CONFIG_CMD_PING)
+       case ICMP_ECHO_REPLY:
+               /*
+                       * IP header OK.  Pass the packet to the
+                       * current handler.
+                       */
+               /*
+                * XXX point to ip packet - should this use
+                * packet_icmp_handler?
+                */
+               (*packetHandler)((uchar *)ip, 0, src_ip, 0, 0);
+               break;
+       case ICMP_ECHO_REQUEST:
+               debug("Got ICMP ECHO REQUEST, return %d bytes\n",
+                       ETHER_HDR_SIZE + len);
+
+               memcpy(&et->et_dest[0], &et->et_src[0], 6);
+               memcpy(&et->et_src[0], NetOurEther, 6);
+
+               ip->ip_sum = 0;
+               ip->ip_off = 0;
+               NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
+               NetCopyIP((void *)&ip->ip_src, &NetOurIP);
+               ip->ip_sum = ~NetCksum((uchar *)ip,
+                                       IP_HDR_SIZE_NO_UDP >> 1);
+
+               icmph->type = ICMP_ECHO_REPLY;
+               icmph->checksum = 0;
+               icmph->checksum = ~NetCksum((uchar *)icmph,
+                       (len - IP_HDR_SIZE_NO_UDP) >> 1);
+               (void) eth_send((uchar *)et,
+                               ETHER_HDR_SIZE + len);
+               break;
+#endif
+       default:
+#ifdef CONFIG_CMD_TFTPPUT
+               if (packet_icmp_handler)
+                       packet_icmp_handler(icmph->type, icmph->code,
+                               ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
+                               icmph->un.data, ntohs(ip->udp_len));
+#endif
+               break;
+       }
+}
 
 void
-NetReceive(volatile uchar * inpkt, int len)
+NetReceive(volatile uchar *inpkt, int len)
 {
        Ethernet_t *et;
        IP_t    *ip;
        ARP_t   *arp;
        IPaddr_t tmp;
+       IPaddr_t src_ip;
        int     x;
        uchar *pkt;
 #if defined(CONFIG_CMD_CDP)
@@ -1163,12 +1452,10 @@ NetReceive(volatile uchar * inpkt, int len)
 #endif
        ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
 
-#ifdef ET_DEBUG
-       printf("packet received\n");
-#endif
+       debug("packet received\n");
 
-       NetRxPkt = inpkt;
-       NetRxPktLen = len;
+       NetRxPacket = inpkt;
+       NetRxPacketLen = len;
        et = (Ethernet_t *)inpkt;
 
        /* too small packet? */
@@ -1196,9 +1483,7 @@ NetReceive(volatile uchar * inpkt, int len)
 
        x = ntohs(et->et_protlen);
 
-#ifdef ET_DEBUG
-       printf("packet received\n");
-#endif
+       debug("packet received\n");
 
        if (x < 1514) {
                /*
@@ -1216,9 +1501,8 @@ NetReceive(volatile uchar * inpkt, int len)
        } else {                        /* VLAN packet */
                VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
 
-#ifdef ET_DEBUG
-               printf("VLAN packet received\n");
-#endif
+               debug("VLAN packet received\n");
+
                /* too small packet? */
                if (len < VLAN_ETHER_HDR_SIZE)
                        return;
@@ -1239,9 +1523,7 @@ NetReceive(volatile uchar * inpkt, int len)
                len -= VLAN_ETHER_HDR_SIZE;
        }
 
-#ifdef ET_DEBUG
-       printf("Receive from protocol 0x%x\n", x);
-#endif
+       debug("Receive from protocol 0x%x\n", x);
 
 #if defined(CONFIG_CMD_CDP)
        if (iscdp) {
@@ -1270,77 +1552,75 @@ NetReceive(volatile uchar * inpkt, int len)
                 *   address; so if we receive such a packet, we set
                 *   the server ethernet address
                 */
-#ifdef ET_DEBUG
-               puts ("Got ARP\n");
-#endif
+               debug("Got ARP\n");
+
                arp = (ARP_t *)ip;
                if (len < ARP_HDR_SIZE) {
                        printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
                        return;
                }
-               if (ntohs(arp->ar_hrd) != ARP_ETHER) {
+               if (ntohs(arp->ar_hrd) != ARP_ETHER)
                        return;
-               }
-               if (ntohs(arp->ar_pro) != PROT_IP) {
+               if (ntohs(arp->ar_pro) != PROT_IP)
                        return;
-               }
-               if (arp->ar_hln != 6) {
+               if (arp->ar_hln != 6)
                        return;
-               }
-               if (arp->ar_pln != 4) {
+               if (arp->ar_pln != 4)
                        return;
-               }
 
-               if (NetOurIP == 0) {
+               if (NetOurIP == 0)
                        return;
-               }
 
-               if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
+               if (NetReadIP(&arp->ar_data[16]) != NetOurIP)
                        return;
-               }
 
                switch (ntohs(arp->ar_op)) {
-               case ARPOP_REQUEST:             /* reply with our IP address    */
-#ifdef ET_DEBUG
-                       puts ("Got ARP REQUEST, return our IP\n");
-#endif
+               case ARPOP_REQUEST:
+                       /* reply with our IP address */
+                       debug("Got ARP REQUEST, return our IP\n");
                        pkt = (uchar *)et;
                        pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
                        arp->ar_op = htons(ARPOP_REPLY);
-                       memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);
+                       memcpy(&arp->ar_data[10], &arp->ar_data[0], 6);
                        NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
-                       memcpy   (&arp->ar_data[ 0], NetOurEther, 6);
-                       NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
-                       (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
+                       memcpy(&arp->ar_data[0], NetOurEther, 6);
+                       NetCopyIP(&arp->ar_data[6], &NetOurIP);
+                       (void) eth_send((uchar *)et,
+                                       (pkt - (uchar *)et) + ARP_HDR_SIZE);
                        return;
 
                case ARPOP_REPLY:               /* arp reply */
                        /* are we waiting for a reply */
                        if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
                                break;
-#ifdef ET_DEBUG
-                       printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
-                               arp->ar_data[0], arp->ar_data[1],
-                               arp->ar_data[2], arp->ar_data[3],
-                               arp->ar_data[4], arp->ar_data[5]);
+
+#ifdef CONFIG_KEEP_SERVERADDR
+                       if (NetServerIP == NetArpWaitPacketIP) {
+                               char buf[20];
+                               sprintf(buf, "%pM", arp->ar_data);
+                               setenv("serveraddr", buf);
+                       }
 #endif
 
+                       debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
+                               arp->ar_data);
+
                        tmp = NetReadIP(&arp->ar_data[6]);
 
                        /* matched waiting packet's address */
                        if (tmp == NetArpWaitReplyIP) {
-#ifdef ET_DEBUG
-                               puts ("Got it\n");
-#endif
+                               debug("Got it\n");
                                /* save address for later use */
-                               memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
+                               memcpy(NetArpWaitPacketMAC,
+                                      &arp->ar_data[0], 6);
 
 #ifdef CONFIG_NETCONSOLE
-                               (*packetHandler)(0,0,0,0);
+                               (*packetHandler)(0, 0, 0, 0, 0);
 #endif
                                /* modify header, and transmit it */
                                memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
-                               (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
+                               (void) eth_send(NetArpWaitTxPacket,
+                                               NetArpWaitTxPacketSize);
 
                                /* no arp request pending now */
                                NetArpWaitPacketIP = 0;
@@ -1350,17 +1630,15 @@ NetReceive(volatile uchar * inpkt, int len)
                        }
                        return;
                default:
-#ifdef ET_DEBUG
-                       printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
-#endif
+                       debug("Unexpected ARP opcode 0x%x\n",
+                             ntohs(arp->ar_op));
                        return;
                }
                break;
 
+#ifdef CONFIG_CMD_RARP
        case PROT_RARP:
-#ifdef ET_DEBUG
-               puts ("Got RARP\n");
-#endif
+               debug("Got RARP\n");
                arp = (ARP_t *)ip;
                if (len < ARP_HDR_SIZE) {
                        printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
@@ -1372,55 +1650,61 @@ NetReceive(volatile uchar * inpkt, int len)
                        (ntohs(arp->ar_pro) != PROT_IP)     ||
                        (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
 
-                       puts ("invalid RARP header\n");
+                       puts("invalid RARP header\n");
                } else {
-                       NetCopyIP(&NetOurIP,    &arp->ar_data[16]);
+                       NetCopyIP(&NetOurIP, &arp->ar_data[16]);
                        if (NetServerIP == 0)
-                               NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
-                       memcpy (NetServerEther, &arp->ar_data[ 0], 6);
+                               NetCopyIP(&NetServerIP, &arp->ar_data[6]);
+                       memcpy(NetServerEther, &arp->ar_data[0], 6);
 
-                       (*packetHandler)(0,0,0,0);
+                       (*packetHandler)(0, 0, 0, 0, 0);
                }
                break;
-
-       case PROT_IP:
-#ifdef ET_DEBUG
-               puts ("Got IP\n");
 #endif
+       case PROT_IP:
+               debug("Got IP\n");
+               /* Before we start poking the header, make sure it is there */
                if (len < IP_HDR_SIZE) {
-                       debug ("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
+                       debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
                        return;
                }
+               /* Check the packet length */
                if (len < ntohs(ip->ip_len)) {
                        printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
                        return;
                }
                len = ntohs(ip->ip_len);
-#ifdef ET_DEBUG
-               printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
-#endif
-               if ((ip->ip_hl_v & 0xf0) != 0x40) {
-                       return;
-               }
-               /* Can't deal with fragments */
-               if (ip->ip_off & htons(IP_OFFS | IP_FLAGS_MFRAG)) {
+               debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
+
+               /* Can't deal with anything except IPv4 */
+               if ((ip->ip_hl_v & 0xf0) != 0x40)
                        return;
-               }
-               /* can't deal with headers > 20 bytes */
-               if ((ip->ip_hl_v & 0x0f) > 0x05) {
+               /* Can't deal with IP options (headers != 20 bytes) */
+               if ((ip->ip_hl_v & 0x0f) > 0x05)
                        return;
-               }
+               /* Check the Checksum of the header */
                if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
-                       puts ("checksum bad\n");
+                       puts("checksum bad\n");
                        return;
                }
+               /* If it is not for us, ignore it */
                tmp = NetReadIP(&ip->ip_dst);
                if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
 #ifdef CONFIG_MCAST_TFTP
                        if (Mcast_addr != tmp)
 #endif
-                       return;
+                               return;
                }
+               /* Read source IP address for later use */
+               src_ip = NetReadIP(&ip->ip_src);
+               /*
+                * The function returns the unchanged packet if it's not
+                * a fragment, and either the complete packet or NULL if
+                * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
+                */
+               ip = NetDefragment(ip, &len);
+               if (!ip)
+                       return;
                /*
                 * watch for ICMP host redirects
                 *
@@ -1437,50 +1721,14 @@ NetReceive(volatile uchar * inpkt, int len)
                 * subnet. So this is probably a warning that your
                 * configuration might be wrong. But I'm not really
                 * sure if there aren't any other situations.
+                *
+                * Simon Glass <sjg@chromium.org>: We get an ICMP when
+                * we send a tftp packet to a dead connection, or when
+                * there is no server at the other end.
                 */
                if (ip->ip_p == IPPROTO_ICMP) {
-                       ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
-
-                       switch (icmph->type) {
-                       case ICMP_REDIRECT:
-                               if (icmph->code != ICMP_REDIR_HOST)
-                                       return;
-                               puts (" ICMP Host Redirect to ");
-                               print_IPaddr(icmph->un.gateway);
-                               putc(' ');
-                               return;
-#if defined(CONFIG_CMD_PING)
-                       case ICMP_ECHO_REPLY:
-                               /*
-                                *      IP header OK.  Pass the packet to the current handler.
-                                */
-                               /* XXX point to ip packet */
-                               (*packetHandler)((uchar *)ip, 0, 0, 0);
-                               return;
-                       case ICMP_ECHO_REQUEST:
-#ifdef ET_DEBUG
-                               printf ("Got ICMP ECHO REQUEST, return %d bytes \n",
-                                       ETHER_HDR_SIZE + len);
-#endif
-                               memcpy (&et->et_dest[0], &et->et_src[0], 6);
-                               memcpy (&et->et_src[ 0], NetOurEther, 6);
-
-                               ip->ip_sum = 0;
-                               ip->ip_off = 0;
-                               NetCopyIP((void*)&ip->ip_dst, &ip->ip_src);
-                               NetCopyIP((void*)&ip->ip_src, &NetOurIP);
-                               ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP >> 1);
-
-                               icmph->type = ICMP_ECHO_REPLY;
-                               icmph->checksum = 0;
-                               icmph->checksum = ~NetCksum((uchar *)icmph,
-                                               (len - IP_HDR_SIZE_NO_UDP) >> 1);
-                               (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);
-                               return;
-#endif
-                       default:
-                               return;
-                       }
+                       receive_icmp(ip, len, src_ip, et);
+                       return;
                } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
                        return;
                }
@@ -1516,7 +1764,8 @@ NetReceive(volatile uchar * inpkt, int len)
                                xsum += sumdata;
                        }
                        while ((xsum >> 16) != 0) {
-                               xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
+                               xsum = (xsum & 0x0000ffff) +
+                                      ((xsum >> 16) & 0x0000ffff);
                        }
                        if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
                                printf(" UDP wrong checksum %08lx %08x\n",
@@ -1528,7 +1777,7 @@ NetReceive(volatile uchar * inpkt, int len)
 
 
 #ifdef CONFIG_NETCONSOLE
-               nc_input_packet((uchar *)ip +IP_HDR_SIZE,
+               nc_input_packet((uchar *)ip + IP_HDR_SIZE,
                                                ntohs(ip->udp_dst),
                                                ntohs(ip->udp_src),
                                                ntohs(ip->udp_len) - 8);
@@ -1536,8 +1785,9 @@ NetReceive(volatile uchar * inpkt, int len)
                /*
                 *      IP header OK.  Pass the packet to the current handler.
                 */
-               (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
+               (*packetHandler)((uchar *)ip + IP_HDR_SIZE,
                                                ntohs(ip->udp_dst),
+                                               src_ip,
                                                ntohs(ip->udp_src),
                                                ntohs(ip->udp_len) - 8);
                break;
@@ -1547,91 +1797,100 @@ NetReceive(volatile uchar * inpkt, int len)
 
 /**********************************************************************/
 
-static int net_check_prereq (proto_t protocol)
+static int net_check_prereq(enum proto_t protocol)
 {
        switch (protocol) {
                /* Fall through */
 #if defined(CONFIG_CMD_PING)
        case PING:
                if (NetPingIP == 0) {
-                       puts ("*** ERROR: ping address not given\n");
-                       return (1);
+                       puts("*** ERROR: ping address not given\n");
+                       return 1;
                }
                goto common;
 #endif
 #if defined(CONFIG_CMD_SNTP)
        case SNTP:
                if (NetNtpServerIP == 0) {
-                       puts ("*** ERROR: NTP server address not given\n");
-                       return (1);
+                       puts("*** ERROR: NTP server address not given\n");
+                       return 1;
+               }
+               goto common;
+#endif
+#if defined(CONFIG_CMD_DNS)
+       case DNS:
+               if (NetOurDNSIP == 0) {
+                       puts("*** ERROR: DNS server address not given\n");
+                       return 1;
                }
                goto common;
 #endif
 #if defined(CONFIG_CMD_NFS)
        case NFS:
 #endif
-       case NETCONS:
-       case TFTP:
+       case TFTPGET:
+       case TFTPPUT:
                if (NetServerIP == 0) {
-                       puts ("*** ERROR: `serverip' not set\n");
-                       return (1);
+                       puts("*** ERROR: `serverip' not set\n");
+                       return 1;
                }
-#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP)
-    common:
+#if    defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
+       defined(CONFIG_CMD_DNS)
+common:
 #endif
+               /* Fall through */
 
+       case NETCONS:
+       case TFTPSRV:
                if (NetOurIP == 0) {
-                       puts ("*** ERROR: `ipaddr' not set\n");
-                       return (1);
+                       puts("*** ERROR: `ipaddr' not set\n");
+                       return 1;
                }
                /* Fall through */
 
-       case DHCP:
+#ifdef CONFIG_CMD_RARP
        case RARP:
+#endif
        case BOOTP:
        case CDP:
-               if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
-#ifdef CONFIG_NET_MULTI
-                       extern int eth_get_dev_index (void);
-                       int num = eth_get_dev_index ();
+       case DHCP:
+               if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
+                       extern int eth_get_dev_index(void);
+                       int num = eth_get_dev_index();
 
                        switch (num) {
                        case -1:
-                               puts ("*** ERROR: No ethernet found.\n");
-                               return (1);
+                               puts("*** ERROR: No ethernet found.\n");
+                               return 1;
                        case 0:
-                               puts ("*** ERROR: `ethaddr' not set\n");
+                               puts("*** ERROR: `ethaddr' not set\n");
                                break;
                        default:
-                               printf ("*** ERROR: `eth%daddr' not set\n",
+                               printf("*** ERROR: `eth%daddr' not set\n",
                                        num);
                                break;
                        }
 
-                       NetStartAgain ();
-                       return (2);
-#else
-                       puts ("*** ERROR: `ethaddr' not set\n");
-                       return (1);
-#endif
+                       NetStartAgain();
+                       return 2;
                }
                /* Fall through */
        default:
-               return (0);
+               return 0;
        }
-       return (0);             /* OK */
+       return 0;               /* OK */
 }
 /**********************************************************************/
 
 int
-NetCksumOk(uchar * ptr, int len)
+NetCksumOk(uchar *ptr, int len)
 {
        return !((NetCksum(ptr, len) + 1) & 0xfffe);
 }
 
 
 unsigned
-NetCksum(uchar * ptr, int len)
+NetCksum(uchar *ptr, int len)
 {
        ulong   xsum;
        ushort *p = (ushort *)ptr;
@@ -1641,7 +1900,7 @@ NetCksum(uchar * ptr, int len)
                xsum += *p++;
        xsum = (xsum & 0xffff) + (xsum >> 16);
        xsum = (xsum & 0xffff) + (xsum >> 16);
-       return (xsum & 0xffff);
+       return xsum & 0xffff;
 }
 
 int
@@ -1653,11 +1912,12 @@ NetEthHdrSize(void)
        if (myvlanid == (ushort)-1)
                myvlanid = VLAN_NONE;
 
-       return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : VLAN_ETHER_HDR_SIZE;
+       return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
+               VLAN_ETHER_HDR_SIZE;
 }
 
 int
-NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
+NetSetEther(volatile uchar *xet, uchar * addr, uint prot)
 {
        Ethernet_t *et = (Ethernet_t *)xet;
        ushort myvlanid;
@@ -1666,10 +1926,10 @@ NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
        if (myvlanid == (ushort)-1)
                myvlanid = VLAN_NONE;
 
-       memcpy (et->et_dest, addr, 6);
-       memcpy (et->et_src, NetOurEther, 6);
+       memcpy(et->et_dest, addr, 6);
+       memcpy(et->et_src, NetOurEther, 6);
        if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
-       et->et_protlen = htons(prot);
+               et->et_protlen = htons(prot);
                return ETHER_HDR_SIZE;
        } else {
                VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
@@ -1682,7 +1942,7 @@ NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
 }
 
 void
-NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
+NetSetIP(volatile uchar *xip, IPaddr_t dest, int dport, int sport, int len)
 {
        IP_t *ip = (IP_t *)xip;
 
@@ -1698,7 +1958,8 @@ NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
         *      Construct an IP and UDP header.
         *      (need to set no fragment bit - XXX)
         */
-       ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
+       /* IP_HDR_SIZE / 4 (not including UDP) */
+       ip->ip_hl_v  = 0x45;
        ip->ip_tos   = 0;
        ip->ip_len   = htons(IP_HDR_SIZE + len);
        ip->ip_id    = htons(NetIPID++);
@@ -1706,8 +1967,10 @@ NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
        ip->ip_ttl   = 255;
        ip->ip_p     = 17;              /* UDP */
        ip->ip_sum   = 0;
-       NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
-       NetCopyIP((void*)&ip->ip_dst, &dest);      /* - "" - */
+       /* already in network byte order */
+       NetCopyIP((void *)&ip->ip_src, &NetOurIP);
+       /* - "" - */
+       NetCopyIP((void *)&ip->ip_dst, &dest);
        ip->udp_src  = htons(sport);
        ip->udp_dst  = htons(dport);
        ip->udp_len  = htons(8 + len);
@@ -1715,50 +1978,40 @@ NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
        ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
 }
 
-void copy_filename (char *dst, char *src, int size)
+void copy_filename(char *dst, const char *src, int size)
 {
        if (*src && (*src == '"')) {
                ++src;
                --size;
        }
 
-       while ((--size > 0) && *src && (*src != '"')) {
+       while ((--size > 0) && *src && (*src != '"'))
                *dst++ = *src++;
-       }
        *dst = '\0';
 }
 
-#endif
-
-void ip_to_string (IPaddr_t x, char *s)
+#if    defined(CONFIG_CMD_NFS)         || \
+       defined(CONFIG_CMD_SNTP)        || \
+       defined(CONFIG_CMD_DNS)
+/*
+ * make port a little random (1024-17407)
+ * This keeps the math somewhat trivial to compute, and seems to work with
+ * all supported protocols/clients/servers
+ */
+unsigned int random_port(void)
 {
-       x = ntohl (x);
-       sprintf (s, "%d.%d.%d.%d",
-                (int) ((x >> 24) & 0xff),
-                (int) ((x >> 16) & 0xff),
-                (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
-       );
+       return 1024 + (get_timer(0) % 0x4000);
 }
+#endif
 
-IPaddr_t string_to_ip(char *s)
+void ip_to_string(IPaddr_t x, char *s)
 {
-       IPaddr_t addr;
-       char *e;
-       int i;
-
-       if (s == NULL)
-               return(0);
-
-       for (addr=0, i=0; i<4; ++i) {
-               ulong val = s ? simple_strtoul(s, &e, 10) : 0;
-               addr <<= 8;
-               addr |= (val & 0xFF);
-               if (s) {
-                       s = (*e) ? e+1 : e;
-               }
-       }
-
-       return (htonl(addr));
+       x = ntohl(x);
+       sprintf(s, "%d.%d.%d.%d",
+               (int) ((x >> 24) & 0xff),
+               (int) ((x >> 16) & 0xff),
+               (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
+       );
 }
 
 void VLAN_to_string(ushort x, char *s)
@@ -1774,7 +2027,7 @@ void VLAN_to_string(ushort x, char *s)
                sprintf(s, "%d", x & VLAN_IDMASK);
 }
 
-ushort string_to_VLAN(char *s)
+ushort string_to_VLAN(const char *s)
 {
        ushort id;
 
@@ -1789,21 +2042,7 @@ ushort string_to_VLAN(char *s)
        return htons(id);
 }
 
-void print_IPaddr (IPaddr_t x)
-{
-       char tmp[16];
-
-       ip_to_string (x, tmp);
-
-       puts (tmp);
-}
-
-IPaddr_t getenv_IPaddr (char *var)
-{
-       return (string_to_ip(getenv(var)));
-}
-
 ushort getenv_VLAN(char *var)
 {
-       return (string_to_VLAN(getenv(var)));
+       return string_to_VLAN(getenv(var));
 }