]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/net.c
cc3bec638c006ec83fe103c9c506d6eb78058022
[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 #include "arp.h"
69
70 #if (CONFIG_COMMANDS & CFG_CMD_NET)
71
72 #if 0
73 #define ET_DEBUG
74 #endif
75
76 /** BOOTP EXTENTIONS **/
77
78 IPaddr_t        NetOurSubnetMask=0;             /* Our subnet mask (0=unknown)  */
79 IPaddr_t        NetOurGatewayIP=0;              /* Our gateways IP address      */
80 IPaddr_t        NetOurDNSIP=0;                  /* Our DNS IP address           */
81 char            NetOurNISDomain[32]={0,};       /* Our NIS domain               */
82 char            NetOurHostName[32]={0,};        /* Our hostname                 */
83 char            NetOurRootPath[64]={0,};        /* Our bootpath                 */
84 ushort          NetBootFileSize=0;              /* Our bootfile size in blocks  */
85
86 /** END OF BOOTP EXTENTIONS **/
87
88 ulong           NetBootFileXferSize;    /* The actual transferred size of the bootfile (in bytes) */
89 uchar           NetOurEther[6];         /* Our ethernet address                 */
90 uchar           NetServerEther[6] =     /* Boot server enet address             */
91                         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
92 IPaddr_t        NetOurIP;               /* Our IP addr (0 = unknown)            */
93 IPaddr_t        NetServerIP;            /* Our IP addr (0 = unknown)            */
94 volatile uchar *NetRxPkt;               /* Current receive packet               */
95 int             NetRxPktLen;            /* Current rx packet length             */
96 unsigned        NetIPID;                /* IP packet ID                         */
97 uchar           NetBcastAddr[6] =       /* Ethernet bcast address               */
98                         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
99 int             NetState;               /* Network loop state                   */
100 #ifdef CONFIG_NET_MULTI
101 int             NetRestartWrap = 0;     /* Tried all network devices            */
102 static int      NetRestarted = 0;       /* Network loop restarted               */
103 static int      NetDevExists = 0;       /* At least one device configured       */
104 #endif
105
106 char            BootFile[128];          /* Boot File name                       */
107
108 volatile uchar  PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
109
110 volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets                     */
111
112 static rxhand_f *packetHandler;         /* Current RX packet handler            */
113 static thand_f *timeHandler;            /* Current timeout handler              */
114 static ulong    timeValue;              /* Current timeout value                */
115 volatile uchar *NetTxPacket = 0;        /* THE transmit packet                  */
116
117 static int net_check_prereq (proto_t protocol);
118
119 /**********************************************************************/
120 /*
121  *      Main network processing loop.
122  */
123
124 int
125 NetLoop(proto_t protocol)
126 {
127         DECLARE_GLOBAL_DATA_PTR;
128
129         bd_t *bd = gd->bd;
130
131 #ifdef CONFIG_NET_MULTI
132         NetRestarted = 0;
133         NetDevExists = 0;
134 #endif
135
136         if (!NetTxPacket) {
137                 int     i;
138
139                 /*
140                  *      Setup packet buffers, aligned correctly.
141                  */
142                 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
143                 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
144                 for (i = 0; i < PKTBUFSRX; i++) {
145                         NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
146                 }
147         }
148
149         eth_halt();
150         eth_init(bd);
151
152 restart:
153 #ifdef CONFIG_NET_MULTI
154         memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
155 #else
156         memcpy (NetOurEther, bd->bi_enetaddr, 6);
157 #endif
158
159         NetState = NETLOOP_CONTINUE;
160
161         /*
162          *      Start the ball rolling with the given start function.  From
163          *      here on, this code is a state machine driven by received
164          *      packets and timer events.
165          */
166
167         switch (protocol) {
168         case TFTP:
169                 NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
170                 NetServerIP     = getenv_IPaddr ("serverip");
171                 NetOurGatewayIP = getenv_IPaddr ("gatewayip");
172                 NetOurSubnetMask= getenv_IPaddr ("netmask");
173                 break;
174         case BOOTP:
175         case RARP:
176                 /*
177                  * initialize our IP addr to 0 in order to accept ANY
178                  * IP addr assigned to us by the BOOTP / RARP server
179                  */
180                 NetOurIP = 0;
181                 NetServerIP = 0;
182                 break;
183         default:
184                 break;
185         }
186
187         switch (net_check_prereq (protocol)) {
188         case 1:
189                 /* network not configured */
190                 return 0;
191
192 #ifdef CONFIG_NET_MULTI
193         case 2:
194                 /* network device not configured */
195                 break;
196 #endif /* CONFIG_NET_MULTI */
197
198         case 0:
199 #ifdef CONFIG_NET_MULTI
200                 NetDevExists = 1;
201 #endif
202                 switch (protocol) {
203                 case TFTP:
204                         /* always use ARP to get server ethernet address */
205                         ArpTry = 0;
206                         ArpRequest ();
207                         break;
208
209 #if (CONFIG_COMMANDS & CFG_CMD_DHCP)
210                 case DHCP:
211                         /* Start with a clean slate... */
212                         NetOurIP = 0;
213                         NetServerIP = 0;
214                         DhcpRequest();          /* Basically same as BOOTP */
215                         break;
216 #endif /* CFG_CMD_DHCP */
217
218                 case BOOTP:
219                         BootpTry = 0;
220                         BootpRequest ();
221                         break;
222
223                 case RARP:
224                         RarpTry = 0;
225                         RarpRequest ();
226                         break;
227                 default:
228                         break;
229                 }
230
231                 NetBootFileXferSize = 0;
232                 break;
233         }
234
235
236         /*
237          *      Main packet reception loop.  Loop receiving packets until
238          *      someone sets `NetQuit'.
239          */
240         for (;;) {
241                 WATCHDOG_RESET();
242 #ifdef CONFIG_SHOW_ACTIVITY
243                 {
244                         extern void show_activity(int arg);
245                         show_activity(1);
246                 }
247 #endif
248                 /*
249                  *      Check the ethernet for a new packet.  The ethernet
250                  *      receive routine will process it.
251                  */
252                         eth_rx();
253
254                 /*
255                  *      Abort if ctrl-c was pressed.
256                  */
257                 if (ctrlc()) {
258                         eth_halt();
259                         printf("\nAbort\n");
260                         return 0;
261                 }
262
263
264                 /*
265                  *      Check for a timeout, and run the timeout handler
266                  *      if we have one.
267                  */
268                 if (timeHandler && (get_timer(0) > timeValue)) {
269                         thand_f *x;
270
271                         x = timeHandler;
272                         timeHandler = (thand_f *)0;
273                         (*x)();
274                 }
275
276
277                 switch (NetState) {
278
279                 case NETLOOP_RESTART:
280 #ifdef CONFIG_NET_MULTI
281                         NetRestarted = 1;
282 #endif
283                         goto restart;
284
285                 case NETLOOP_SUCCESS:
286                         if (NetBootFileXferSize > 0) {
287                                 char buf[10];
288                                 printf("Bytes transferred = %ld (%lx hex)\n",
289                                         NetBootFileXferSize,
290                                         NetBootFileXferSize);
291                                 sprintf(buf, "%lx", NetBootFileXferSize);
292                                 setenv("filesize", buf);
293                         }
294                         eth_halt();
295                         return NetBootFileXferSize;
296
297                 case NETLOOP_FAIL:
298                         return 0;
299                 }
300         }
301 }
302
303 /**********************************************************************/
304
305 static void
306 startAgainTimeout(void)
307 {
308         NetState = NETLOOP_RESTART;
309 }
310
311 static void
312 startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
313 {
314         /* Totally ignore the packet */
315 }
316
317 void
318 NetStartAgain(void)
319 {
320 #ifndef CONFIG_NET_MULTI
321         NetSetTimeout(10 * CFG_HZ, startAgainTimeout);
322         NetSetHandler(startAgainHandler);
323 #else
324         DECLARE_GLOBAL_DATA_PTR;
325
326         eth_halt();
327         eth_try_another(!NetRestarted);
328         eth_init(gd->bd);
329         if (NetRestartWrap)
330         {
331                 NetRestartWrap = 0;
332                 if (NetDevExists)
333                 {
334                         NetSetTimeout(10 * CFG_HZ, startAgainTimeout);
335                         NetSetHandler(startAgainHandler);
336                 }
337                 else
338                 {
339                         NetState = NETLOOP_FAIL;
340                 }
341         }
342         else
343         {
344                 NetState = NETLOOP_RESTART;
345         }
346 #endif
347 }
348
349 /**********************************************************************/
350 /*
351  *      Miscelaneous bits.
352  */
353
354 void
355 NetSetHandler(rxhand_f * f)
356 {
357         packetHandler = f;
358 }
359
360
361 void
362 NetSetTimeout(int iv, thand_f * f)
363 {
364         if (iv == 0) {
365                 timeHandler = (thand_f *)0;
366         } else {
367                 timeHandler = f;
368                 timeValue = get_timer(0) + iv;
369         }
370 }
371
372
373 void
374 NetSendPacket(volatile uchar * pkt, int len)
375 {
376         (void) eth_send(pkt, len);
377 }
378
379
380
381 void
382 NetReceive(volatile uchar * pkt, int len)
383 {
384         Ethernet_t *et;
385         IP_t    *ip;
386         ARP_t   *arp;
387         IPaddr_t tmp;
388         int     x;
389
390
391         NetRxPkt = pkt;
392         NetRxPktLen = len;
393         et = (Ethernet_t *)pkt;
394
395         x = ntohs(et->et_protlen);
396
397         if (x < 1514) {
398                 /*
399                  *      Got a 802 packet.  Check the other protocol field.
400                  */
401                 x = ntohs(et->et_prot);
402                 ip = (IP_t *)(pkt + E802_HDR_SIZE);
403                 len -= E802_HDR_SIZE;
404         } else {
405                 ip = (IP_t *)(pkt + ETHER_HDR_SIZE);
406                 len -= ETHER_HDR_SIZE;
407         }
408
409 #ifdef ET_DEBUG
410         printf("Receive from protocol 0x%x\n", x);
411 #endif
412
413         switch (x) {
414
415         case PROT_ARP:
416                 /*
417                  * We have to deal with two types of ARP packets:
418                  * - REQUEST packets will be answered by sending  our
419                  *   IP address - if we know it.
420                  * - REPLY packates are expected only after we asked
421                  *   for the TFTP server's or the gateway's ethernet
422                  *   address; so if we receive such a packet, we set
423                  *   the server ethernet address
424                  */
425 #ifdef ET_DEBUG
426                 printf("Got ARP\n");
427 #endif
428                 arp = (ARP_t *)ip;
429                 if (len < ARP_HDR_SIZE) {
430                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
431                         return;
432                 }
433                 if (ntohs(arp->ar_hrd) != ARP_ETHER) {
434                         return;
435                 }
436                 if (ntohs(arp->ar_pro) != PROT_IP) {
437                         return;
438                 }
439                 if (arp->ar_hln != 6) {
440                         return;
441                 }
442                 if (arp->ar_pln != 4) {
443                         return;
444                 }
445
446                 if (NetOurIP == 0) {
447                         return;
448                 }
449
450                 if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
451                         return;
452                 }
453
454                 switch (ntohs(arp->ar_op)) {
455                 case ARPOP_REQUEST:             /* reply with our IP address    */
456 #ifdef ET_DEBUG
457                         printf("Got ARP REQUEST, return our IP\n");
458 #endif
459                         NetSetEther((uchar *)et, et->et_src, PROT_ARP);
460                         arp->ar_op = htons(ARPOP_REPLY);
461                         memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);
462                         NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
463                         memcpy   (&arp->ar_data[ 0], NetOurEther, 6);
464                         NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
465                         NetSendPacket((uchar *)et,((uchar *)arp-pkt)+ARP_HDR_SIZE);
466                         return;
467                 case ARPOP_REPLY:               /* set TFTP server eth addr     */
468 #ifdef ET_DEBUG
469                         printf("Got ARP REPLY, set server/gtwy eth addr\n");
470 #endif
471                         memcpy (NetServerEther, &arp->ar_data[0], 6);
472                         (*packetHandler)(0,0,0,0);      /* start TFTP */
473                         return;
474                 default:
475 #ifdef ET_DEBUG
476                         printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
477 #endif
478                         return;
479                 }
480
481         case PROT_RARP:
482 #ifdef ET_DEBUG
483                 printf("Got RARP\n");
484 #endif
485                 arp = (ARP_t *)ip;
486                 if (len < ARP_HDR_SIZE) {
487                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
488                         return;
489                 }
490
491                 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
492                         (ntohs(arp->ar_hrd) != ARP_ETHER)   ||
493                         (ntohs(arp->ar_pro) != PROT_IP)     ||
494                         (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
495
496                         printf("invalid RARP header\n");
497                 } else {
498                         NetCopyIP(&NetOurIP,    &arp->ar_data[16]);
499                         NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
500                         memcpy (NetServerEther, &arp->ar_data[ 0], 6);
501
502                         (*packetHandler)(0,0,0,0);
503                 }
504                 break;
505
506         case PROT_IP:
507 #ifdef ET_DEBUG
508                 printf("Got IP\n");
509 #endif
510                 if (len < IP_HDR_SIZE) {
511                         debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
512                         return;
513                 }
514                 if (len < ntohs(ip->ip_len)) {
515                         printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
516                         return;
517                 }
518                 len = ntohs(ip->ip_len);
519 #ifdef ET_DEBUG
520                 printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
521 #endif
522                 if ((ip->ip_hl_v & 0xf0) != 0x40) {
523                         return;
524                 }
525                 if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
526                         return;
527                 }
528                 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
529                         printf("checksum bad\n");
530                         return;
531                 }
532                 tmp = NetReadIP(&ip->ip_dst);
533                 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
534                         return;
535                 }
536                 /*
537                  * watch for ICMP host redirects
538                  *
539                  * There is no real handler code (yet). We just watch
540                  * for ICMP host redirect messages. In case anybody
541                  * sees these messages: please contact me
542                  * (wd@denx.de), or - even better - send me the
543                  * necessary fixes :-)
544                  *
545                  * Note: in all cases where I have seen this so far
546                  * it was a problem with the router configuration,
547                  * for instance when a router was configured in the
548                  * BOOTP reply, but the TFTP server was on the same
549                  * subnet. So this is probably a warning that your
550                  * configuration might be wrong. But I'm not really
551                  * sure if there aren't any other situations.
552                  */
553                 if (ip->ip_p == IPPROTO_ICMP) {
554                         ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
555
556                         if (icmph->type != ICMP_REDIRECT)
557                                 return;
558                         if (icmph->code != ICMP_REDIR_HOST)
559                                 return;
560                         puts (" ICMP Host Redirect to ");
561                         print_IPaddr(icmph->un.gateway);
562                         putc(' ');
563                 } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
564                         return;
565                 }
566
567                 /*
568                  *      IP header OK.  Pass the packet to the current handler.
569                  */
570                 (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
571                                                 ntohs(ip->udp_dst),
572                                                 ntohs(ip->udp_src),
573                                                 ntohs(ip->udp_len) - 8);
574
575                 break;
576         }
577 }
578
579
580 /**********************************************************************/
581
582 static int net_check_prereq (proto_t protocol)
583 {
584         switch (protocol) {
585         case ARP:       /* nothing to do */
586                         break;
587
588         case TFTP:
589                         if (NetServerIP == 0) {
590                                 puts ("*** ERROR: `serverip' not set\n");
591                                 return (1);
592                         }
593
594                         if (NetOurIP == 0) {
595                                 puts ("*** ERROR: `ipaddr' not set\n");
596                                 return (1);
597                         }
598                         /* Fall through */
599
600         case DHCP:
601         case RARP:
602         case BOOTP:
603                         if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
604 #ifdef CONFIG_NET_MULTI
605                             extern int eth_get_dev_index (void);
606                             int num = eth_get_dev_index();
607
608                             switch (num) {
609                             case -1:
610                                 puts ("*** ERROR: No ethernet found.\n");
611                                 return (1);
612                             case 0:
613                                 puts ("*** ERROR: `ethaddr' not set\n");
614                                 break;
615                             default:
616                                 printf ("*** ERROR: `eth%daddr' not set\n",
617                                         num);
618                                 break;
619                             }
620
621                             NetStartAgain ();
622                             return (2);
623 #else
624                             puts ("*** ERROR: `ethaddr' not set\n");
625                             return (1);
626 #endif
627                         }
628                         /* Fall through */
629         }
630         return (0);     /* OK */
631 }
632 /**********************************************************************/
633
634 int
635 NetCksumOk(uchar * ptr, int len)
636 {
637         return !((NetCksum(ptr, len) + 1) & 0xfffe);
638 }
639
640
641 unsigned
642 NetCksum(uchar * ptr, int len)
643 {
644         ulong   xsum;
645
646         xsum = 0;
647         while (len-- > 0)
648                 xsum += *((ushort *)ptr)++;
649         xsum = (xsum & 0xffff) + (xsum >> 16);
650         xsum = (xsum & 0xffff) + (xsum >> 16);
651         return (xsum & 0xffff);
652 }
653
654
655 void
656 NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
657 {
658         Ethernet_t *et = (Ethernet_t *)xet;
659
660         memcpy (et->et_dest, addr, 6);
661         memcpy (et->et_src, NetOurEther, 6);
662         et->et_protlen = htons(prot);
663 }
664
665
666 void
667 NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
668 {
669         volatile IP_t *ip = (IP_t *)xip;
670
671         /*
672          *      If the data is an odd number of bytes, zero the
673          *      byte after the last byte so that the checksum
674          *      will work.
675          */
676         if (len & 1)
677                 xip[IP_HDR_SIZE + len] = 0;
678
679         /*
680          *      Construct an IP and UDP header.
681                         (need to set no fragment bit - XXX)
682          */
683         ip->ip_hl_v  = 0x45;            /* IP_HDR_SIZE / 4 (not including UDP) */
684         ip->ip_tos   = 0;
685         ip->ip_len   = htons(IP_HDR_SIZE + len);
686         ip->ip_id    = htons(NetIPID++);
687         ip->ip_off   = htons(0x4000);   /* No fragmentation */
688         ip->ip_ttl   = 255;
689         ip->ip_p     = 17;              /* UDP */
690         ip->ip_sum   = 0;
691         NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
692         NetCopyIP((void*)&ip->ip_dst, &dest);      /* - "" - */
693         ip->udp_src  = htons(sport);
694         ip->udp_dst  = htons(dport);
695         ip->udp_len  = htons(8 + len);
696         ip->udp_xsum = 0;
697         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
698 }
699
700 void copy_filename (uchar *dst, uchar *src, int size)
701 {
702         if (*src && (*src == '"')) {
703                 ++src;
704                 --size;
705         }
706
707         while ((--size > 0) && *src && (*src != '"')) {
708                 *dst++ = *src++;
709         }
710         *dst = '\0';
711 }
712
713 #endif /* CFG_CMD_NET */
714
715 void ip_to_string (IPaddr_t x, char *s)
716 {
717     x = ntohl(x);
718     sprintf (s,"%d.%d.%d.%d",
719         (int)((x >> 24) & 0xff),
720         (int)((x >> 16) & 0xff),
721         (int)((x >>  8) & 0xff),
722         (int)((x >>  0) & 0xff)
723     );
724 }
725
726 void print_IPaddr (IPaddr_t x)
727 {
728     char tmp[16];
729
730     ip_to_string(x, tmp);
731
732     puts(tmp);
733 }
734
735 IPaddr_t getenv_IPaddr (char *var)
736 {
737         IPaddr_t addr;
738         char *s, *e;
739         int i;
740
741         s = getenv (var);
742
743         for (addr=0, i=0; i<4; ++i) {
744                 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
745                 addr <<= 8;
746                 addr |= (val & 0xFF);
747                 if (s) {
748                         s = (*e) ? e+1 : e;
749                 }
750         }
751
752         return (htonl(addr));
753 }