]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/net.c
* Patch by Masami Komiy, 22 Feb 2004:
[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
69
70 #include <common.h>
71 #include <watchdog.h>
72 #include <command.h>
73 #include <net.h>
74 #include "bootp.h"
75 #include "tftp.h"
76 #include "rarp.h"
77 #include "nfs.h"
78 #ifdef CONFIG_STATUS_LED
79 #include <status_led.h>
80 #include <miiphy.h>
81 #endif
82
83 #if (CONFIG_COMMANDS & CFG_CMD_NET)
84
85 #define ARP_TIMEOUT             5               /* Seconds before trying ARP again */
86 #ifndef CONFIG_NET_RETRY_COUNT
87 # define ARP_TIMEOUT_COUNT      5               /* # of timeouts before giving up  */
88 #else
89 # define ARP_TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
90 #endif
91
92 #if 0
93 #define ET_DEBUG
94 #endif
95
96 /** BOOTP EXTENTIONS **/
97
98 IPaddr_t        NetOurSubnetMask=0;             /* Our subnet mask (0=unknown)  */
99 IPaddr_t        NetOurGatewayIP=0;              /* Our gateways IP address      */
100 IPaddr_t        NetOurDNSIP=0;                  /* Our DNS IP address           */
101 #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
102 IPaddr_t        NetOurDNS2IP=0;                 /* Our 2nd DNS IP address       */
103 #endif
104 char            NetOurNISDomain[32]={0,};       /* Our NIS domain               */
105 char            NetOurHostName[32]={0,};        /* Our hostname                 */
106 char            NetOurRootPath[64]={0,};        /* Our bootpath                 */
107 ushort          NetBootFileSize=0;              /* Our bootfile size in blocks  */
108
109 /** END OF BOOTP EXTENTIONS **/
110
111 ulong           NetBootFileXferSize;    /* The actual transferred size of the bootfile (in bytes) */
112 uchar           NetOurEther[6];         /* Our ethernet address                 */
113 uchar           NetServerEther[6] =     /* Boot server enet address             */
114                         { 0, 0, 0, 0, 0, 0 };
115 IPaddr_t        NetOurIP;               /* Our IP addr (0 = unknown)            */
116 IPaddr_t        NetServerIP;            /* Our IP addr (0 = unknown)            */
117 volatile uchar *NetRxPkt;               /* Current receive packet               */
118 int             NetRxPktLen;            /* Current rx packet length             */
119 unsigned        NetIPID;                /* IP packet ID                         */
120 uchar           NetBcastAddr[6] =       /* Ethernet bcast address               */
121                         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
122 uchar           NetEtherNullAddr[6] =
123                         { 0, 0, 0, 0, 0, 0 };
124 int             NetState;               /* Network loop state                   */
125 #ifdef CONFIG_NET_MULTI
126 int             NetRestartWrap = 0;     /* Tried all network devices            */
127 static int      NetRestarted = 0;       /* Network loop restarted               */
128 static int      NetDevExists = 0;       /* At least one device configured       */
129 #endif
130
131 char            BootFile[128];          /* Boot File name                       */
132
133 #if (CONFIG_COMMANDS & CFG_CMD_PING)
134 IPaddr_t        NetPingIP;              /* the ip address to ping               */
135
136 static void PingStart(void);
137 #endif
138
139 volatile uchar  PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
140
141 volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets                     */
142
143 static rxhand_f *packetHandler;         /* Current RX packet handler            */
144 static thand_f *timeHandler;            /* Current timeout handler              */
145 static ulong    timeStart;              /* Time base value                      */
146 static ulong    timeDelta;              /* Current timeout value                */
147 volatile uchar *NetTxPacket = 0;        /* THE transmit packet                  */
148
149 static int net_check_prereq (proto_t protocol);
150
151 /**********************************************************************/
152
153 IPaddr_t        NetArpWaitPacketIP;
154 IPaddr_t        NetArpWaitReplyIP;
155 uchar          *NetArpWaitPacketMAC;    /* MAC address of waiting packet's destination  */
156 uchar          *NetArpWaitTxPacket;     /* THE transmit packet                  */
157 int             NetArpWaitTxPacketSize;
158 uchar           NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
159 ulong           NetArpWaitTimerStart;
160 int             NetArpWaitTry;
161
162 void ArpRequest(void)
163 {
164         int i;
165         volatile uchar *pkt;
166         ARP_t * arp;
167
168 #ifdef ET_DEBUG
169         printf("ARP broadcast %d\n", NetArpWaitTry);
170 #endif
171         pkt = NetTxPacket;
172
173         NetSetEther(pkt, NetBcastAddr, PROT_ARP);
174         pkt += ETHER_HDR_SIZE;
175
176         arp = (ARP_t *)pkt;
177
178         arp->ar_hrd = htons(ARP_ETHER);
179         arp->ar_pro = htons(PROT_IP);
180         arp->ar_hln = 6;
181         arp->ar_pln = 4;
182         arp->ar_op  = htons(ARPOP_REQUEST);
183
184         memcpy (&arp->ar_data[0], NetOurEther, 6);      /* source ET addr       */
185         NetWriteIP((uchar*)&arp->ar_data[6], NetOurIP); /* source IP addr       */
186         for (i=10; i<16; ++i) {
187                 arp->ar_data[i] = 0;                    /* dest ET addr = 0     */
188         }
189
190         if((NetArpWaitPacketIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) {
191             if (NetOurGatewayIP == 0) {
192                 puts ("## Warning: gatewayip needed but not set\n");
193             }
194             NetArpWaitReplyIP = NetOurGatewayIP;
195         } else
196             NetArpWaitReplyIP = NetArpWaitPacketIP;
197
198         NetWriteIP((uchar*)&arp->ar_data[16], NetArpWaitReplyIP);
199         (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
200 }
201
202 void ArpTimeoutCheck(void)
203 {
204         ulong t;
205
206         if (!NetArpWaitPacketIP)
207                 return;
208
209         t = get_timer(0);
210
211         /* check for arp timeout */
212         if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT * CFG_HZ) {
213                 NetArpWaitTry++;
214
215                 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
216                         puts ("\nARP Retry count exceeded; starting again\n");
217                         NetArpWaitTry = 0;
218                         NetStartAgain();
219                 } else {
220                         NetArpWaitTimerStart = t;
221                         ArpRequest();
222                 }
223         }
224 }
225
226 /**********************************************************************/
227 /*
228  *      Main network processing loop.
229  */
230
231 int
232 NetLoop(proto_t protocol)
233 {
234         DECLARE_GLOBAL_DATA_PTR;
235
236         bd_t *bd = gd->bd;
237
238 #ifdef CONFIG_NET_MULTI
239         NetRestarted = 0;
240         NetDevExists = 0;
241 #endif
242
243         /* XXX problem with bss workaround */
244         NetArpWaitPacketMAC = NULL;
245         NetArpWaitTxPacket = NULL;
246         NetArpWaitPacketIP = 0;
247         NetArpWaitReplyIP = 0;
248         NetArpWaitTxPacket = NULL;
249         NetTxPacket = NULL;
250
251         if (!NetTxPacket) {
252                 int     i;
253
254                 /*
255                  *      Setup packet buffers, aligned correctly.
256                  */
257                 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
258                 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
259                 for (i = 0; i < PKTBUFSRX; i++) {
260                         NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
261                 }
262
263         }
264
265         if (!NetArpWaitTxPacket) {
266                 NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
267                 NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
268                 NetArpWaitTxPacketSize = 0;
269         }
270
271         eth_halt();
272         if(eth_init(bd) < 0)
273             return(-1);
274
275 restart:
276 #ifdef CONFIG_NET_MULTI
277         memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
278 #else
279         memcpy (NetOurEther, bd->bi_enetaddr, 6);
280 #endif
281
282         NetState = NETLOOP_CONTINUE;
283
284         /*
285          *      Start the ball rolling with the given start function.  From
286          *      here on, this code is a state machine driven by received
287          *      packets and timer events.
288          */
289
290         switch (protocol) {
291 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
292         case NFS:
293 #endif
294 #if (CONFIG_COMMANDS & CFG_CMD_PING)
295         case PING:
296 #endif
297         case TFTP:
298                 NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
299                 NetOurGatewayIP = getenv_IPaddr ("gatewayip");
300                 NetOurSubnetMask= getenv_IPaddr ("netmask");
301
302                 switch (protocol) {
303 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
304                 case NFS:
305 #endif
306                 case TFTP:
307                         NetServerIP = getenv_IPaddr ("serverip");
308                         break;
309 #if (CONFIG_COMMANDS & CFG_CMD_PING)
310                 case PING:
311                         /* nothing */
312                         break;
313 #endif
314                 default:
315                         break;
316                 }
317
318                 break;
319         case BOOTP:
320         case RARP:
321                 /*
322                  * initialize our IP addr to 0 in order to accept ANY
323                  * IP addr assigned to us by the BOOTP / RARP server
324                  */
325                 NetOurIP = 0;
326                 NetServerIP = 0;
327                 break;
328         default:
329                 break;
330         }
331
332         switch (net_check_prereq (protocol)) {
333         case 1:
334                 /* network not configured */
335                 return (-1);
336
337 #ifdef CONFIG_NET_MULTI
338         case 2:
339                 /* network device not configured */
340                 break;
341 #endif /* CONFIG_NET_MULTI */
342
343         case 0:
344 #ifdef CONFIG_NET_MULTI
345                 NetDevExists = 1;
346 #endif
347                 switch (protocol) {
348                 case TFTP:
349                         /* always use ARP to get server ethernet address */
350                         TftpStart();
351                         break;
352
353 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
354                 case DHCP:
355                         /* Start with a clean slate... */
356                         NetOurIP = 0;
357                         NetServerIP = 0;
358                         DhcpRequest();          /* Basically same as BOOTP */
359                         break;
360 #endif /* CFG_CMD_DHCP */
361
362                 case BOOTP:
363                         BootpTry = 0;
364                         BootpRequest ();
365                         break;
366
367                 case RARP:
368                         RarpTry = 0;
369                         RarpRequest ();
370                         break;
371 #if (CONFIG_COMMANDS & CFG_CMD_PING)
372                 case PING:
373                         PingStart();
374                         break;
375 #endif
376 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
377                 case NFS:
378                         NfsStart();
379                         break;
380 #endif
381                 default:
382                         break;
383                 }
384
385                 NetBootFileXferSize = 0;
386                 break;
387         }
388
389 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
390 #if defined(CFG_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
391         /*
392          * Echo the inverted link state to the fault LED.
393          */
394         if(miiphy_link(CFG_FAULT_MII_ADDR)) {
395                 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
396         } else {
397                 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
398         }
399 #endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
400 #endif /* CONFIG_MII, ... */
401
402         /*
403          *      Main packet reception loop.  Loop receiving packets until
404          *      someone sets `NetQuit'.
405          */
406         for (;;) {
407                 WATCHDOG_RESET();
408 #ifdef CONFIG_SHOW_ACTIVITY
409                 {
410                         extern void show_activity(int arg);
411                         show_activity(1);
412                 }
413 #endif
414                 /*
415                  *      Check the ethernet for a new packet.  The ethernet
416                  *      receive routine will process it.
417                  */
418                         eth_rx();
419
420                 /*
421                  *      Abort if ctrl-c was pressed.
422                  */
423                 if (ctrlc()) {
424                         eth_halt();
425                         printf("\nAbort\n");
426                         return (-1);
427                 }
428
429                 ArpTimeoutCheck();
430
431                 /*
432                  *      Check for a timeout, and run the timeout handler
433                  *      if we have one.
434                  */
435                 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
436                         thand_f *x;
437
438 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
439 #if defined(CFG_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
440                         /*
441                          * Echo the inverted link state to the fault LED.
442                          */
443                         if(miiphy_link(CFG_FAULT_MII_ADDR)) {
444                                 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
445                         } else {
446                                 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
447                         }
448 #endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
449 #endif /* CONFIG_MII, ... */
450                         x = timeHandler;
451                         timeHandler = (thand_f *)0;
452                         (*x)();
453                 }
454
455
456                 switch (NetState) {
457
458                 case NETLOOP_RESTART:
459 #ifdef CONFIG_NET_MULTI
460                         NetRestarted = 1;
461 #endif
462                         goto restart;
463
464                 case NETLOOP_SUCCESS:
465                         if (NetBootFileXferSize > 0) {
466                                 char buf[10];
467                                 printf("Bytes transferred = %ld (%lx hex)\n",
468                                         NetBootFileXferSize,
469                                         NetBootFileXferSize);
470                                 sprintf(buf, "%lx", NetBootFileXferSize);
471                                 setenv("filesize", buf);
472                         }
473                         eth_halt();
474                         return NetBootFileXferSize;
475
476                 case NETLOOP_FAIL:
477                         return (-1);
478                 }
479         }
480 }
481
482 /**********************************************************************/
483
484 static void
485 startAgainTimeout(void)
486 {
487         NetState = NETLOOP_RESTART;
488 }
489
490 static void
491 startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
492 {
493         /* Totally ignore the packet */
494 }
495
496 void
497 NetStartAgain(void)
498 {
499 #ifndef CONFIG_NET_MULTI
500         NetSetTimeout(10 * CFG_HZ, startAgainTimeout);
501         NetSetHandler(startAgainHandler);
502 #else
503         DECLARE_GLOBAL_DATA_PTR;
504
505         eth_halt();
506         eth_try_another(!NetRestarted);
507         eth_init(gd->bd);
508         if (NetRestartWrap)
509         {
510                 NetRestartWrap = 0;
511                 if (NetDevExists)
512                 {
513                         NetSetTimeout(10 * CFG_HZ, startAgainTimeout);
514                         NetSetHandler(startAgainHandler);
515                 }
516                 else
517                 {
518                         NetState = NETLOOP_FAIL;
519                 }
520         }
521         else
522         {
523                 NetState = NETLOOP_RESTART;
524         }
525 #endif
526 }
527
528 /**********************************************************************/
529 /*
530  *      Miscelaneous bits.
531  */
532
533 void
534 NetSetHandler(rxhand_f * f)
535 {
536         packetHandler = f;
537 }
538
539
540 void
541 NetSetTimeout(int iv, thand_f * f)
542 {
543         if (iv == 0) {
544                 timeHandler = (thand_f *)0;
545         } else {
546                 timeHandler = f;
547                 timeStart = get_timer(0);
548                 timeDelta = iv;
549         }
550 }
551
552
553 void
554 NetSendPacket(volatile uchar * pkt, int len)
555 {
556         (void) eth_send(pkt, len);
557 }
558
559 int
560 NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
561 {
562         /* convert to new style broadcast */
563         if (dest == 0)
564                 dest = 0xFFFFFFFF;
565
566         /* if broadcast, make the ether address a broadcast and don't do ARP */
567         if (dest == 0xFFFFFFFF)
568                 ether = NetBcastAddr;
569
570         /* if MAC address was not discovered yet, save the packet and do an ARP request */
571         if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
572
573 #ifdef ET_DEBUG
574                 printf("sending ARP for %08lx\n", dest);
575 #endif
576
577                 NetArpWaitPacketIP = dest;
578                 NetArpWaitPacketMAC = ether;
579                 NetSetEther (NetArpWaitTxPacket, NetArpWaitPacketMAC, PROT_IP);
580                 NetSetIP (NetArpWaitTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
581                 memcpy(NetArpWaitTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE,
582                         (uchar *)NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE, len);
583
584                 /* size of the waiting packet */
585                 NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE + len;
586
587                 /* and do the ARP request */
588                 NetArpWaitTry = 1;
589                 NetArpWaitTimerStart = get_timer(0);
590                 ArpRequest();
591                 return 1;       /* waiting */
592         }
593
594 #ifdef ET_DEBUG
595         printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
596                         dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
597 #endif
598
599         NetSetEther (NetTxPacket, ether, PROT_IP);
600         NetSetIP (NetTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
601         (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len);
602
603         return 0;       /* transmited */
604 }
605
606 #if (CONFIG_COMMANDS & CFG_CMD_PING)
607 static ushort PingSeqNo;
608
609 int PingSend(void)
610 {
611         static uchar mac[6];
612         volatile IP_t *ip;
613         volatile ushort *s;
614
615         /* XXX always send arp request */
616
617         memcpy(mac, NetEtherNullAddr, 6);
618
619 #ifdef ET_DEBUG
620         printf("sending ARP for %08lx\n", NetPingIP);
621 #endif
622
623         NetArpWaitPacketIP = NetPingIP;
624         NetArpWaitPacketMAC = mac;
625
626         NetSetEther(NetArpWaitTxPacket, mac, PROT_IP);
627
628         ip = (volatile IP_t *)(NetArpWaitTxPacket + ETHER_HDR_SIZE);
629
630         /*
631          *      Construct an IP and ICMP header.  (need to set no fragment bit - XXX)
632          */
633         ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
634         ip->ip_tos   = 0;
635         ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
636         ip->ip_id    = htons(NetIPID++);
637         ip->ip_off   = htons(0x4000);   /* No fragmentation */
638         ip->ip_ttl   = 255;
639         ip->ip_p     = 0x01;            /* ICMP */
640         ip->ip_sum   = 0;
641         NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
642         NetCopyIP((void*)&ip->ip_dst, &NetPingIP);         /* - "" - */
643         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
644
645         s = &ip->udp_src;               /* XXX ICMP starts here */
646         s[0] = htons(0x0800);           /* echo-request, code */
647         s[1] = 0;                       /* checksum */
648         s[2] = 0;                       /* identifier */
649         s[3] = htons(PingSeqNo++);      /* sequence number */
650         s[1] = ~NetCksum((uchar *)s, 8/2);
651
652         /* size of the waiting packet */
653         NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + 8;
654
655         /* and do the ARP request */
656         NetArpWaitTry = 1;
657         NetArpWaitTimerStart = get_timer(0);
658         ArpRequest();
659         return 1;       /* waiting */
660 }
661
662 static void
663 PingTimeout (void)
664 {
665         eth_halt();
666         NetState = NETLOOP_FAIL;        /* we did not get the reply */
667 }
668
669 static void
670 PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
671 {
672         IPaddr_t tmp;
673         volatile IP_t *ip = (volatile IP_t *)pkt;
674
675         tmp = NetReadIP((void *)&ip->ip_src);
676         if (tmp != NetPingIP)
677                 return;
678
679         NetState = NETLOOP_SUCCESS;
680 }
681
682 static void PingStart(void)
683 {
684         NetSetTimeout (10 * CFG_HZ, PingTimeout);
685         NetSetHandler (PingHandler);
686
687         PingSend();
688 }
689
690 #endif
691
692 void
693 NetReceive(volatile uchar * pkt, int len)
694 {
695         Ethernet_t *et;
696         IP_t    *ip;
697         ARP_t   *arp;
698         IPaddr_t tmp;
699         int     x;
700
701         NetRxPkt = pkt;
702         NetRxPktLen = len;
703         et = (Ethernet_t *)pkt;
704
705         x = ntohs(et->et_protlen);
706
707         if (x < 1514) {
708                 /*
709                  *      Got a 802 packet.  Check the other protocol field.
710                  */
711                 x = ntohs(et->et_prot);
712                 ip = (IP_t *)(pkt + E802_HDR_SIZE);
713                 len -= E802_HDR_SIZE;
714         } else {
715                 ip = (IP_t *)(pkt + ETHER_HDR_SIZE);
716                 len -= ETHER_HDR_SIZE;
717         }
718
719 #ifdef ET_DEBUG
720         printf("Receive from protocol 0x%x\n", x);
721 #endif
722
723         switch (x) {
724
725         case PROT_ARP:
726                 /*
727                  * We have to deal with two types of ARP packets:
728                  * - REQUEST packets will be answered by sending  our
729                  *   IP address - if we know it.
730                  * - REPLY packates are expected only after we asked
731                  *   for the TFTP server's or the gateway's ethernet
732                  *   address; so if we receive such a packet, we set
733                  *   the server ethernet address
734                  */
735 #ifdef ET_DEBUG
736                 printf("Got ARP\n");
737 #endif
738                 arp = (ARP_t *)ip;
739                 if (len < ARP_HDR_SIZE) {
740                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
741                         return;
742                 }
743                 if (ntohs(arp->ar_hrd) != ARP_ETHER) {
744                         return;
745                 }
746                 if (ntohs(arp->ar_pro) != PROT_IP) {
747                         return;
748                 }
749                 if (arp->ar_hln != 6) {
750                         return;
751                 }
752                 if (arp->ar_pln != 4) {
753                         return;
754                 }
755
756                 if (NetOurIP == 0) {
757                         return;
758                 }
759
760                 if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
761                         return;
762                 }
763
764                 switch (ntohs(arp->ar_op)) {
765                 case ARPOP_REQUEST:             /* reply with our IP address    */
766 #ifdef ET_DEBUG
767                         printf("Got ARP REQUEST, return our IP\n");
768 #endif
769                         NetSetEther((uchar *)et, et->et_src, PROT_ARP);
770                         arp->ar_op = htons(ARPOP_REPLY);
771                         memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);
772                         NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
773                         memcpy   (&arp->ar_data[ 0], NetOurEther, 6);
774                         NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
775                         (void) eth_send((uchar *)et, ((uchar *)arp-pkt) + ARP_HDR_SIZE);
776                         return;
777
778                 case ARPOP_REPLY:               /* arp reply */
779                         /* are we waiting for a reply */
780                         if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
781                                 break;
782 #ifdef ET_DEBUG
783                         printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
784                                 arp->ar_data[0], arp->ar_data[1],
785                                 arp->ar_data[2], arp->ar_data[3],
786                                 arp->ar_data[4], arp->ar_data[5]);
787 #endif
788
789                         tmp = NetReadIP(&arp->ar_data[6]);
790
791                         /* matched waiting packet's address */
792                         if (tmp == NetArpWaitReplyIP) {
793 #ifdef ET_DEBUG
794                                 printf("Got it\n");
795 #endif
796                                 /* save address for later use */
797                                 memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
798
799                                 /* modify header, and transmit it */
800                                 memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
801                                 (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
802
803                                 /* no arp request pending now */
804                                 NetArpWaitPacketIP = 0;
805                                 NetArpWaitTxPacketSize = 0;
806                                 NetArpWaitPacketMAC = NULL;
807
808                         }
809                         return;
810                 default:
811 #ifdef ET_DEBUG
812                         printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
813 #endif
814                         return;
815                 }
816
817         case PROT_RARP:
818 #ifdef ET_DEBUG
819                 printf("Got RARP\n");
820 #endif
821                 arp = (ARP_t *)ip;
822                 if (len < ARP_HDR_SIZE) {
823                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
824                         return;
825                 }
826
827                 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
828                         (ntohs(arp->ar_hrd) != ARP_ETHER)   ||
829                         (ntohs(arp->ar_pro) != PROT_IP)     ||
830                         (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
831
832                         printf("invalid RARP header\n");
833                 } else {
834                         NetCopyIP(&NetOurIP,    &arp->ar_data[16]);
835                         NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
836                         memcpy (NetServerEther, &arp->ar_data[ 0], 6);
837
838                         (*packetHandler)(0,0,0,0);
839                 }
840                 break;
841
842         case PROT_IP:
843 #ifdef ET_DEBUG
844                 printf("Got IP\n");
845 #endif
846                 if (len < IP_HDR_SIZE) {
847                         debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
848                         return;
849                 }
850                 if (len < ntohs(ip->ip_len)) {
851                         printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
852                         return;
853                 }
854                 len = ntohs(ip->ip_len);
855 #ifdef ET_DEBUG
856                 printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
857 #endif
858                 if ((ip->ip_hl_v & 0xf0) != 0x40) {
859                         return;
860                 }
861                 if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
862                         return;
863                 }
864                 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
865                         printf("checksum bad\n");
866                         return;
867                 }
868                 tmp = NetReadIP(&ip->ip_dst);
869                 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
870                         return;
871                 }
872                 /*
873                  * watch for ICMP host redirects
874                  *
875                  * There is no real handler code (yet). We just watch
876                  * for ICMP host redirect messages. In case anybody
877                  * sees these messages: please contact me
878                  * (wd@denx.de), or - even better - send me the
879                  * necessary fixes :-)
880                  *
881                  * Note: in all cases where I have seen this so far
882                  * it was a problem with the router configuration,
883                  * for instance when a router was configured in the
884                  * BOOTP reply, but the TFTP server was on the same
885                  * subnet. So this is probably a warning that your
886                  * configuration might be wrong. But I'm not really
887                  * sure if there aren't any other situations.
888                  */
889                 if (ip->ip_p == IPPROTO_ICMP) {
890                         ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
891
892                         switch (icmph->type) {
893                         case ICMP_REDIRECT:
894                         if (icmph->code != ICMP_REDIR_HOST)
895                                 return;
896                         puts (" ICMP Host Redirect to ");
897                         print_IPaddr(icmph->un.gateway);
898                         putc(' ');
899                                 break;
900 #if (CONFIG_COMMANDS & CFG_CMD_PING)
901                         case ICMP_ECHO_REPLY:
902                                 /*
903                                  *      IP header OK.  Pass the packet to the current handler.
904                                  */
905                                 /* XXX point to ip packet */
906                                 (*packetHandler)((uchar *)ip, 0, 0, 0);
907                                 break;
908 #endif
909                         default:
910                                 return;
911                         }
912                 } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
913                         return;
914                 }
915
916                 /*
917                  *      IP header OK.  Pass the packet to the current handler.
918                  */
919                 (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
920                                                 ntohs(ip->udp_dst),
921                                                 ntohs(ip->udp_src),
922                                                 ntohs(ip->udp_len) - 8);
923
924                 break;
925         }
926 }
927
928
929 /**********************************************************************/
930
931 static int net_check_prereq (proto_t protocol)
932 {
933         switch (protocol) {
934                         /* Fall through */
935 #if (CONFIG_COMMANDS & CFG_CMD_PING)
936         case PING:
937                         if (NetPingIP == 0) {
938                                 puts ("*** ERROR: ping address not given\n");
939                                 return (1);
940                         }
941                         goto common;
942 #endif
943 #if (CONFIG_COMMANDS & CFG_CMD_NFS)
944         case NFS:
945 #endif
946         case TFTP:
947                         if (NetServerIP == 0) {
948                                 puts ("*** ERROR: `serverip' not set\n");
949                                 return (1);
950                         }
951
952 #if (CONFIG_COMMANDS & CFG_CMD_PING)
953                 common:
954 #endif
955
956                         if (NetOurIP == 0) {
957                                 puts ("*** ERROR: `ipaddr' not set\n");
958                                 return (1);
959                         }
960                         /* Fall through */
961
962         case DHCP:
963         case RARP:
964         case BOOTP:
965                         if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
966 #ifdef CONFIG_NET_MULTI
967                             extern int eth_get_dev_index (void);
968                             int num = eth_get_dev_index();
969
970                             switch (num) {
971                             case -1:
972                                 puts ("*** ERROR: No ethernet found.\n");
973                                 return (1);
974                             case 0:
975                                 puts ("*** ERROR: `ethaddr' not set\n");
976                                 break;
977                             default:
978                                 printf ("*** ERROR: `eth%daddr' not set\n",
979                                         num);
980                                 break;
981                             }
982
983                             NetStartAgain ();
984                             return (2);
985 #else
986                             puts ("*** ERROR: `ethaddr' not set\n");
987                             return (1);
988 #endif
989                         }
990                         /* Fall through */
991                 default:
992                         return(0);
993         }
994         return (0);     /* OK */
995 }
996 /**********************************************************************/
997
998 int
999 NetCksumOk(uchar * ptr, int len)
1000 {
1001         return !((NetCksum(ptr, len) + 1) & 0xfffe);
1002 }
1003
1004
1005 unsigned
1006 NetCksum(uchar * ptr, int len)
1007 {
1008         ulong   xsum;
1009
1010         xsum = 0;
1011         while (len-- > 0)
1012                 xsum += *((ushort *)ptr)++;
1013         xsum = (xsum & 0xffff) + (xsum >> 16);
1014         xsum = (xsum & 0xffff) + (xsum >> 16);
1015         return (xsum & 0xffff);
1016 }
1017
1018
1019 void
1020 NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
1021 {
1022         Ethernet_t *et = (Ethernet_t *)xet;
1023
1024         memcpy (et->et_dest, addr, 6);
1025         memcpy (et->et_src, NetOurEther, 6);
1026         et->et_protlen = htons(prot);
1027 }
1028
1029
1030 void
1031 NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
1032 {
1033         volatile IP_t *ip = (IP_t *)xip;
1034
1035         /*
1036          *      If the data is an odd number of bytes, zero the
1037          *      byte after the last byte so that the checksum
1038          *      will work.
1039          */
1040         if (len & 1)
1041                 xip[IP_HDR_SIZE + len] = 0;
1042
1043         /*
1044          *      Construct an IP and UDP header.
1045                         (need to set no fragment bit - XXX)
1046          */
1047         ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
1048         ip->ip_tos   = 0;
1049         ip->ip_len   = htons(IP_HDR_SIZE + len);
1050         ip->ip_id    = htons(NetIPID++);
1051         ip->ip_off   = htons(0x4000);   /* No fragmentation */
1052         ip->ip_ttl   = 255;
1053         ip->ip_p     = 17;              /* UDP */
1054         ip->ip_sum   = 0;
1055         NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
1056         NetCopyIP((void*)&ip->ip_dst, &dest);      /* - "" - */
1057         ip->udp_src  = htons(sport);
1058         ip->udp_dst  = htons(dport);
1059         ip->udp_len  = htons(8 + len);
1060         ip->udp_xsum = 0;
1061         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1062 }
1063
1064 void copy_filename (uchar *dst, uchar *src, int size)
1065 {
1066         if (*src && (*src == '"')) {
1067                 ++src;
1068                 --size;
1069         }
1070
1071         while ((--size > 0) && *src && (*src != '"')) {
1072                 *dst++ = *src++;
1073         }
1074         *dst = '\0';
1075 }
1076
1077 #endif /* CFG_CMD_NET */
1078
1079 void ip_to_string (IPaddr_t x, char *s)
1080 {
1081     x = ntohl(x);
1082     sprintf (s,"%d.%d.%d.%d",
1083         (int)((x >> 24) & 0xff),
1084         (int)((x >> 16) & 0xff),
1085         (int)((x >>  8) & 0xff),
1086         (int)((x >>  0) & 0xff)
1087     );
1088 }
1089
1090 IPaddr_t string_to_ip(char *s)
1091 {
1092         IPaddr_t addr;
1093         char *e;
1094         int i;
1095
1096         if (s == NULL)
1097                 return(0);
1098
1099         for (addr=0, i=0; i<4; ++i) {
1100                 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
1101                 addr <<= 8;
1102                 addr |= (val & 0xFF);
1103                 if (s) {
1104                         s = (*e) ? e+1 : e;
1105                 }
1106         }
1107
1108         return (htonl(addr));
1109 }
1110
1111 void print_IPaddr (IPaddr_t x)
1112 {
1113     char tmp[16];
1114
1115     ip_to_string(x, tmp);
1116
1117     puts(tmp);
1118 }
1119
1120 IPaddr_t getenv_IPaddr (char *var)
1121 {
1122         return (string_to_ip(getenv(var)));
1123 }