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