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