]> git.sur5r.net Git - u-boot/blobdiff - net/net.c
* Update TRAB auto update code
[u-boot] / net / net.c
index b9cb67b25cefc0435fb8bfdde267196f549e1d6b..a139742292d11f43a17a8accb99d23611f2a8a37 100644 (file)
--- a/net/net.c
+++ b/net/net.c
 #include "bootp.h"
 #include "tftp.h"
 #include "rarp.h"
-#include "arp.h"
 
 #if (CONFIG_COMMANDS & CFG_CMD_NET)
 
+#define ARP_TIMEOUT            5               /* Seconds before trying ARP again */
+#ifndef        CONFIG_NET_RETRY_COUNT
+# define ARP_TIMEOUT_COUNT     5               /* # of timeouts before giving up  */
+#else
+# define ARP_TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
+#endif
+
 #if 0
 #define ET_DEBUG
 #endif
@@ -78,6 +84,9 @@
 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           */
+#if (CONFIG_BOOTP_MASK & 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                 */
@@ -88,7 +97,7 @@ ushort                NetBootFileSize=0;              /* Our bootfile size in blocks  */
 ulong          NetBootFileXferSize;    /* The actual transferred size of the bootfile (in bytes) */
 uchar          NetOurEther[6];         /* Our ethernet address                 */
 uchar          NetServerEther[6] =     /* Boot server enet address             */
-                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+                       { 0, 0, 0, 0, 0, 0 };
 IPaddr_t       NetOurIP;               /* Our IP addr (0 = unknown)            */
 IPaddr_t       NetServerIP;            /* Our IP addr (0 = unknown)            */
 volatile uchar *NetRxPkt;              /* Current receive packet               */
@@ -96,6 +105,8 @@ 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 };
 int            NetState;               /* Network loop state                   */
 #ifdef CONFIG_NET_MULTI
 int            NetRestartWrap = 0;     /* Tried all network devices            */
@@ -105,17 +116,99 @@ static int        NetDevExists = 0;       /* At least one device configured       */
 
 char           BootFile[128];          /* Boot File name                       */
 
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+IPaddr_t       NetPingIP;              /* the ip address to ping               */
+
+static void PingStart(void);
+#endif
+
 volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
 
 volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets                    */
 
 static rxhand_f *packetHandler;                /* Current RX packet handler            */
 static thand_f *timeHandler;           /* Current timeout handler              */
-static ulong   timeValue;              /* Current timeout value                */
+static ulong   timeStart;              /* Time base value                      */
+static ulong   timeDelta;              /* Current timeout value                */
 volatile uchar *NetTxPacket = 0;       /* THE transmit packet                  */
 
 static int net_check_prereq (proto_t protocol);
 
+/**********************************************************************/
+
+IPaddr_t       NetArpWaitPacketIP;
+IPaddr_t       NetArpWaitReplyIP;
+uchar         *NetArpWaitPacketMAC;    /* MAC address of waiting packet's destination  */
+uchar          *NetArpWaitTxPacket;    /* THE transmit packet                  */
+int            NetArpWaitTxPacketSize;
+uchar          NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
+ulong          NetArpWaitTimerStart;
+int            NetArpWaitTry;
+
+void ArpRequest(void)
+{
+       int i;
+       volatile uchar *pkt;
+       ARP_t * arp;
+
+#ifdef ET_DEBUG
+       printf("ARP broadcast %d\n", NetArpWaitTry);
+#endif
+       pkt = NetTxPacket;
+
+       NetSetEther(pkt, NetBcastAddr, PROT_ARP);
+       pkt += ETHER_HDR_SIZE;
+
+       arp = (ARP_t *)pkt;
+
+       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     */
+       }
+
+       if((NetArpWaitPacketIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) {
+           if (NetOurGatewayIP == 0) {
+               puts ("## Warning: gatewayip needed but not set\n");
+           }
+           NetArpWaitReplyIP = NetOurGatewayIP;
+       } else
+           NetArpWaitReplyIP = NetArpWaitPacketIP;
+
+       NetWriteIP((uchar*)&arp->ar_data[16], NetArpWaitReplyIP);
+       (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+}
+
+void ArpTimeoutCheck(void)
+{
+       ulong t;
+
+       if (!NetArpWaitPacketIP)
+               return;
+
+       t = get_timer(0);
+
+       /* check for arp timeout */
+       if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT * CFG_HZ) {
+               NetArpWaitTry++;
+
+               if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
+                       puts ("\nARP Retry count exceeded; starting again\n");
+                       NetArpWaitTry = 0;
+                       NetStartAgain();
+               } else {
+                       NetArpWaitTimerStart = t;
+                       ArpRequest();
+               }
+       }
+}
+
 /**********************************************************************/
 /*
  *     Main network processing loop.
@@ -133,6 +226,14 @@ NetLoop(proto_t protocol)
        NetDevExists = 0;
 #endif
 
+       /* XXX problem with bss workaround */
+       NetArpWaitPacketMAC = NULL;
+       NetArpWaitTxPacket = NULL;
+       NetArpWaitPacketIP = 0;
+       NetArpWaitReplyIP = 0;
+       NetArpWaitTxPacket = NULL;
+       NetTxPacket = NULL;
+
        if (!NetTxPacket) {
                int     i;
 
@@ -144,10 +245,18 @@ NetLoop(proto_t protocol)
                for (i = 0; i < PKTBUFSRX; i++) {
                        NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
                }
+
+       }
+
+       if (!NetArpWaitTxPacket) {
+               NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
+               NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
+               NetArpWaitTxPacketSize = 0;
        }
 
        eth_halt();
