Import upstream u-boot 1.1.4
[u-boot.git] / net / net.c
1 /*
2  *      Copied from Linux Monitor (LiMon) - Networking.
3  *
4  *      Copyright 1994 - 2000 Neil Russell.
5  *      (See License)
6  *      Copyright 2000 Roland Borde
7  *      Copyright 2000 Paolo Scaffardi
8  *      Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10
11 /*
12  * General Desription:
13  *
14  * The user interface supports commands for BOOTP, RARP, and TFTP.
15  * Also, we support ARP internally. Depending on available data,
16  * these interact as follows:
17  *
18  * BOOTP:
19  *
20  *      Prerequisites:  - own ethernet address
21  *      We want:        - own IP address
22  *                      - TFTP server IP address
23  *                      - name of bootfile
24  *      Next step:      ARP
25  *
26  * RARP:
27  *
28  *      Prerequisites:  - own ethernet address
29  *      We want:        - own IP address
30  *                      - TFTP server IP address
31  *      Next step:      ARP
32  *
33  * ARP:
34  *
35  *      Prerequisites:  - own ethernet address
36  *                      - own IP address
37  *                      - TFTP server IP address
38  *      We want:        - TFTP server ethernet address
39  *      Next step:      TFTP
40  *
41  * DHCP:
42  *
43  *     Prerequisites:   - own ethernet address
44  *     We want:         - IP, Netmask, ServerIP, Gateway IP
45  *                      - bootfilename, lease time
46  *     Next step:       - TFTP
47  *
48  * TFTP:
49  *
50  *      Prerequisites:  - own ethernet address
51  *                      - own IP address
52  *                      - TFTP server IP address
53  *                      - TFTP server ethernet address
54  *                      - name of bootfile (if unknown, we use a default name
55  *                        derived from our own IP address)
56  *      We want:        - load the boot file
57  *      Next step:      none
58  *
59  * NFS:
60  *
61  *      Prerequisites:  - own ethernet address
62  *                      - own IP address
63  *                      - name of bootfile (if unknown, we use a default name
64  *                        derived from our own IP address)
65  *      We want:        - load the boot file
66  *      Next step:      none
67  *
68  * SNTP:
69  *
70  *      Prerequisites:  - own ethernet address
71  *                      - own IP address
72  *      We want:        - network time
73  *      Next step:      none
74  */
75
76
77 #include <common.h>
78 #include <watchdog.h>
79 #include <command.h>
80 #include <net.h>
81 #include "bootp.h"
82 #include "tftp.h"
83 #include "rarp.h"
84 #include "nfs.h"
85 #ifdef CONFIG_STATUS_LED
86 #include <status_led.h>
87 #include <miiphy.h>
88 #endif
89 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
90 #include "sntp.h"
91 #endif
92
93 #if (CONFIG_COMMANDS & CFG_CMD_NET)
94
95 #define ARP_TIMEOUT             5               /* Seconds before trying ARP again */
96 #ifndef CONFIG_NET_RETRY_COUNT
97 # define ARP_TIMEOUT_COUNT      5               /* # of timeouts before giving up  */
98 #else
99 # define ARP_TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
100 #endif
101
102 #if 0
103 #define ET_DEBUG
104 #endif
105
106 /** BOOTP EXTENTIONS **/
107
108 IPaddr_t        NetOurSubnetMask=0;             /* Our subnet mask (0=unknown)  */
109 IPaddr_t        NetOurGatewayIP=0;              /* Our gateways IP address      */
110 IPaddr_t        NetOurDNSIP=0;                  /* Our DNS IP address           */
111 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
112 IPaddr_t        NetOurDNS2IP=0;                 /* Our 2nd DNS IP address       */
113 #endif
114 char            NetOurNISDomain[32]={0,};       /* Our NIS domain               */
115 char            NetOurHostName[32]={0,};        /* Our hostname                 */
116 char            NetOurRootPath[64]={0,};        /* Our bootpath                 */
117 ushort          NetBootFileSize=0;              /* Our bootfile size in blocks  */
118
119 /** END OF BOOTP EXTENTIONS **/
120
121 ulong           NetBootFileXferSize;    /* The actual transferred size of the bootfile (in bytes) */
122 uchar           NetOurEther[6];         /* Our ethernet address                 */
123 uchar           NetServerEther[6] =     /* Boot server enet address             */
124                         { 0, 0, 0, 0, 0, 0 };
125 IPaddr_t        NetOurIP;               /* Our IP addr (0 = unknown)            */
126 IPaddr_t        NetServerIP;            /* Our IP addr (0 = unknown)            */
127 volatile uchar *NetRxPkt;               /* Current receive packet               */
128 int             NetRxPktLen;            /* Current rx packet length             */
129 unsigned        NetIPID;                /* IP packet ID                         */
130 uchar           NetBcastAddr[6] =       /* Ethernet bcast address               */
131                         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
132 uchar           NetEtherNullAddr[6] =
133                         { 0, 0, 0, 0, 0, 0 };
134 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
135 uchar           NetCDPAddr[6] =         /* Ethernet bcast address               */
136                         { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
137 #endif
138 int             NetState;               /* Network loop state                   */
139 #ifdef CONFIG_NET_MULTI
140 int             NetRestartWrap = 0;     /* Tried all network devices            */
141 static int      NetRestarted = 0;       /* Network loop restarted               */
142 static int      NetDevExists = 0;       /* At least one device configured       */
143 #endif
144
145 /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
146 ushort          NetOurVLAN = 0xFFFF;            /* default is without VLAN      */
147 ushort          NetOurNativeVLAN = 0xFFFF;      /* ditto                        */
148
149 char            BootFile[128];          /* Boot File name                       */
150
151 #if (CONFIG_COMMANDS & CFG_CMD_PING)
152 IPaddr_t        NetPingIP;              /* the ip address to ping               */
153
154 static void PingStart(void);
155 #endif
156
157 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
158 static void CDPStart(void);
159 #endif
160
161 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
162 IPaddr_t        NetNtpServerIP;         /* NTP server IP address                */
163 int             NetTimeOffset=0;        /* offset time from UTC                 */
164 #endif
165
166 #ifdef CONFIG_NETCONSOLE
167 void NcStart(void);
168 int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
169 #endif
170
171 volatile uchar  PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
172
173 volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets                     */
174
175 static rxhand_f *packetHandler;         /* Current RX packet handler            */
176 static thand_f *timeHandler;            /* Current timeout handler              */
177 static ulong    timeStart;              /* Time base value                      */
178 static ulong    timeDelta;              /* Current timeout value                */
179 volatile uchar *NetTxPacket = 0;        /* THE transmit packet                  */
180
181 static int net_check_prereq (proto_t protocol);
182
183 /**********************************************************************/
184
185 IPaddr_t        NetArpWaitPacketIP;
186 IPaddr_t        NetArpWaitReplyIP;
187 uchar          *NetArpWaitPacketMAC;    /* MAC address of waiting packet's destination  */
188 uchar          *NetArpWaitTxPacket;     /* THE transmit packet                  */
189 int             NetArpWaitTxPacketSize;
190 uchar           NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
191 ulong           NetArpWaitTimerStart;
192 int             NetArpWaitTry;
193
194 void ArpRequest (void)
195 {
196         int i;
197         volatile uchar *pkt;
198         ARP_t *arp;
199
200 #ifdef ET_DEBUG
201         printf ("ARP broadcast %d\n", NetArpWaitTry);
202 #endif
203         pkt = NetTxPacket;
204
205         pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
206
207         arp = (ARP_t *) pkt;
208
209         arp->ar_hrd = htons (ARP_ETHER);
210         arp->ar_pro = htons (PROT_IP);
211         arp->ar_hln = 6;
212         arp->ar_pln = 4;
213         arp->ar_op = htons (ARPOP_REQUEST);
214
215         memcpy (&arp->ar_data[0], NetOurEther, 6);              /* source ET addr       */
216         NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP);     /* source IP addr       */
217         for (i = 10; i < 16; ++i) {
218                 arp->ar_data[i] = 0;                            /* dest ET addr = 0     */
219         }
220
221         if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
222             (NetOurIP & NetOurSubnetMask)) {
223                 if (NetOurGatewayIP == 0) {
224                         puts ("## Warning: gatewayip needed but not set\n");
225                 }
226                 NetArpWaitReplyIP = NetOurGatewayIP;
227         } else {
228                 NetArpWaitReplyIP = NetArpWaitPacketIP;
229         }
230
231         NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
232         (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
233 }
234
235 void ArpTimeoutCheck(void)
236 {
237         ulong t;
238
239         if (!NetArpWaitPacketIP)
240                 return;
241
242         t = get_timer(0);
243
244         /* check for arp timeout */
245         if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT * CFG_HZ) {
246                 NetArpWaitTry++;
247
248                 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
249                         puts ("\nARP Retry count exceeded; starting again\n");
250                         NetArpWaitTry = 0;
251                         NetStartAgain();
252                 } else {
253                         NetArpWaitTimerStart = t;
254                         ArpRequest();
255                 }
256         }
257 }
258
259 /**********************************************************************/
260 /*
261  *      Main network processing loop.
262  */
263
264 int
265 NetLoop(proto_t protocol)
266 {
267         DECLARE_GLOBAL_DATA_PTR;
268
269         bd_t *bd = gd->bd;
270
271 #ifdef CONFIG_NET_MULTI
272         NetRestarted = 0;
273         NetDevExists = 0;
274 #endif
275
276         /* XXX problem with bss workaround */
277         NetArpWaitPacketMAC = NULL;
278         NetArpWaitTxPacket = NULL;
279         NetArpWaitPacketIP = 0;
280         NetArpWaitReplyIP = 0;
281         NetArpWaitTxPacket = NULL;
282         NetTxPacket = NULL;
283
284         if (!NetTxPacket) {
285                 int     i;
286                 /*
287                  *      Setup packet buffers, aligned correctly.
288                  */
289                 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
290                 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
291                 for (i = 0; i < PKTBUFSRX; i++) {
292                         NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
293                 }
294         }
295
296         if (!NetArpWaitTxPacket) {
297                 NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
298                 NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
299                 NetArpWaitTxPacketSize = 0;
300         }
301
302         eth_halt();
303 #ifdef CONFIG_NET_MULTI
304         eth_set_current();
305 #endif
306         if (eth_init(bd) < 0) {
307                 eth_halt();
308                 return(-1);
309         }
310
311 restart:
312 #ifdef CONFIG_NET_MULTI
313         memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
314 #else
315         memcpy (NetOurEther, bd->bi_enetaddr, 6);
316 #endif
317
318         NetState = NETLOOP_CONTINUE;
319
320         /*
321          *      Start the ball rolling with the given start function.  From
322          *      here on, this code is a state machine driven by received
323          *      packets and timer events.
324          */
325
326         switch (protocol) {
327 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
328         case NFS:
329 #endif
330 #if (CONFIG_COMMANDS & CFG_CMD_PING)
331         case PING:
332 #endif
333 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
334         case SNTP:
335 #endif
336         case NETCONS:
337         case TFTP:
338                 NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
339                 NetOurGatewayIP = getenv_IPaddr ("gatewayip");
340                 NetOurSubnetMask= getenv_IPaddr ("netmask");
341                 NetOurVLAN = getenv_VLAN("vlan");
342                 NetOurNativeVLAN = getenv_VLAN("nvlan");
343
344                 switch (protocol) {
345 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
346                 case NFS:
347 #endif
348                 case NETCONS:
349                 case TFTP:
350                         NetServerIP = getenv_IPaddr ("serverip");
351                         break;
352 #if (CONFIG_COMMANDS & CFG_CMD_PING)
353                 case PING:
354                         /* nothing */
355                         break;
356 #endif
357 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
358                 case SNTP:
359                         /* nothing */
360                         break;
361 #endif
362                 default:
363                         break;
364                 }
365
366                 break;
367         case BOOTP:
368         case RARP:
369                 /*
370                  * initialize our IP addr to 0 in order to accept ANY
371                  * IP addr assigned to us by the BOOTP / RARP server
372                  */
373                 NetOurIP = 0;
374                 NetServerIP = getenv_IPaddr ("serverip");
375                 NetOurVLAN = getenv_VLAN("vlan");       /* VLANs must be read */
376                 NetOurNativeVLAN = getenv_VLAN("nvlan");
377         case CDP:
378                 NetOurVLAN = getenv_VLAN("vlan");       /* VLANs must be read */
379                 NetOurNativeVLAN = getenv_VLAN("nvlan");
380                 break;
381         default:
382                 break;
383         }
384
385         switch (net_check_prereq (protocol)) {
386         case 1:
387                 /* network not configured */
388                 eth_halt();
389                 return (-1);
390
391 #ifdef CONFIG_NET_MULTI
392         case 2:
393                 /* network device not configured */
394                 break;
395 #endif /* CONFIG_NET_MULTI */
396
397         case 0:
398 #ifdef CONFIG_NET_MULTI
399                 NetDevExists = 1;
400 #endif
401                 switch (protocol) {
402                 case TFTP:
403                         /* always use ARP to get server ethernet address */
404                         TftpStart();
405                         break;
406
407 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
408                 case DHCP:
409                         /* Start with a clean slate... */
410                         BootpTry = 0;
411                         NetOurIP = 0;
412                         NetServerIP = getenv_IPaddr ("serverip");
413                         DhcpRequest();          /* Basically same as BOOTP */
414                         break;
415 #endif /* CFG_CMD_DHCP */
416
417                 case BOOTP:
418                         BootpTry = 0;
419                         BootpRequest ();
420                         break;
421
422                 case RARP:
423                         RarpTry = 0;
424                         RarpRequest ();
425                         break;
426 #if (CONFIG_COMMANDS & CFG_CMD_PING)
427                 case PING:
428                         PingStart();
429                         break;
430 #endif
431 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
432                 case NFS:
433                         NfsStart();
434                         break;
435 #endif
436 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
437                 case CDP:
438                         CDPStart();
439                         break;
440 #endif
441 #ifdef CONFIG_NETCONSOLE
442                 case NETCONS:
443                         NcStart();
444                         break;
445 #endif
446 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
447                 case SNTP:
448                         SntpStart();
449                         break;
450 #endif
451                 default:
452                         break;
453                 }
454
455                 NetBootFileXferSize = 0;
456                 break;
457         }
458
459 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
460 #if defined(CFG_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
461         /*
462          * Echo the inverted link state to the fault LED.
463          */
464         if(miiphy_link(eth_get_dev()->name, CFG_FAULT_MII_ADDR)) {
465                 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
466         } else {
467                 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
468         }
469 #endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
470 #endif /* CONFIG_MII, ... */
471
472         /*
473          *      Main packet reception loop.  Loop receiving packets until
474          *      someone sets `NetState' to a state that terminates.
475          */
476         for (;;) {
477                 WATCHDOG_RESET();
478 #ifdef CONFIG_SHOW_ACTIVITY
479                 {
480                         extern void show_activity(int arg);
481                         show_activity(1);
482                 }
483 #endif
484                 /*
485                  *      Check the ethernet for a new packet.  The ethernet
486                  *      receive routine will process it.
487                  */
488                         eth_rx();
489
490                 /*
491                  *      Abort if ctrl-c was pressed.
492                  */
493                 if (ctrlc()) {
494                         eth_halt();
495                         puts ("\nAbort\n");
496                         return (-1);
497                 }
498
499                 ArpTimeoutCheck();
500
501                 /*
502                  *      Check for a timeout, and run the timeout handler
503                  *      if we have one.
504                  */
505                 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
506                         thand_f *x;
507
508 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
509 #  if defined(CFG_FAULT_ECHO_LINK_DOWN) && \
510       defined(CONFIG_STATUS_LED) &&        \
511       defined(STATUS_LED_RED)
512                         /*
513                          * Echo the inverted link state to the fault LED.
514                          */
515                         if(miiphy_link(eth_get_dev()->name, CFG_FAULT_MII_ADDR)) {
516                                 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
517                         } else {
518                                 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
519                         }
520 #  endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
521 #endif /* CONFIG_MII, ... */
522                         x = timeHandler;
523                         timeHandler = (thand_f *)0;
524                         (*x)();
525                 }
526
527
528                 switch (NetState) {
529
530                 case NETLOOP_RESTART:
531 #ifdef CONFIG_NET_MULTI
532                         NetRestarted = 1;
533 #endif
534                         goto restart;
535
536                 case NETLOOP_SUCCESS:
537                         if (NetBootFileXferSize > 0) {
538                                 char buf[10];
539                                 printf("Bytes transferred = %ld (%lx hex)\n",
540                                         NetBootFileXferSize,
541                                         NetBootFileXferSize);
542                                 sprintf(buf, "%lx", NetBootFileXferSize);
543                                 setenv("filesize", buf);
544
545                                 sprintf(buf, "%lX", (unsigned long)load_addr);
546                                 setenv("fileaddr", buf);
547                         }
548                         eth_halt();
549                         return NetBootFileXferSize;
550
551                 case NETLOOP_FAIL:
552                         return (-1);
553                 }
554         }
555 }
556
557 /**********************************************************************/
558
559 static void
560 startAgainTimeout(void)
561 {
562         NetState = NETLOOP_RESTART;
563 }
564
565 static void
566 startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
567 {
568         /* Totally ignore the packet */
569 }
570
571 void NetStartAgain (void)
572 {
573 #ifdef  CONFIG_NET_MULTI
574         DECLARE_GLOBAL_DATA_PTR;
575 #endif
576         char *nretry;
577         int noretry = 0, once = 0;
578
579         if ((nretry = getenv ("netretry")) != NULL) {
580                 noretry = (strcmp (nretry, "no") == 0);
581                 once = (strcmp (nretry, "once") == 0);
582         }
583         if (noretry) {
584                 eth_halt ();
585                 NetState = NETLOOP_FAIL;
586                 return;
587         }
588 #ifndef CONFIG_NET_MULTI
589         NetSetTimeout (10 * CFG_HZ, startAgainTimeout);
590         NetSetHandler (startAgainHandler);
591 #else   /* !CONFIG_NET_MULTI*/
592         eth_halt ();
593         eth_try_another (!NetRestarted);
594         eth_init (gd->bd);
595         if (NetRestartWrap) {
596                 NetRestartWrap = 0;
597                 if (NetDevExists && !once) {
598                         NetSetTimeout (10 * CFG_HZ, startAgainTimeout);
599                         NetSetHandler (startAgainHandler);
600                 } else {
601                         NetState = NETLOOP_FAIL;
602                 }
603         } else {
604                 NetState = NETLOOP_RESTART;
605         }
606 #endif  /* CONFIG_NET_MULTI */
607 }
608
609 /**********************************************************************/
610 /*
611  *      Miscelaneous bits.
612  */
613
614 void
615 NetSetHandler(rxhand_f * f)
616 {
617         packetHandler = f;
618 }
619
620
621 void
622 NetSetTimeout(ulong iv, thand_f * f)
623 {
624         if (iv == 0) {
625                 timeHandler = (thand_f *)0;
626         } else {
627                 timeHandler = f;
628                 timeStart = get_timer(0);
629                 timeDelta = iv;
630         }
631 }
632
633
634 void
635 NetSendPacket(volatile uchar * pkt, int len)
636 {
637         (void) eth_send(pkt, len);
638 }
639
640 int
641 NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
642 {
643         uchar *pkt;
644
645         /* convert to new style broadcast */
646         if (dest == 0)
647                 dest = 0xFFFFFFFF;
648
649         /* if broadcast, make the ether address a broadcast and don't do ARP */
650         if (dest == 0xFFFFFFFF)
651                 ether = NetBcastAddr;
652
653         /* if MAC address was not discovered yet, save the packet and do an ARP request */
654         if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
655
656 #ifdef ET_DEBUG
657                 printf("sending ARP for %08lx\n", dest);
658 #endif
659                 NetArpWaitPacketIP = dest;
660                 NetArpWaitPacketMAC = ether;
661
662                 pkt = NetArpWaitTxPacket;
663                 pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
664
665                 NetSetIP (pkt, dest, dport, sport, len);
666                 memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
667
668                 /* size of the waiting packet */
669                 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
670
671                 /* and do the ARP request */
672                 NetArpWaitTry = 1;
673                 NetArpWaitTimerStart = get_timer(0);
674                 ArpRequest();
675                 return 1;       /* waiting */
676         }
677
678 #ifdef ET_DEBUG
679         printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
680                 dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
681 #endif
682
683         pkt = (uchar *)NetTxPacket;
684         pkt += NetSetEther (pkt, ether, PROT_IP);
685         NetSetIP (pkt, dest, dport, sport, len);
686         (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
687
688         return 0;       /* transmitted */
689 }
690
691 #if (CONFIG_COMMANDS & CFG_CMD_PING)
692 static ushort PingSeqNo;
693
694 int PingSend(void)
695 {
696         static uchar mac[6];
697         volatile IP_t *ip;
698         volatile ushort *s;
699         uchar *pkt;
700
701         /* XXX always send arp request */
702
703         memcpy(mac, NetEtherNullAddr, 6);
704
705 #ifdef ET_DEBUG
706         printf("sending ARP for %08lx\n", NetPingIP);
707 #endif
708
709         NetArpWaitPacketIP = NetPingIP;
710         NetArpWaitPacketMAC = mac;
711
712         pkt = NetArpWaitTxPacket;
713         pkt += NetSetEther(pkt, mac, PROT_IP);
714
715         ip = (volatile IP_t *)pkt;
716
717         /*
718          *      Construct an IP and ICMP header.  (need to set no fragment bit - XXX)
719          */
720         ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
721         ip->ip_tos   = 0;
722         ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
723         ip->ip_id    = htons(NetIPID++);
724         ip->ip_off   = htons(0x4000);   /* No fragmentation */
725         ip->ip_ttl   = 255;
726         ip->ip_p     = 0x01;            /* ICMP */
727         ip->ip_sum   = 0;
728         NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
729         NetCopyIP((void*)&ip->ip_dst, &NetPingIP);         /* - "" - */
730         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
731
732         s = &ip->udp_src;               /* XXX ICMP starts here */
733         s[0] = htons(0x0800);           /* echo-request, code */
734         s[1] = 0;                       /* checksum */
735         s[2] = 0;                       /* identifier */
736         s[3] = htons(PingSeqNo++);      /* sequence number */
737         s[1] = ~NetCksum((uchar *)s, 8/2);
738
739         /* size of the waiting packet */
740         NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
741
742         /* and do the ARP request */
743         NetArpWaitTry = 1;
744         NetArpWaitTimerStart = get_timer(0);
745         ArpRequest();
746         return 1;       /* waiting */
747 }
748
749 static void
750 PingTimeout (void)
751 {
752         eth_halt();
753         NetState = NETLOOP_FAIL;        /* we did not get the reply */
754 }
755
756 static void
757 PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
758 {
759         IPaddr_t tmp;
760         volatile IP_t *ip = (volatile IP_t *)pkt;
761
762         tmp = NetReadIP((void *)&ip->ip_src);
763         if (tmp != NetPingIP)
764                 return;
765
766         NetState = NETLOOP_SUCCESS;
767 }
768
769 static void PingStart(void)
770 {
771 #if defined(CONFIG_NET_MULTI)
772         printf ("Using %s device\n", eth_get_name());
773 #endif  /* CONFIG_NET_MULTI */
774         NetSetTimeout (10 * CFG_HZ, PingTimeout);
775         NetSetHandler (PingHandler);
776
777         PingSend();
778 }
779 #endif  /* CFG_CMD_PING */
780
781 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
782
783 #define CDP_DEVICE_ID_TLV               0x0001
784 #define CDP_ADDRESS_TLV                 0x0002
785 #define CDP_PORT_ID_TLV                 0x0003
786 #define CDP_CAPABILITIES_TLV            0x0004
787 #define CDP_VERSION_TLV                 0x0005
788 #define CDP_PLATFORM_TLV                0x0006
789 #define CDP_NATIVE_VLAN_TLV             0x000a
790 #define CDP_APPLIANCE_VLAN_TLV          0x000e
791 #define CDP_TRIGGER_TLV                 0x000f
792 #define CDP_POWER_CONSUMPTION_TLV       0x0010
793 #define CDP_SYSNAME_TLV                 0x0014
794 #define CDP_SYSOBJECT_TLV               0x0015
795 #define CDP_MANAGEMENT_ADDRESS_TLV      0x0016
796
797 #define CDP_TIMEOUT                     (CFG_HZ/4)      /* one packet every 250ms */
798
799 static int CDPSeq;
800 static int CDPOK;
801
802 ushort CDPNativeVLAN;
803 ushort CDPApplianceVLAN;
804
805 static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
806
807 static ushort CDP_compute_csum(const uchar *buff, ushort len)
808 {
809         ushort csum;
810         int     odd;
811         ulong   result = 0;
812         ushort  leftover;
813         ushort *p;
814
815         if (len > 0) {
816                 odd = 1 & (ulong)buff;
817                 if (odd) {
818                         result = *buff << 8;
819                         len--;
820                         buff++;
821                 }
822                 while (len > 1) {
823                         p = (ushort *)buff;
824                         result += *p++;
825                         buff = (uchar *)p;
826                         if (result & 0x80000000)
827                                 result = (result & 0xFFFF) + (result >> 16);
828                         len -= 2;
829                 }
830                 if (len) {
831                         leftover = (signed short)(*(const signed char *)buff);
832                         /* CISCO SUCKS big time! (and blows too):
833                          * CDP uses the IP checksum algorithm with a twist;
834                          * for the last byte it *sign* extends and sums.
835                          */
836                         result = (result & 0xffff0000) | ((result + leftover) & 0x0000ffff);
837                 }
838                 while (result >> 16)
839                         result = (result & 0xFFFF) + (result >> 16);
840
841                 if (odd)
842                         result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
843         }
844
845         /* add up 16-bit and 17-bit words for 17+c bits */
846         result = (result & 0xffff) + (result >> 16);
847         /* add up 16-bit and 2-bit for 16+c bit */
848         result = (result & 0xffff) + (result >> 16);
849         /* add up carry.. */
850         result = (result & 0xffff) + (result >> 16);
851
852         /* negate */
853         csum = ~(ushort)result;
854
855         /* run time endian detection */
856         if (csum != htons(csum))        /* little endian */
857                 csum = htons(csum);
858
859         return csum;
860 }
861
862 int CDPSendTrigger(void)
863 {
864         volatile uchar *pkt;
865         volatile ushort *s;
866         volatile ushort *cp;
867         Ethernet_t *et;
868         int len;
869         ushort chksum;
870 #if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID)   || \
871     defined(CONFIG_CDP_VERSION)   || defined(CONFIG_CDP_PLATFORM)
872         char buf[32];
873 #endif
874
875         pkt = NetTxPacket;
876         et = (Ethernet_t *)pkt;
877
878         /* NOTE: trigger sent not on any VLAN */
879
880         /* form ethernet header */
881         memcpy(et->et_dest, NetCDPAddr, 6);
882         memcpy(et->et_src, NetOurEther, 6);
883
884         pkt += ETHER_HDR_SIZE;
885
886         /* SNAP header */
887         memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
888         pkt += sizeof(CDP_SNAP_hdr);
889
890         /* CDP header */
891         *pkt++ = 0x02;                          /* CDP version 2 */
892         *pkt++ = 180;                           /* TTL */
893         s = (volatile ushort *)pkt;
894         cp = s;
895         *s++ = htons(0);                        /* checksum (0 for later calculation) */
896
897         /* CDP fields */
898 #ifdef CONFIG_CDP_DEVICE_ID
899         *s++ = htons(CDP_DEVICE_ID_TLV);
900         *s++ = htons(CONFIG_CDP_DEVICE_ID);
901         memset(buf, 0, sizeof(buf));
902         sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%02X%02X%02X%02X%02X%02X",
903                 NetOurEther[0] & 0xff, NetOurEther[1] & 0xff,
904                 NetOurEther[2] & 0xff, NetOurEther[3] & 0xff,
905                 NetOurEther[4] & 0xff, NetOurEther[5] & 0xff);
906         memcpy((uchar *)s, buf, 16);
907         s += 16 / 2;
908 #endif
909
910 #ifdef CONFIG_CDP_PORT_ID
911         *s++ = htons(CDP_PORT_ID_TLV);
912         memset(buf, 0, sizeof(buf));
913         sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
914         len = strlen(buf);
915         if (len & 1)    /* make it even */
916                 len++;
917         *s++ = htons(len + 4);
918         memcpy((uchar *)s, buf, len);
919         s += len / 2;
920 #endif
921
922 #ifdef CONFIG_CDP_CAPABILITIES
923         *s++ = htons(CDP_CAPABILITIES_TLV);
924         *s++ = htons(8);
925         *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
926         s += 2;
927 #endif
928
929 #ifdef CONFIG_CDP_VERSION
930         *s++ = htons(CDP_VERSION_TLV);
931         memset(buf, 0, sizeof(buf));
932         strcpy(buf, CONFIG_CDP_VERSION);
933         len = strlen(buf);
934         if (len & 1)    /* make it even */
935                 len++;
936         *s++ = htons(len + 4);
937         memcpy((uchar *)s, buf, len);
938         s += len / 2;
939 #endif
940
941 #ifdef CONFIG_CDP_PLATFORM
942         *s++ = htons(CDP_PLATFORM_TLV);
943         memset(buf, 0, sizeof(buf));
944         strcpy(buf, CONFIG_CDP_PLATFORM);
945         len = strlen(buf);
946         if (len & 1)    /* make it even */
947                 len++;
948         *s++ = htons(len + 4);
949         memcpy((uchar *)s, buf, len);
950         s += len / 2;
951 #endif
952
953 #ifdef CONFIG_CDP_TRIGGER
954         *s++ = htons(CDP_TRIGGER_TLV);
955         *s++ = htons(8);
956         *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
957         s += 2;
958 #endif
959
960 #ifdef CONFIG_CDP_POWER_CONSUMPTION
961         *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
962         *s++ = htons(6);
963         *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
964 #endif
965
966         /* length of ethernet packet */
967         len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
968         et->et_protlen = htons(len);
969
970         len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
971         chksum = CDP_compute_csum((uchar *)NetTxPacket + len, (uchar *)s - (NetTxPacket + len));
972         if (chksum == 0)
973                 chksum = 0xFFFF;
974         *cp = htons(chksum);
975
976         (void) eth_send(NetTxPacket, (uchar *)s - NetTxPacket);
977         return 0;
978 }
979
980 static void
981 CDPTimeout (void)
982 {
983         CDPSeq++;
984
985         if (CDPSeq < 3) {
986                 NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
987                 CDPSendTrigger();
988                 return;
989         }
990
991         /* if not OK try again */
992         if (!CDPOK)
993                 NetStartAgain();
994         else
995                 NetState = NETLOOP_SUCCESS;
996 }
997
998 static void
999 CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
1000 {
1001         /* nothing */
1002 }
1003
1004 static void
1005 CDPHandler(const uchar * pkt, unsigned len)
1006 {
1007         const uchar *t;
1008         const ushort *ss;
1009         ushort type, tlen;
1010         uchar applid;
1011         ushort vlan, nvlan;
1012
1013         /* minimum size? */
1014         if (len < sizeof(CDP_SNAP_hdr) + 4)
1015                 goto pkt_short;
1016
1017         /* check for valid CDP SNAP header */
1018         if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
1019                 return;
1020
1021         pkt += sizeof(CDP_SNAP_hdr);
1022         len -= sizeof(CDP_SNAP_hdr);
1023
1024         /* Version of CDP protocol must be >= 2 and TTL != 0 */
1025         if (pkt[0] < 0x02 || pkt[1] == 0)
1026                 return;
1027
1028         /* if version is greater than 0x02 maybe we'll have a problem; output a warning */
1029         if (pkt[0] != 0x02)
1030                 printf("** WARNING: CDP packet received with a protocol version %d > 2\n",
1031                                 pkt[0] & 0xff);
1032
1033         if (CDP_compute_csum(pkt, len) != 0)
1034                 return;
1035
1036         pkt += 4;
1037         len -= 4;
1038
1039         vlan = htons(-1);
1040         nvlan = htons(-1);
1041         while (len > 0) {
1042                 if (len < 4)
1043                         goto pkt_short;
1044
1045                 ss = (const ushort *)pkt;
1046                 type = ntohs(ss[0]);
1047                 tlen = ntohs(ss[1]);
1048                 if (tlen > len) {
1049                         goto pkt_short;
1050                 }
1051
1052                 pkt += tlen;
1053                 len -= tlen;
1054
1055                 ss += 2;        /* point ss to the data of the TLV */
1056                 tlen -= 4;
1057
1058                 switch (type) {
1059                         case CDP_DEVICE_ID_TLV:
1060                                 break;
1061                         case CDP_ADDRESS_TLV:
1062                                 break;
1063                         case CDP_PORT_ID_TLV:
1064                                 break;
1065                         case CDP_CAPABILITIES_TLV:
1066                                 break;
1067                         case CDP_VERSION_TLV:
1068                                 break;
1069                         case CDP_PLATFORM_TLV:
1070                                 break;
1071                         case CDP_NATIVE_VLAN_TLV:
1072                                 nvlan = *ss;
1073                                 break;
1074                         case CDP_APPLIANCE_VLAN_TLV:
1075                                 t = (const uchar *)ss;
1076                                 while (tlen > 0) {
1077                                         if (tlen < 3)
1078                                                 goto pkt_short;
1079
1080                                         applid = t[0];
1081                                         ss = (const ushort *)(t + 1);
1082
1083 #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
1084                                         if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
1085                                                 vlan = *ss;
1086 #else
1087                                         vlan = ntohs(*ss);      /* XXX will this work; dunno */
1088 #endif
1089                                         t += 3; tlen -= 3;
1090                                 }
1091                                 break;
1092                         case CDP_TRIGGER_TLV:
1093                                 break;
1094                         case CDP_POWER_CONSUMPTION_TLV:
1095                                 break;
1096                         case CDP_SYSNAME_TLV:
1097                                 break;
1098                         case CDP_SYSOBJECT_TLV:
1099                                 break;
1100                         case CDP_MANAGEMENT_ADDRESS_TLV:
1101                                 break;
1102                 }
1103         }
1104
1105         CDPApplianceVLAN = vlan;
1106         CDPNativeVLAN = nvlan;
1107
1108         CDPOK = 1;
1109         return;
1110
1111  pkt_short:
1112         printf("** CDP packet is too short\n");
1113         return;
1114 }
1115
1116 static void CDPStart(void)
1117 {
1118 #if defined(CONFIG_NET_MULTI)
1119         printf ("Using %s device\n", eth_get_name());
1120 #endif
1121         CDPSeq = 0;
1122         CDPOK = 0;
1123
1124         CDPNativeVLAN = htons(-1);
1125         CDPApplianceVLAN = htons(-1);
1126
1127         NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
1128         NetSetHandler (CDPDummyHandler);
1129
1130         CDPSendTrigger();
1131 }
1132 #endif  /* CFG_CMD_CDP */
1133
1134
1135 void
1136 NetReceive(volatile uchar * inpkt, int len)
1137 {
1138         Ethernet_t *et;
1139         IP_t    *ip;
1140         ARP_t   *arp;
1141         IPaddr_t tmp;
1142         int     x;
1143         uchar *pkt;
1144 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
1145         int iscdp;
1146 #endif
1147         ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
1148
1149 #ifdef ET_DEBUG
1150         printf("packet received\n");
1151 #endif
1152
1153         NetRxPkt = inpkt;
1154         NetRxPktLen = len;
1155         et = (Ethernet_t *)inpkt;
1156
1157         /* too small packet? */
1158         if (len < ETHER_HDR_SIZE)
1159                 return;
1160
1161 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
1162         /* keep track if packet is CDP */
1163         iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
1164 #endif
1165
1166         myvlanid = ntohs(NetOurVLAN);
1167         if (myvlanid == (ushort)-1)
1168                 myvlanid = VLAN_NONE;
1169         mynvlanid = ntohs(NetOurNativeVLAN);
1170         if (mynvlanid == (ushort)-1)
1171                 mynvlanid = VLAN_NONE;
1172
1173         x = ntohs(et->et_protlen);
1174
1175 #ifdef ET_DEBUG
1176         printf("packet received\n");
1177 #endif
1178
1179         if (x < 1514) {
1180                 /*
1181                  *      Got a 802 packet.  Check the other protocol field.
1182                  */
1183                 x = ntohs(et->et_prot);
1184
1185                 ip = (IP_t *)(inpkt + E802_HDR_SIZE);
1186                 len -= E802_HDR_SIZE;
1187
1188         } else if (x != PROT_VLAN) {    /* normal packet */
1189                 ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
1190                 len -= ETHER_HDR_SIZE;
1191
1192         } else {                        /* VLAN packet */
1193                 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
1194
1195 #ifdef ET_DEBUG
1196                 printf("VLAN packet received\n");
1197 #endif
1198                 /* too small packet? */
1199                 if (len < VLAN_ETHER_HDR_SIZE)
1200                         return;
1201
1202                 /* if no VLAN active */
1203                 if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
1204 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
1205                                 && iscdp == 0
1206 #endif
1207                                 )
1208                         return;
1209
1210                 cti = ntohs(vet->vet_tag);
1211                 vlanid = cti & VLAN_IDMASK;
1212                 x = ntohs(vet->vet_type);
1213
1214                 ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
1215                 len -= VLAN_ETHER_HDR_SIZE;
1216         }
1217
1218 #ifdef ET_DEBUG
1219         printf("Receive from protocol 0x%x\n", x);
1220 #endif
1221
1222 #if (CONFIG_COMMANDS & CFG_CMD_CDP)
1223         if (iscdp) {
1224                 CDPHandler((uchar *)ip, len);
1225                 return;
1226         }
1227 #endif
1228
1229         if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1230                 if (vlanid == VLAN_NONE)
1231                         vlanid = (mynvlanid & VLAN_IDMASK);
1232                 /* not matched? */
1233                 if (vlanid != (myvlanid & VLAN_IDMASK))
1234                         return;
1235         }
1236
1237         switch (x) {
1238
1239         case PROT_ARP:
1240                 /*
1241                  * We have to deal with two types of ARP packets:
1242                  * - REQUEST packets will be answered by sending  our
1243                  *   IP address - if we know it.
1244                  * - REPLY packates are expected only after we asked
1245                  *   for the TFTP server's or the gateway's ethernet
1246                  *   address; so if we receive such a packet, we set
1247                  *   the server ethernet address
1248                  */
1249 #ifdef ET_DEBUG
1250                 puts ("Got ARP\n");
1251 #endif
1252                 arp = (ARP_t *)ip;
1253                 if (len < ARP_HDR_SIZE) {
1254                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1255                         return;
1256                 }
1257                 if (ntohs(arp->ar_hrd) != ARP_ETHER) {
1258                         return;
1259                 }
1260                 if (ntohs(arp->ar_pro) != PROT_IP) {
1261                         return;
1262                 }
1263                 if (arp->ar_hln != 6) {
1264                         return;
1265                 }
1266                 if (arp->ar_pln != 4) {
1267                         return;
1268                 }
1269
1270                 if (NetOurIP == 0) {
1271                         return;
1272                 }
1273
1274                 if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
1275                         return;
1276                 }
1277
1278                 switch (ntohs(arp->ar_op)) {
1279                 case ARPOP_REQUEST:             /* reply with our IP address    */
1280 #ifdef ET_DEBUG
1281                         puts ("Got ARP REQUEST, return our IP\n");
1282 #endif
1283                         pkt = (uchar *)et;
1284                         pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
1285                         arp->ar_op = htons(ARPOP_REPLY);
1286                         memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);
1287                         NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
1288                         memcpy   (&arp->ar_data[ 0], NetOurEther, 6);
1289                         NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
1290                         (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
1291                         return;
1292
1293                 case ARPOP_REPLY:               /* arp reply */
1294                         /* are we waiting for a reply */
1295                         if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
1296                                 break;
1297 #ifdef ET_DEBUG
1298                         printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
1299                                 arp->ar_data[0], arp->ar_data[1],
1300                                 arp->ar_data[2], arp->ar_data[3],
1301                                 arp->ar_data[4], arp->ar_data[5]);
1302 #endif
1303
1304                         tmp = NetReadIP(&arp->ar_data[6]);
1305
1306                         /* matched waiting packet's address */
1307                         if (tmp == NetArpWaitReplyIP) {
1308 #ifdef ET_DEBUG
1309                                 puts ("Got it\n");
1310 #endif
1311                                 /* save address for later use */
1312                                 memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
1313
1314 #ifdef CONFIG_NETCONSOLE
1315                                 (*packetHandler)(0,0,0,0);
1316 #endif
1317                                 /* modify header, and transmit it */
1318                                 memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
1319                                 (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
1320
1321                                 /* no arp request pending now */
1322                                 NetArpWaitPacketIP = 0;
1323                                 NetArpWaitTxPacketSize = 0;
1324                                 NetArpWaitPacketMAC = NULL;
1325
1326                         }
1327                         return;
1328                 default:
1329 #ifdef ET_DEBUG
1330                         printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
1331 #endif
1332                         return;
1333                 }
1334                 break;
1335
1336         case PROT_RARP:
1337 #ifdef ET_DEBUG
1338                 puts ("Got RARP\n");
1339 #endif
1340                 arp = (ARP_t *)ip;
1341                 if (len < ARP_HDR_SIZE) {
1342                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1343                         return;
1344                 }
1345
1346                 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
1347                         (ntohs(arp->ar_hrd) != ARP_ETHER)   ||
1348                         (ntohs(arp->ar_pro) != PROT_IP)     ||
1349                         (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
1350
1351                         puts ("invalid RARP header\n");
1352                 } else {
1353                         NetCopyIP(&NetOurIP,    &arp->ar_data[16]);
1354                         if (NetServerIP == 0)
1355                                 NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
1356                         memcpy (NetServerEther, &arp->ar_data[ 0], 6);
1357
1358                         (*packetHandler)(0,0,0,0);
1359                 }
1360                 break;
1361
1362         case PROT_IP:
1363 #ifdef ET_DEBUG
1364                 puts ("Got IP\n");
1365 #endif
1366                 if (len < IP_HDR_SIZE) {
1367                         debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
1368                         return;
1369                 }
1370                 if (len < ntohs(ip->ip_len)) {
1371                         printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
1372                         return;
1373                 }
1374                 len = ntohs(ip->ip_len);
1375 #ifdef ET_DEBUG
1376                 printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
1377 #endif
1378                 if ((ip->ip_hl_v & 0xf0) != 0x40) {
1379                         return;
1380                 }
1381                 if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
1382                         return;
1383                 }
1384                 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
1385                         puts ("checksum bad\n");
1386                         return;
1387                 }
1388                 tmp = NetReadIP(&ip->ip_dst);
1389                 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
1390                         return;
1391                 }
1392                 /*
1393                  * watch for ICMP host redirects
1394                  *
1395                  * There is no real handler code (yet). We just watch
1396                  * for ICMP host redirect messages. In case anybody
1397                  * sees these messages: please contact me
1398                  * (wd@denx.de), or - even better - send me the
1399                  * necessary fixes :-)
1400                  *
1401                  * Note: in all cases where I have seen this so far
1402                  * it was a problem with the router configuration,
1403                  * for instance when a router was configured in the
1404                  * BOOTP reply, but the TFTP server was on the same
1405                  * subnet. So this is probably a warning that your
1406                  * configuration might be wrong. But I'm not really
1407                  * sure if there aren't any other situations.
1408                  */
1409                 if (ip->ip_p == IPPROTO_ICMP) {
1410                         ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
1411
1412                         switch (icmph->type) {
1413                         case ICMP_REDIRECT:
1414                                 if (icmph->code != ICMP_REDIR_HOST)
1415                                         return;
1416                                 puts (" ICMP Host Redirect to ");
1417                                 print_IPaddr(icmph->un.gateway);
1418                                 putc(' ');
1419                                 return;
1420 #if (CONFIG_COMMANDS & CFG_CMD_PING)
1421                         case ICMP_ECHO_REPLY:
1422                                 /*
1423                                  *      IP header OK.  Pass the packet to the current handler.
1424                                  */
1425                                 /* XXX point to ip packet */
1426                                 (*packetHandler)((uchar *)ip, 0, 0, 0);
1427                                 return;
1428 #endif
1429                         default:
1430                                 return;
1431                         }
1432                 } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
1433                         return;
1434                 }
1435
1436 #ifdef CONFIG_UDP_CHECKSUM
1437                 if (ip->udp_xsum != 0) {
1438                         ulong   xsum;
1439                         ushort *sumptr;
1440                         ushort  sumlen;
1441
1442                         xsum  = ip->ip_p;
1443                         xsum += (ntohs(ip->udp_len));
1444                         xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
1445                         xsum += (ntohl(ip->ip_src) >>  0) & 0x0000ffff;
1446                         xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
1447                         xsum += (ntohl(ip->ip_dst) >>  0) & 0x0000ffff;
1448
1449                         sumlen = ntohs(ip->udp_len);
1450                         sumptr = (ushort *) &(ip->udp_src);
1451
1452                         while (sumlen > 1) {
1453                                 ushort sumdata;
1454
1455                                 sumdata = *sumptr++;
1456                                 xsum += ntohs(sumdata);
1457                                 sumlen -= 2;
1458                         }
1459                         if (sumlen > 0) {
1460                                 ushort sumdata;
1461
1462                                 sumdata = *(unsigned char *) sumptr;
1463                                 sumdata = (sumdata << 8) & 0xff00;
1464                                 xsum += sumdata;
1465                         }
1466                         while ((xsum >> 16) != 0) {
1467                                 xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
1468                         }
1469                         if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
1470                                 printf(" UDP wrong checksum %08x %08x\n", xsum, ntohs(ip->udp_xsum));
1471                                 return;
1472                         }
1473                 }
1474 #endif
1475
1476 #ifdef CONFIG_NETCONSOLE
1477                 nc_input_packet((uchar *)ip +IP_HDR_SIZE,
1478                                                 ntohs(ip->udp_dst),
1479                                                 ntohs(ip->udp_src),
1480                                                 ntohs(ip->udp_len) - 8);
1481 #endif
1482                 /*
1483                  *      IP header OK.  Pass the packet to the current handler.
1484                  */
1485                 (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
1486                                                 ntohs(ip->udp_dst),
1487                                                 ntohs(ip->udp_src),
1488                                                 ntohs(ip->udp_len) - 8);
1489                 break;
1490         }
1491 }
1492
1493
1494 /**********************************************************************/
1495
1496 static int net_check_prereq (proto_t protocol)
1497 {
1498         switch (protocol) {
1499                 /* Fall through */
1500 #if (CONFIG_COMMANDS & CFG_CMD_PING)
1501         case PING:
1502                 if (NetPingIP == 0) {
1503                         puts ("*** ERROR: ping address not given\n");
1504                         return (1);
1505                 }
1506                 goto common;
1507 #endif
1508 #if (CONFIG_COMMANDS & CFG_CMD_SNTP)
1509         case SNTP:
1510                 if (NetNtpServerIP == 0) {
1511                         puts ("*** ERROR: NTP server address not given\n");
1512                         return (1);
1513                 }
1514                 goto common;
1515 #endif
1516 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
1517         case NFS:
1518 #endif
1519         case NETCONS:
1520         case TFTP:
1521                 if (NetServerIP == 0) {
1522                         puts ("*** ERROR: `serverip' not set\n");
1523                         return (1);
1524                 }
1525 #if (CONFIG_COMMANDS & (CFG_CMD_PING | CFG_CMD_SNTP))
1526     common:
1527 #endif
1528
1529                 if (NetOurIP == 0) {
1530                         puts ("*** ERROR: `ipaddr' not set\n");
1531                         return (1);
1532                 }
1533                 /* Fall through */
1534
1535         case DHCP:
1536         case RARP:
1537         case BOOTP:
1538         case CDP:
1539                 if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
1540 #ifdef CONFIG_NET_MULTI
1541                         extern int eth_get_dev_index (void);
1542                         int num = eth_get_dev_index ();
1543
1544                         switch (num) {
1545                         case -1:
1546                                 puts ("*** ERROR: No ethernet found.\n");
1547                                 return (1);
1548                         case 0:
1549                                 puts ("*** ERROR: `ethaddr' not set\n");
1550                                 break;
1551                         default:
1552                                 printf ("*** ERROR: `eth%daddr' not set\n",
1553                                         num);
1554                                 break;
1555                         }
1556
1557                         NetStartAgain ();
1558                         return (2);
1559 #else
1560                         puts ("*** ERROR: `ethaddr' not set\n");
1561                         return (1);
1562 #endif
1563                 }
1564                 /* Fall through */
1565         default:
1566                 return (0);
1567         }
1568         return (0);             /* OK */
1569 }
1570 /**********************************************************************/
1571
1572 int
1573 NetCksumOk(uchar * ptr, int len)
1574 {
1575         return !((NetCksum(ptr, len) + 1) & 0xfffe);
1576 }
1577
1578
1579 unsigned
1580 NetCksum(uchar * ptr, int len)
1581 {
1582         ulong   xsum;
1583         ushort *p = (ushort *)ptr;
1584
1585         xsum = 0;
1586         while (len-- > 0)
1587                 xsum += *p++;
1588         xsum = (xsum & 0xffff) + (xsum >> 16);
1589         xsum = (xsum & 0xffff) + (xsum >> 16);
1590         return (xsum & 0xffff);
1591 }
1592
1593 int
1594 NetEthHdrSize(void)
1595 {
1596         ushort myvlanid;
1597
1598         myvlanid = ntohs(NetOurVLAN);
1599         if (myvlanid == (ushort)-1)
1600                 myvlanid = VLAN_NONE;
1601
1602         return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : VLAN_ETHER_HDR_SIZE;
1603 }
1604
1605 int
1606 NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
1607 {
1608         Ethernet_t *et = (Ethernet_t *)xet;
1609         ushort myvlanid;
1610
1611         myvlanid = ntohs(NetOurVLAN);
1612         if (myvlanid == (ushort)-1)
1613                 myvlanid = VLAN_NONE;
1614
1615         memcpy (et->et_dest, addr, 6);
1616         memcpy (et->et_src, NetOurEther, 6);
1617         if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
1618         et->et_protlen = htons(prot);
1619                 return ETHER_HDR_SIZE;
1620         } else {
1621                 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
1622
1623                 vet->vet_vlan_type = htons(PROT_VLAN);
1624                 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1625                 vet->vet_type = htons(prot);
1626                 return VLAN_ETHER_HDR_SIZE;
1627         }
1628 }
1629
1630 void
1631 NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
1632 {
1633         volatile IP_t *ip = (IP_t *)xip;
1634
1635         /*
1636          *      If the data is an odd number of bytes, zero the
1637          *      byte after the last byte so that the checksum
1638          *      will work.
1639          */
1640         if (len & 1)
1641                 xip[IP_HDR_SIZE + len] = 0;
1642
1643         /*
1644          *      Construct an IP and UDP header.
1645          *      (need to set no fragment bit - XXX)
1646          */
1647         ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
1648         ip->ip_tos   = 0;
1649         ip->ip_len   = htons(IP_HDR_SIZE + len);
1650         ip->ip_id    = htons(NetIPID++);
1651         ip->ip_off   = htons(0x4000);   /* No fragmentation */
1652         ip->ip_ttl   = 255;
1653         ip->ip_p     = 17;              /* UDP */
1654         ip->ip_sum   = 0;
1655         NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
1656         NetCopyIP((void*)&ip->ip_dst, &dest);      /* - "" - */
1657         ip->udp_src  = htons(sport);
1658         ip->udp_dst  = htons(dport);
1659         ip->udp_len  = htons(8 + len);
1660         ip->udp_xsum = 0;
1661         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1662 }
1663
1664 void copy_filename (char *dst, char *src, int size)
1665 {
1666         if (*src && (*src == '"')) {
1667                 ++src;
1668                 --size;
1669         }
1670
1671         while ((--size > 0) && *src && (*src != '"')) {
1672                 *dst++ = *src++;
1673         }
1674         *dst = '\0';
1675 }
1676
1677 #endif /* CFG_CMD_NET */
1678
1679 void ip_to_string (IPaddr_t x, char *s)
1680 {
1681         x = ntohl (x);
1682         sprintf (s, "%d.%d.%d.%d",
1683                  (int) ((x >> 24) & 0xff),
1684                  (int) ((x >> 16) & 0xff),
1685                  (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
1686         );
1687 }
1688
1689 IPaddr_t string_to_ip(char *s)
1690 {
1691         IPaddr_t addr;
1692         char *e;
1693         int i;
1694
1695         if (s == NULL)
1696                 return(0);
1697
1698         for (addr=0, i=0; i<4; ++i) {
1699                 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
1700                 addr <<= 8;
1701                 addr |= (val & 0xFF);
1702                 if (s) {
1703                         s = (*e) ? e+1 : e;
1704                 }
1705         }
1706
1707         return (htonl(addr));
1708 }
1709
1710 void VLAN_to_string(ushort x, char *s)
1711 {
1712         x = ntohs(x);
1713
1714         if (x == (ushort)-1)
1715                 x = VLAN_NONE;
1716
1717         if (x == VLAN_NONE)
1718                 strcpy(s, "none");
1719         else
1720                 sprintf(s, "%d", x & VLAN_IDMASK);
1721 }
1722
1723 ushort string_to_VLAN(char *s)
1724 {
1725         ushort id;
1726
1727         if (s == NULL)
1728                 return htons(VLAN_NONE);
1729
1730         if (*s < '0' || *s > '9')
1731                 id = VLAN_NONE;
1732         else
1733                 id = (ushort)simple_strtoul(s, NULL, 10);
1734
1735         return htons(id);
1736 }
1737
1738 void print_IPaddr (IPaddr_t x)
1739 {
1740         char tmp[16];
1741
1742         ip_to_string (x, tmp);
1743
1744         puts (tmp);
1745 }
1746
1747 IPaddr_t getenv_IPaddr (char *var)
1748 {
1749         return (string_to_ip(getenv(var)));
1750 }
1751
1752 ushort getenv_VLAN(char *var)
1753 {
1754         return (string_to_VLAN(getenv(var)));
1755 }