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