-       eth_init(bd);
+       if(eth_init(bd) < 0)
+           return(-1);
 
 restart:
 #ifdef CONFIG_NET_MULTI
@@ -165,17 +274,33 @@ restart:
         */
 
        switch (protocol) {
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+       case PING:
+#endif
        case TFTP:
                NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
-               NetServerIP     = getenv_IPaddr ("serverip");
                NetOurGatewayIP = getenv_IPaddr ("gatewayip");
                NetOurSubnetMask= getenv_IPaddr ("netmask");
+
+               switch (protocol) {
+               case TFTP:
+                       NetServerIP = getenv_IPaddr ("serverip");
+                       break;
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+               case PING:
+                       /* 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
+                * initialize our IP addr to 0 in order to accept ANY
+                * IP addr assigned to us by the BOOTP / RARP server
                 */
                NetOurIP = 0;
                NetServerIP = 0;
@@ -202,8 +327,7 @@ restart:
                switch (protocol) {
                case TFTP:
                        /* always use ARP to get server ethernet address */
-                       ArpTry = 0;
-                       ArpRequest ();
+                       TftpStart();
                        break;
 
 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
@@ -224,6 +348,11 @@ restart:
                        RarpTry = 0;
                        RarpRequest ();
                        break;
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+               case PING:
+                       PingStart();
+                       break;
+#endif
                default:
                        break;
                }
@@ -255,17 +384,18 @@ restart:
                 *      Abort if ctrl-c was pressed.
                 */
                if (ctrlc()) {
-                       eth_halt();
+                       eth_halt();
                        printf("\nAbort\n");
                        return (-1);
                }
 
+               ArpTimeoutCheck();
 
                /*
                 *      Check for a timeout, and run the timeout handler
                 *      if we have one.
                 */
-               if (timeHandler && (get_timer(0) > timeValue)) {
+               if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
                        thand_f *x;
 
                        x = timeHandler;
@@ -365,7 +495,8 @@ NetSetTimeout(int iv, thand_f * f)
                timeHandler = (thand_f *)0;
        } else {
                timeHandler = f;
-               timeValue = get_timer(0) + iv;
+               timeStart = get_timer(0);
+               timeDelta = iv;
        }
 }
 
@@ -376,7 +507,138 @@ NetSendPacket(volatile uchar * pkt, int len)
        (void) eth_send(pkt, len);
 }
 
