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