+int
+NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
+{
+       /* convert to new style broadcast */
+       if (dest == 0)
+               dest = 0xFFFFFFFF;
+
+       /* if broadcast, make the ether address a broadcast and don't do ARP */
+       if (dest == 0xFFFFFFFF)
+               ether = NetBcastAddr;
+
+       /* 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
+
+               NetArpWaitPacketIP = dest;
+               NetArpWaitPacketMAC = ether;
+               NetSetEther (NetArpWaitTxPacket, NetArpWaitPacketMAC, PROT_IP);
+               NetSetIP (NetArpWaitTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
+               memcpy(NetArpWaitTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE,
+                       (uchar *)NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE, len);
+
+               /* size of the waiting packet */
+               NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE + len;
+
+               /* and do the ARP request */
+               NetArpWaitTry = 1;
+               NetArpWaitTimerStart = get_timer(0);
+               ArpRequest();
+               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
+
+       NetSetEther (NetTxPacket, ether, PROT_IP);
+       NetSetIP (NetTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
+       (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len);
+
+       return 0;       /* transmited */
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+static ushort PingSeqNo;
+
+int PingSend(void)
+{
+       static uchar mac[6];
+       volatile IP_t *ip;
+       volatile ushort *s;
+
+       /* XXX always send arp request */
+
+       memcpy(mac, NetEtherNullAddr, 6);
+
+#ifdef ET_DEBUG
+       printf("sending ARP for %08lx\n", NetPingIP);
+#endif
+
+       NetArpWaitPacketIP = NetPingIP;
+       NetArpWaitPacketMAC = mac;
+
+       NetSetEther(NetArpWaitTxPacket, mac, PROT_IP);
+
+       ip = (volatile IP_t *)(NetArpWaitTxPacket + ETHER_HDR_SIZE);
+
+       /*
+        *      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->ip_tos   = 0;
+       ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
+       ip->ip_id    = htons(NetIPID++);
+       ip->ip_off   = htons(0x4000);   /* No fragmentation */
+       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);         /* - "" - */
+       ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
+
+       s = &ip->udp_src;               /* XXX ICMP starts here */
+       s[0] = htons(0x0800);           /* echo-request, code */
+       s[1] = 0;                       /* checksum */
+       s[2] = 0;                       /* identifier */
+       s[3] = htons(PingSeqNo++);      /* sequence number */
+       s[1] = ~NetCksum((uchar *)s, 8/2);
+
+       /* size of the waiting packet */
+       NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + 8;
+
+       /* and do the ARP request */
+       NetArpWaitTry = 1;
+       NetArpWaitTimerStart = get_timer(0);
+       ArpRequest();
+       return 1;       /* waiting */
+}
+
+static 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)
+{
+       IPaddr_t tmp;
+       volatile IP_t *ip = (volatile IP_t *)pkt;
+
+       tmp = NetReadIP((void *)&ip->ip_src);
+       if (tmp != NetPingIP)
+               return;
+
+       NetState = NETLOOP_SUCCESS;
+}
+
+static void PingStart(void)
+{
+       NetSetTimeout (10 * CFG_HZ, PingTimeout);
+       NetSetHandler (PingHandler);
 
+       PingSend();
+}
+
+#endif
 
 void
 NetReceive(volatile uchar * pkt, int len)
@@ -387,7 +649,6 @@ NetReceive(volatile uchar * pkt, int len)
        IPaddr_t tmp;
        int     x;
 
-
        NetRxPkt = pkt;
        NetRxPktLen = len;
        et = (Ethernet_t *)pkt;
@@ -415,12 +676,12 @@ NetReceive(volatile uchar * pkt, int len)
        case PROT_ARP:
                /*
                 * We have to deal with two types of ARP packets:
-                 * - REQUEST packets will be answered by sending  our
-                 *   IP address - if we know it.
-                 * - REPLY packates are expected only after we asked
-                 *   for the TFTP server's or the gateway's ethernet
-                 *   address; so if we receive such a packet, we set
-                 *   the server ethernet address
+                * - REQUEST packets will be answered by sending  our
+                *   IP address - if we know it.
+                * - REPLY packates are expected only after we asked
+                *   for the TFTP server's or the gateway's ethernet
+                *   address; so if we receive such a packet, we set
+                *   the server ethernet address
                 */
 #ifdef ET_DEBUG
                printf("Got ARP\n");
@@ -462,14 +723,40 @@ NetReceive(volatile uchar * pkt, int len)
                        NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
                        memcpy   (&arp->ar_data[ 0], NetOurEther, 6);
                        NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
-                       NetSendPacket((uchar *)et,((uchar *)arp-pkt)+ARP_HDR_SIZE);
+                       (void) eth_send((uchar *)et, ((uchar *)arp-pkt) + ARP_HDR_SIZE);
                        return;
-               case ARPOP_REPLY:               /* set TFTP server eth addr     */
+
+               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]);
+#endif
+
+                       tmp = NetReadIP(&arp->ar_data[6]);
+
+                       /* matched waiting packet's address */
+                       if (tmp == NetArpWaitReplyIP) {
 #ifdef ET_DEBUG
-                       printf("Got ARP REPLY, set server/gtwy eth addr\n");
+                               printf("Got it\n");
 #endif
-                       memcpy (NetServerEther, &arp->ar_data[0], 6);
-                       (*packetHandler)(0,0,0,0);      /* start TFTP */
+                               /* save address for later use */
+                               memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
+
+                               /* modify header, and transmit it */
+                               memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
+                               (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
+
+                               /* no arp request pending now */
+                               NetArpWaitPacketIP = 0;
+                               NetArpWaitTxPacketSize = 0;
+                               NetArpWaitPacketMAC = NULL;
+
+                       }
                        return;
                default:
 #ifdef ET_DEBUG
@@ -536,30 +823,43 @@ NetReceive(volatile uchar * pkt, int len)
                /*
                 * watch for ICMP host redirects
                 *
-                 * There is no real handler code (yet). We just watch
-                 * for ICMP host redirect messages. In case anybody
-                 * sees these messages: please contact me
-                 * (wd@denx.de), or - even better - send me the
-                 * necessary fixes :-)
+                * There is no real handler code (yet). We just watch
+                * for ICMP host redirect messages. In case anybody
+                * sees these messages: please contact me
+                * (wd@denx.de), or - even better - send me the
+                * necessary fixes :-)
                 *
-                 * Note: in all cases where I have seen this so far
-                 * it was a problem with the router configuration,
-                 * for instance when a router was configured in the
-                 * BOOTP reply, but the TFTP server was on the same
-                 * 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.
+                * Note: in all cases where I have seen this so far
+                * it was a problem with the router configuration,
+                * for instance when a router was configured in the
+                * BOOTP reply, but the TFTP server was on the same
+                * 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.
                 */
                if (ip->ip_p == IPPROTO_ICMP) {
                        ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
 
-                       if (icmph->type != ICMP_REDIRECT)
-                               return;
+                       switch (icmph->type) {
+                       case ICMP_REDIRECT:
                        if (icmph->code != ICMP_REDIR_HOST)
                                return;
                        puts (" ICMP Host Redirect to ");
                        print_IPaddr(icmph->un.gateway);
                        putc(' ');
+                               break;
+#if (CONFIG_COMMANDS & CFG_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);
+                               break;
+#endif
+                       default:
+                               return;
+                       }
                } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
                        return;
                }
@@ -582,15 +882,25 @@ NetReceive(volatile uchar * pkt, int len)
 static int net_check_prereq (proto_t protocol)
 {
        switch (protocol) {
-       case ARP:       /* nothing to do */
-                       break;
-
+                       /* Fall through */
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+       case PING:
+                       if (NetPingIP == 0) {
+                               puts ("*** ERROR: ping address not given\n");
+                               return (1);
+                       }
+                       goto common;
+#endif
        case TFTP:
                        if (NetServerIP == 0) {
                                puts ("*** ERROR: `serverip' not set\n");
                                return (1);
                        }
 
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+               common:
+#endif
+
                        if (NetOurIP == 0) {
                                puts ("*** ERROR: `ipaddr' not set\n");
                                return (1);
@@ -613,7 +923,7 @@ static int net_check_prereq (proto_t protocol)
                                puts ("*** ERROR: `ethaddr' not set\n");
                                break;
                            default:
-                               printf ("*** ERROR: `eth%daddr' not set\n",
+                               printf ("*** ERROR: `eth%daddr' not set\n",
                                        num);
                                break;
                            }
@@ -626,6 +936,8 @@ static int net_check_prereq (proto_t protocol)
 #endif
                        }
                        /* Fall through */
+               default:
+                       return(0);
        }
        return (0);     /* OK */
 }
@@ -716,29 +1028,21 @@ void ip_to_string (IPaddr_t x, char *s)
 {
     x = ntohl(x);
     sprintf (s,"%d.%d.%d.%d",
-       (int)((x >> 24) & 0xff),
+       (int)((x >> 24) & 0xff),
        (int)((x >> 16) & 0xff),
        (int)((x >>  8) & 0xff),
        (int)((x >>  0) & 0xff)
     );
 }
 
-void print_IPaddr (IPaddr_t x)
-{
-    char tmp[16];
-
-    ip_to_string(x, tmp);
-
-    puts(tmp);
-}
-
-IPaddr_t getenv_IPaddr (char *var)
+IPaddr_t string_to_ip(char *s)
 {
        IPaddr_t addr;
-       char *s, *e;
+       char *e;
        int i;
 
-       s = getenv (var);
+       if (s == NULL)
+               return(0);
 
        for (addr=0, i=0; i<4; ++i) {
                ulong val = s ? simple_strtoul(s, &e, 10) : 0;
@@ -751,3 +1055,17 @@ IPaddr_t getenv_IPaddr (char *var)
 
        return (htonl(addr));
 }
+
+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)));
+}