xref: /rk3399_rockchip-uboot/net/net.c (revision f575ae1f7d3940efbfc43e4236adb4a8ec1db632)
1 /*
2  *	Copied from Linux Monitor (LiMon) - Networking.
3  *
4  *	Copyright 1994 - 2000 Neil Russell.
5  *	(See License)
6  *	Copyright 2000 Roland Borde
7  *	Copyright 2000 Paolo Scaffardi
8  *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10 
11 /*
12  * General Desription:
13  *
14  * The user interface supports commands for BOOTP, RARP, and TFTP.
15  * Also, we support ARP internally. Depending on available data,
16  * these interact as follows:
17  *
18  * BOOTP:
19  *
20  *	Prerequisites:	- own ethernet address
21  *	We want:	- own IP address
22  *			- TFTP server IP address
23  *			- name of bootfile
24  *	Next step:	ARP
25  *
26  * RARP:
27  *
28  *	Prerequisites:	- own ethernet address
29  *	We want:	- own IP address
30  *			- TFTP server IP address
31  *	Next step:	ARP
32  *
33  * ARP:
34  *
35  *	Prerequisites:	- own ethernet address
36  *			- own IP address
37  *			- TFTP server IP address
38  *	We want:	- TFTP server ethernet address
39  *	Next step:	TFTP
40  *
41  * DHCP:
42  *
43  *     Prerequisites:	- own ethernet address
44  *     We want:		- IP, Netmask, ServerIP, Gateway IP
45  *			- bootfilename, lease time
46  *     Next step:	- TFTP
47  *
48  * TFTP:
49  *
50  *	Prerequisites:	- own ethernet address
51  *			- own IP address
52  *			- TFTP server IP address
53  *			- TFTP server ethernet address
54  *			- name of bootfile (if unknown, we use a default name
55  *			  derived from our own IP address)
56  *	We want:	- load the boot file
57  *	Next step:	none
58  *
59  * NFS:
60  *
61  *	Prerequisites:	- own ethernet address
62  *			- own IP address
63  *			- name of bootfile (if unknown, we use a default name
64  *			  derived from our own IP address)
65  *	We want:	- load the boot file
66  *	Next step:	none
67  *
68  * SNTP:
69  *
70  *	Prerequisites:	- own ethernet address
71  *			- own IP address
72  *	We want:	- network time
73  *	Next step:	none
74  */
75 
76 
77 #include <common.h>
78 #include <watchdog.h>
79 #include <command.h>
80 #include <linux/compiler.h>
81 #include <net.h>
82 #include "bootp.h"
83 #include "tftp.h"
84 #ifdef CONFIG_CMD_RARP
85 #include "rarp.h"
86 #endif
87 #include "nfs.h"
88 #ifdef CONFIG_STATUS_LED
89 #include <status_led.h>
90 #include <miiphy.h>
91 #endif
92 #if defined(CONFIG_CMD_SNTP)
93 #include "sntp.h"
94 #endif
95 #include "cdp.h"
96 #if defined(CONFIG_CMD_DNS)
97 #include "dns.h"
98 #endif
99 
100 DECLARE_GLOBAL_DATA_PTR;
101 
102 #ifndef	CONFIG_ARP_TIMEOUT
103 /* Milliseconds before trying ARP again */
104 # define ARP_TIMEOUT		5000UL
105 #else
106 # define ARP_TIMEOUT		CONFIG_ARP_TIMEOUT
107 #endif
108 
109 
110 #ifndef	CONFIG_NET_RETRY_COUNT
111 # define ARP_TIMEOUT_COUNT	5	/* # of timeouts before giving up  */
112 #else
113 # define ARP_TIMEOUT_COUNT	CONFIG_NET_RETRY_COUNT
114 #endif
115 
116 /** BOOTP EXTENTIONS **/
117 
118 /* Our subnet mask (0=unknown) */
119 IPaddr_t	NetOurSubnetMask;
120 /* Our gateways IP address */
121 IPaddr_t	NetOurGatewayIP;
122 /* Our DNS IP address */
123 IPaddr_t	NetOurDNSIP;
124 #if defined(CONFIG_BOOTP_DNS2)
125 /* Our 2nd DNS IP address */
126 IPaddr_t	NetOurDNS2IP;
127 #endif
128 /* Our NIS domain */
129 char		NetOurNISDomain[32] = {0,};
130 /* Our hostname */
131 char		NetOurHostName[32] = {0,};
132 /* Our bootpath */
133 char		NetOurRootPath[64] = {0,};
134 /* Our bootfile size in blocks */
135 ushort		NetBootFileSize;
136 
137 #ifdef CONFIG_MCAST_TFTP	/* Multicast TFTP */
138 IPaddr_t Mcast_addr;
139 #endif
140 
141 /** END OF BOOTP EXTENTIONS **/
142 
143 /* The actual transferred size of the bootfile (in bytes) */
144 ulong		NetBootFileXferSize;
145 /* Our ethernet address */
146 uchar		NetOurEther[6];
147 /* Boot server enet address */
148 uchar		NetServerEther[6];
149 /* Our IP addr (0 = unknown) */
150 IPaddr_t	NetOurIP;
151 /* Server IP addr (0 = unknown) */
152 IPaddr_t	NetServerIP;
153 /* Current receive packet */
154 uchar *NetRxPacket;
155 /* Current rx packet length */
156 int		NetRxPacketLen;
157 /* IP packet ID */
158 unsigned	NetIPID;
159 /* Ethernet bcast address */
160 uchar		NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
161 uchar		NetEtherNullAddr[6];
162 #ifdef CONFIG_API
163 void		(*push_packet)(void *, int len) = 0;
164 #endif
165 /* Network loop state */
166 int		NetState;
167 /* Tried all network devices */
168 int		NetRestartWrap;
169 /* Network loop restarted */
170 static int	NetRestarted;
171 /* At least one device configured */
172 static int	NetDevExists;
173 
174 /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
175 /* default is without VLAN */
176 ushort		NetOurVLAN = 0xFFFF;
177 /* ditto */
178 ushort		NetOurNativeVLAN = 0xFFFF;
179 
180 /* Boot File name */
181 char		BootFile[128];
182 
183 #if defined(CONFIG_CMD_PING)
184 /* the ip address to ping */
185 IPaddr_t	NetPingIP;
186 
187 static void PingStart(void);
188 #endif
189 
190 #if defined(CONFIG_CMD_SNTP)
191 /* NTP server IP address */
192 IPaddr_t	NetNtpServerIP;
193 /* offset time from UTC */
194 int		NetTimeOffset;
195 #endif
196 
197 uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
198 
199 /* Receive packet */
200 uchar *NetRxPackets[PKTBUFSRX];
201 
202 /* Current RX packet handler */
203 static rxhand_f *packetHandler;
204 #ifdef CONFIG_CMD_TFTPPUT
205 static rxhand_icmp_f *packet_icmp_handler;	/* Current ICMP rx handler */
206 #endif
207 /* Current timeout handler */
208 static thand_f *timeHandler;
209 /* Time base value */
210 static ulong	timeStart;
211 /* Current timeout value */
212 static ulong	timeDelta;
213 /* THE transmit packet */
214 uchar *NetTxPacket;
215 
216 static int net_check_prereq(enum proto_t protocol);
217 
218 static int NetTryCount;
219 
220 /**********************************************************************/
221 
222 IPaddr_t	NetArpWaitPacketIP;
223 IPaddr_t	NetArpWaitReplyIP;
224 /* MAC address of waiting packet's destination */
225 uchar	       *NetArpWaitPacketMAC;
226 /* THE transmit packet */
227 uchar	       *NetArpWaitTxPacket;
228 int		NetArpWaitTxPacketSize;
229 uchar		NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
230 ulong		NetArpWaitTimerStart;
231 int		NetArpWaitTry;
232 
233 void ArpRequest(void)
234 {
235 	uchar *pkt;
236 	ARP_t *arp;
237 
238 	debug("ARP broadcast %d\n", NetArpWaitTry);
239 
240 	pkt = NetTxPacket;
241 
242 	pkt += NetSetEther(pkt, NetBcastAddr, PROT_ARP);
243 
244 	arp = (ARP_t *) pkt;
245 
246 	arp->ar_hrd = htons(ARP_ETHER);
247 	arp->ar_pro = htons(PROT_IP);
248 	arp->ar_hln = 6;
249 	arp->ar_pln = 4;
250 	arp->ar_op = htons(ARPOP_REQUEST);
251 
252 	/* source ET addr */
253 	memcpy(&arp->ar_data[0], NetOurEther, 6);
254 	/* source IP addr */
255 	NetWriteIP((uchar *) &arp->ar_data[6], NetOurIP);
256 	/* dest ET addr = 0 */
257 	memset(&arp->ar_data[10], '\0', 6);
258 	if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
259 	    (NetOurIP & NetOurSubnetMask)) {
260 		if (NetOurGatewayIP == 0) {
261 			puts("## Warning: gatewayip needed but not set\n");
262 			NetArpWaitReplyIP = NetArpWaitPacketIP;
263 		} else {
264 			NetArpWaitReplyIP = NetOurGatewayIP;
265 		}
266 	} else {
267 		NetArpWaitReplyIP = NetArpWaitPacketIP;
268 	}
269 
270 	NetWriteIP((uchar *) &arp->ar_data[16], NetArpWaitReplyIP);
271 	(void) eth_send(NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
272 }
273 
274 void ArpTimeoutCheck(void)
275 {
276 	ulong t;
277 
278 	if (!NetArpWaitPacketIP)
279 		return;
280 
281 	t = get_timer(0);
282 
283 	/* check for arp timeout */
284 	if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
285 		NetArpWaitTry++;
286 
287 		if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
288 			puts("\nARP Retry count exceeded; starting again\n");
289 			NetArpWaitTry = 0;
290 			NetStartAgain();
291 		} else {
292 			NetArpWaitTimerStart = t;
293 			ArpRequest();
294 		}
295 	}
296 }
297 
298 /*
299  * Check if autoload is enabled. If so, use either NFS or TFTP to download
300  * the boot file.
301  */
302 void net_auto_load(void)
303 {
304 	const char *s = getenv("autoload");
305 
306 	if (s != NULL) {
307 		if (*s == 'n') {
308 			/*
309 			 * Just use BOOTP/RARP to configure system;
310 			 * Do not use TFTP to load the bootfile.
311 			 */
312 			NetState = NETLOOP_SUCCESS;
313 			return;
314 		}
315 #if defined(CONFIG_CMD_NFS)
316 		if (strcmp(s, "NFS") == 0) {
317 			/*
318 			 * Use NFS to load the bootfile.
319 			 */
320 			NfsStart();
321 			return;
322 		}
323 #endif
324 	}
325 	TftpStart(TFTPGET);
326 }
327 
328 static void NetInitLoop(enum proto_t protocol)
329 {
330 	static int env_changed_id;
331 	int env_id = get_env_id();
332 
333 	/* update only when the environment has changed */
334 	if (env_changed_id != env_id) {
335 		NetOurIP = getenv_IPaddr("ipaddr");
336 		NetOurGatewayIP = getenv_IPaddr("gatewayip");
337 		NetOurSubnetMask = getenv_IPaddr("netmask");
338 		NetServerIP = getenv_IPaddr("serverip");
339 		NetOurNativeVLAN = getenv_VLAN("nvlan");
340 		NetOurVLAN = getenv_VLAN("vlan");
341 #if defined(CONFIG_CMD_DNS)
342 		NetOurDNSIP = getenv_IPaddr("dnsip");
343 #endif
344 		env_changed_id = env_id;
345 	}
346 
347 	return;
348 }
349 
350 /**********************************************************************/
351 /*
352  *	Main network processing loop.
353  */
354 
355 int NetLoop(enum proto_t protocol)
356 {
357 	bd_t *bd = gd->bd;
358 	int ret = -1;
359 
360 	NetRestarted = 0;
361 	NetDevExists = 0;
362 
363 	/* XXX problem with bss workaround */
364 	NetArpWaitPacketMAC = NULL;
365 	NetArpWaitTxPacket = NULL;
366 	NetArpWaitPacketIP = 0;
367 	NetArpWaitReplyIP = 0;
368 	NetArpWaitTxPacket = NULL;
369 	NetTxPacket = NULL;
370 	NetTryCount = 1;
371 
372 	if (!NetTxPacket) {
373 		int	i;
374 		/*
375 		 *	Setup packet buffers, aligned correctly.
376 		 */
377 		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
378 		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
379 		for (i = 0; i < PKTBUFSRX; i++)
380 			NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
381 	}
382 
383 	if (!NetArpWaitTxPacket) {
384 		NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
385 		NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
386 		NetArpWaitTxPacketSize = 0;
387 	}
388 
389 	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
390 	eth_halt();
391 	eth_set_current();
392 	if (eth_init(bd) < 0) {
393 		eth_halt();
394 		return -1;
395 	}
396 
397 restart:
398 	memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
399 
400 	NetState = NETLOOP_CONTINUE;
401 
402 	/*
403 	 *	Start the ball rolling with the given start function.  From
404 	 *	here on, this code is a state machine driven by received
405 	 *	packets and timer events.
406 	 */
407 	NetInitLoop(protocol);
408 
409 	switch (net_check_prereq(protocol)) {
410 	case 1:
411 		/* network not configured */
412 		eth_halt();
413 		return -1;
414 
415 	case 2:
416 		/* network device not configured */
417 		break;
418 
419 	case 0:
420 		NetDevExists = 1;
421 		NetBootFileXferSize = 0;
422 		switch (protocol) {
423 		case TFTPGET:
424 #ifdef CONFIG_CMD_TFTPPUT
425 		case TFTPPUT:
426 #endif
427 			/* always use ARP to get server ethernet address */
428 			TftpStart(protocol);
429 			break;
430 #ifdef CONFIG_CMD_TFTPSRV
431 		case TFTPSRV:
432 			TftpStartServer();
433 			break;
434 #endif
435 #if defined(CONFIG_CMD_DHCP)
436 		case DHCP:
437 			BootpTry = 0;
438 			NetOurIP = 0;
439 			DhcpRequest();		/* Basically same as BOOTP */
440 			break;
441 #endif
442 
443 		case BOOTP:
444 			BootpTry = 0;
445 			NetOurIP = 0;
446 			BootpRequest();
447 			break;
448 
449 #if defined(CONFIG_CMD_RARP)
450 		case RARP:
451 			RarpTry = 0;
452 			NetOurIP = 0;
453 			RarpRequest();
454 			break;
455 #endif
456 #if defined(CONFIG_CMD_PING)
457 		case PING:
458 			PingStart();
459 			break;
460 #endif
461 #if defined(CONFIG_CMD_NFS)
462 		case NFS:
463 			NfsStart();
464 			break;
465 #endif
466 #if defined(CONFIG_CMD_CDP)
467 		case CDP:
468 			CDPStart();
469 			break;
470 #endif
471 #ifdef CONFIG_NETCONSOLE
472 		case NETCONS:
473 			NcStart();
474 			break;
475 #endif
476 #if defined(CONFIG_CMD_SNTP)
477 		case SNTP:
478 			SntpStart();
479 			break;
480 #endif
481 #if defined(CONFIG_CMD_DNS)
482 		case DNS:
483 			DnsStart();
484 			break;
485 #endif
486 		default:
487 			break;
488 		}
489 
490 		break;
491 	}
492 
493 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
494 #if	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)	&& \
495 	defined(CONFIG_STATUS_LED)			&& \
496 	defined(STATUS_LED_RED)
497 	/*
498 	 * Echo the inverted link state to the fault LED.
499 	 */
500 	if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
501 		status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
502 	else
503 		status_led_set(STATUS_LED_RED, STATUS_LED_ON);
504 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
505 #endif /* CONFIG_MII, ... */
506 
507 	/*
508 	 *	Main packet reception loop.  Loop receiving packets until
509 	 *	someone sets `NetState' to a state that terminates.
510 	 */
511 	for (;;) {
512 		WATCHDOG_RESET();
513 #ifdef CONFIG_SHOW_ACTIVITY
514 		show_activity(1);
515 #endif
516 		/*
517 		 *	Check the ethernet for a new packet.  The ethernet
518 		 *	receive routine will process it.
519 		 */
520 		eth_rx();
521 
522 		/*
523 		 *	Abort if ctrl-c was pressed.
524 		 */
525 		if (ctrlc()) {
526 			eth_halt();
527 			puts("\nAbort\n");
528 			goto done;
529 		}
530 
531 		ArpTimeoutCheck();
532 
533 		/*
534 		 *	Check for a timeout, and run the timeout handler
535 		 *	if we have one.
536 		 */
537 		if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
538 			thand_f *x;
539 
540 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
541 #if	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)	&& \
542 	defined(CONFIG_STATUS_LED)			&& \
543 	defined(STATUS_LED_RED)
544 			/*
545 			 * Echo the inverted link state to the fault LED.
546 			 */
547 			if (miiphy_link(eth_get_dev()->name,
548 				       CONFIG_SYS_FAULT_MII_ADDR)) {
549 				status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
550 			} else {
551 				status_led_set(STATUS_LED_RED, STATUS_LED_ON);
552 			}
553 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
554 #endif /* CONFIG_MII, ... */
555 			x = timeHandler;
556 			timeHandler = (thand_f *)0;
557 			(*x)();
558 		}
559 
560 
561 		switch (NetState) {
562 
563 		case NETLOOP_RESTART:
564 			NetRestarted = 1;
565 			goto restart;
566 
567 		case NETLOOP_SUCCESS:
568 			if (NetBootFileXferSize > 0) {
569 				char buf[20];
570 				printf("Bytes transferred = %ld (%lx hex)\n",
571 					NetBootFileXferSize,
572 					NetBootFileXferSize);
573 				sprintf(buf, "%lX", NetBootFileXferSize);
574 				setenv("filesize", buf);
575 
576 				sprintf(buf, "%lX", (unsigned long)load_addr);
577 				setenv("fileaddr", buf);
578 			}
579 			eth_halt();
580 			ret = NetBootFileXferSize;
581 			goto done;
582 
583 		case NETLOOP_FAIL:
584 			goto done;
585 		}
586 	}
587 
588 done:
589 #ifdef CONFIG_CMD_TFTPPUT
590 	/* Clear out the handlers */
591 	NetSetHandler(NULL);
592 	net_set_icmp_handler(NULL);
593 #endif
594 	return ret;
595 }
596 
597 /**********************************************************************/
598 
599 static void
600 startAgainTimeout(void)
601 {
602 	NetState = NETLOOP_RESTART;
603 }
604 
605 static void
606 startAgainHandler(uchar *pkt, unsigned dest, IPaddr_t sip,
607 		  unsigned src, unsigned len)
608 {
609 	/* Totally ignore the packet */
610 }
611 
612 void NetStartAgain(void)
613 {
614 	char *nretry;
615 	int retry_forever = 0;
616 	unsigned long retrycnt = 0;
617 
618 	nretry = getenv("netretry");
619 	if (nretry) {
620 		if (!strcmp(nretry, "yes"))
621 			retry_forever = 1;
622 		else if (!strcmp(nretry, "no"))
623 			retrycnt = 0;
624 		else if (!strcmp(nretry, "once"))
625 			retrycnt = 1;
626 		else
627 			retrycnt = simple_strtoul(nretry, NULL, 0);
628 	} else
629 		retry_forever = 1;
630 
631 	if ((!retry_forever) && (NetTryCount >= retrycnt)) {
632 		eth_halt();
633 		NetState = NETLOOP_FAIL;
634 		return;
635 	}
636 
637 	NetTryCount++;
638 
639 	eth_halt();
640 #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
641 	eth_try_another(!NetRestarted);
642 #endif
643 	eth_init(gd->bd);
644 	if (NetRestartWrap) {
645 		NetRestartWrap = 0;
646 		if (NetDevExists) {
647 			NetSetTimeout(10000UL, startAgainTimeout);
648 			NetSetHandler(startAgainHandler);
649 		} else {
650 			NetState = NETLOOP_FAIL;
651 		}
652 	} else {
653 		NetState = NETLOOP_RESTART;
654 	}
655 }
656 
657 /**********************************************************************/
658 /*
659  *	Miscelaneous bits.
660  */
661 
662 void
663 NetSetHandler(rxhand_f *f)
664 {
665 	packetHandler = f;
666 }
667 
668 #ifdef CONFIG_CMD_TFTPPUT
669 void net_set_icmp_handler(rxhand_icmp_f *f)
670 {
671 	packet_icmp_handler = f;
672 }
673 #endif
674 
675 void
676 NetSetTimeout(ulong iv, thand_f *f)
677 {
678 	if (iv == 0) {
679 		timeHandler = (thand_f *)0;
680 	} else {
681 		timeHandler = f;
682 		timeStart = get_timer(0);
683 		timeDelta = iv;
684 	}
685 }
686 
687 
688 void
689 NetSendPacket(uchar *pkt, int len)
690 {
691 	(void) eth_send(pkt, len);
692 }
693 
694 int
695 NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
696 {
697 	uchar *pkt;
698 
699 	/* convert to new style broadcast */
700 	if (dest == 0)
701 		dest = 0xFFFFFFFF;
702 
703 	/* if broadcast, make the ether address a broadcast and don't do ARP */
704 	if (dest == 0xFFFFFFFF)
705 		ether = NetBcastAddr;
706 
707 	/*
708 	 * if MAC address was not discovered yet, save the packet and do
709 	 * an ARP request
710 	 */
711 	if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
712 
713 		debug("sending ARP for %08x\n", dest);
714 
715 		NetArpWaitPacketIP = dest;
716 		NetArpWaitPacketMAC = ether;
717 
718 		pkt = NetArpWaitTxPacket;
719 		pkt += NetSetEther(pkt, NetArpWaitPacketMAC, PROT_IP);
720 
721 		NetSetIP(pkt, dest, dport, sport, len);
722 		memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket +
723 		       (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
724 
725 		/* size of the waiting packet */
726 		NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) +
727 			IP_HDR_SIZE + len;
728 
729 		/* and do the ARP request */
730 		NetArpWaitTry = 1;
731 		NetArpWaitTimerStart = get_timer(0);
732 		ArpRequest();
733 		return 1;	/* waiting */
734 	}
735 
736 	debug("sending UDP to %08x/%pM\n", dest, ether);
737 
738 	pkt = (uchar *)NetTxPacket;
739 	pkt += NetSetEther(pkt, ether, PROT_IP);
740 	NetSetIP(pkt, dest, dport, sport, len);
741 	(void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
742 
743 	return 0;	/* transmitted */
744 }
745 
746 #if defined(CONFIG_CMD_PING)
747 static ushort PingSeqNo;
748 
749 int PingSend(void)
750 {
751 	static uchar mac[6];
752 	IP_t *ip;
753 	ushort *s;
754 	uchar *pkt;
755 
756 	/* XXX always send arp request */
757 
758 	memcpy(mac, NetEtherNullAddr, 6);
759 
760 	debug("sending ARP for %08x\n", NetPingIP);
761 
762 	NetArpWaitPacketIP = NetPingIP;
763 	NetArpWaitPacketMAC = mac;
764 
765 	pkt = NetArpWaitTxPacket;
766 	pkt += NetSetEther(pkt, mac, PROT_IP);
767 
768 	ip = (IP_t *)pkt;
769 
770 	/*
771 	 * Construct an IP and ICMP header.
772 	 * (need to set no fragment bit - XXX)
773 	 */
774 	/* IP_HDR_SIZE / 4 (not including UDP) */
775 	ip->ip_hl_v  = 0x45;
776 	ip->ip_tos   = 0;
777 	ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
778 	ip->ip_id    = htons(NetIPID++);
779 	ip->ip_off   = htons(IP_FLAGS_DFRAG);	/* Don't fragment */
780 	ip->ip_ttl   = 255;
781 	ip->ip_p     = 0x01;		/* ICMP */
782 	ip->ip_sum   = 0;
783 	/* already in network byte order */
784 	NetCopyIP((void *)&ip->ip_src, &NetOurIP);
785 	/* - "" - */
786 	NetCopyIP((void *)&ip->ip_dst, &NetPingIP);
787 	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
788 
789 	s = &ip->udp_src;		/* XXX ICMP starts here */
790 	s[0] = htons(0x0800);		/* echo-request, code */
791 	s[1] = 0;			/* checksum */
792 	s[2] = 0;			/* identifier */
793 	s[3] = htons(PingSeqNo++);	/* sequence number */
794 	s[1] = ~NetCksum((uchar *)s, 8/2);
795 
796 	/* size of the waiting packet */
797 	NetArpWaitTxPacketSize =
798 		(pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
799 
800 	/* and do the ARP request */
801 	NetArpWaitTry = 1;
802 	NetArpWaitTimerStart = get_timer(0);
803 	ArpRequest();
804 	return 1;	/* waiting */
805 }
806 
807 static void
808 PingTimeout(void)
809 {
810 	eth_halt();
811 	NetState = NETLOOP_FAIL;	/* we did not get the reply */
812 }
813 
814 static void
815 PingHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
816 	    unsigned len)
817 {
818 	if (sip != NetPingIP)
819 		return;
820 
821 	NetState = NETLOOP_SUCCESS;
822 }
823 
824 static void PingStart(void)
825 {
826 	printf("Using %s device\n", eth_get_name());
827 	NetSetTimeout(10000UL, PingTimeout);
828 	NetSetHandler(PingHandler);
829 
830 	PingSend();
831 }
832 #endif
833 
834 #ifdef CONFIG_IP_DEFRAG
835 /*
836  * This function collects fragments in a single packet, according
837  * to the algorithm in RFC815. It returns NULL or the pointer to
838  * a complete packet, in static storage
839  */
840 #ifndef CONFIG_NET_MAXDEFRAG
841 #define CONFIG_NET_MAXDEFRAG 16384
842 #endif
843 /*
844  * MAXDEFRAG, above, is chosen in the config file and  is real data
845  * so we need to add the NFS overhead, which is more than TFTP.
846  * To use sizeof in the internal unnamed structures, we need a real
847  * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately).
848  * The compiler doesn't complain nor allocates the actual structure
849  */
850 static struct rpc_t rpc_specimen;
851 #define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))
852 
853 #define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE_NO_UDP)
854 
855 /*
856  * this is the packet being assembled, either data or frag control.
857  * Fragments go by 8 bytes, so this union must be 8 bytes long
858  */
859 struct hole {
860 	/* first_byte is address of this structure */
861 	u16 last_byte;	/* last byte in this hole + 1 (begin of next hole) */
862 	u16 next_hole;	/* index of next (in 8-b blocks), 0 == none */
863 	u16 prev_hole;	/* index of prev, 0 == none */
864 	u16 unused;
865 };
866 
867 static IP_t *__NetDefragment(IP_t *ip, int *lenp)
868 {
869 	static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
870 	static u16 first_hole, total_len;
871 	struct hole *payload, *thisfrag, *h, *newh;
872 	IP_t *localip = (IP_t *)pkt_buff;
873 	uchar *indata = (uchar *)ip;
874 	int offset8, start, len, done = 0;
875 	u16 ip_off = ntohs(ip->ip_off);
876 
877 	/* payload starts after IP header, this fragment is in there */
878 	payload = (struct hole *)(pkt_buff + IP_HDR_SIZE_NO_UDP);
879 	offset8 =  (ip_off & IP_OFFS);
880 	thisfrag = payload + offset8;
881 	start = offset8 * 8;
882 	len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
883 
884 	if (start + len > IP_MAXUDP) /* fragment extends too far */
885 		return NULL;
886 
887 	if (!total_len || localip->ip_id != ip->ip_id) {
888 		/* new (or different) packet, reset structs */
889 		total_len = 0xffff;
890 		payload[0].last_byte = ~0;
891 		payload[0].next_hole = 0;
892 		payload[0].prev_hole = 0;
893 		first_hole = 0;
894 		/* any IP header will work, copy the first we received */
895 		memcpy(localip, ip, IP_HDR_SIZE_NO_UDP);
896 	}
897 
898 	/*
899 	 * What follows is the reassembly algorithm. We use the payload
900 	 * array as a linked list of hole descriptors, as each hole starts
901 	 * at a multiple of 8 bytes. However, last byte can be whatever value,
902 	 * so it is represented as byte count, not as 8-byte blocks.
903 	 */
904 
905 	h = payload + first_hole;
906 	while (h->last_byte < start) {
907 		if (!h->next_hole) {
908 			/* no hole that far away */
909 			return NULL;
910 		}
911 		h = payload + h->next_hole;
912 	}
913 
914 	/* last fragment may be 1..7 bytes, the "+7" forces acceptance */
915 	if (offset8 + ((len + 7) / 8) <= h - payload) {
916 		/* no overlap with holes (dup fragment?) */
917 		return NULL;
918 	}
919 
920 	if (!(ip_off & IP_FLAGS_MFRAG)) {
921 		/* no more fragmentss: truncate this (last) hole */
922 		total_len = start + len;
923 		h->last_byte = start + len;
924 	}
925 
926 	/*
927 	 * There is some overlap: fix the hole list. This code doesn't
928 	 * deal with a fragment that overlaps with two different holes
929 	 * (thus being a superset of a previously-received fragment).
930 	 */
931 
932 	if ((h >= thisfrag) && (h->last_byte <= start + len)) {
933 		/* complete overlap with hole: remove hole */
934 		if (!h->prev_hole && !h->next_hole) {
935 			/* last remaining hole */
936 			done = 1;
937 		} else if (!h->prev_hole) {
938 			/* first hole */
939 			first_hole = h->next_hole;
940 			payload[h->next_hole].prev_hole = 0;
941 		} else if (!h->next_hole) {
942 			/* last hole */
943 			payload[h->prev_hole].next_hole = 0;
944 		} else {
945 			/* in the middle of the list */
946 			payload[h->next_hole].prev_hole = h->prev_hole;
947 			payload[h->prev_hole].next_hole = h->next_hole;
948 		}
949 
950 	} else if (h->last_byte <= start + len) {
951 		/* overlaps with final part of the hole: shorten this hole */
952 		h->last_byte = start;
953 
954 	} else if (h >= thisfrag) {
955 		/* overlaps with initial part of the hole: move this hole */
956 		newh = thisfrag + (len / 8);
957 		*newh = *h;
958 		h = newh;
959 		if (h->next_hole)
960 			payload[h->next_hole].prev_hole = (h - payload);
961 		if (h->prev_hole)
962 			payload[h->prev_hole].next_hole = (h - payload);
963 		else
964 			first_hole = (h - payload);
965 
966 	} else {
967 		/* fragment sits in the middle: split the hole */
968 		newh = thisfrag + (len / 8);
969 		*newh = *h;
970 		h->last_byte = start;
971 		h->next_hole = (newh - payload);
972 		newh->prev_hole = (h - payload);
973 		if (newh->next_hole)
974 			payload[newh->next_hole].prev_hole = (newh - payload);
975 	}
976 
977 	/* finally copy this fragment and possibly return whole packet */
978 	memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE_NO_UDP, len);
979 	if (!done)
980 		return NULL;
981 
982 	localip->ip_len = htons(total_len);
983 	*lenp = total_len + IP_HDR_SIZE_NO_UDP;
984 	return localip;
985 }
986 
987 static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
988 {
989 	u16 ip_off = ntohs(ip->ip_off);
990 	if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
991 		return ip; /* not a fragment */
992 	return __NetDefragment(ip, lenp);
993 }
994 
995 #else /* !CONFIG_IP_DEFRAG */
996 
997 static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
998 {
999 	u16 ip_off = ntohs(ip->ip_off);
1000 	if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
1001 		return ip; /* not a fragment */
1002 	return NULL;
1003 }
1004 #endif
1005 
1006 /**
1007  * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
1008  * drop others.
1009  *
1010  * @parma ip	IP packet containing the ICMP
1011  */
1012 static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
1013 {
1014 	ICMP_t *icmph = (ICMP_t *)&ip->udp_src;
1015 
1016 	switch (icmph->type) {
1017 	case ICMP_REDIRECT:
1018 		if (icmph->code != ICMP_REDIR_HOST)
1019 			return;
1020 		printf(" ICMP Host Redirect to %pI4 ",
1021 			&icmph->un.gateway);
1022 		break;
1023 #if defined(CONFIG_CMD_PING)
1024 	case ICMP_ECHO_REPLY:
1025 		/*
1026 			* IP header OK.  Pass the packet to the
1027 			* current handler.
1028 			*/
1029 		/*
1030 		 * XXX point to ip packet - should this use
1031 		 * packet_icmp_handler?
1032 		 */
1033 		(*packetHandler)((uchar *)ip, 0, src_ip, 0, 0);
1034 		break;
1035 	case ICMP_ECHO_REQUEST:
1036 		debug("Got ICMP ECHO REQUEST, return %d bytes\n",
1037 			ETHER_HDR_SIZE + len);
1038 
1039 		memcpy(&et->et_dest[0], &et->et_src[0], 6);
1040 		memcpy(&et->et_src[0], NetOurEther, 6);
1041 
1042 		ip->ip_sum = 0;
1043 		ip->ip_off = 0;
1044 		NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
1045 		NetCopyIP((void *)&ip->ip_src, &NetOurIP);
1046 		ip->ip_sum = ~NetCksum((uchar *)ip,
1047 					IP_HDR_SIZE_NO_UDP >> 1);
1048 
1049 		icmph->type = ICMP_ECHO_REPLY;
1050 		icmph->checksum = 0;
1051 		icmph->checksum = ~NetCksum((uchar *)icmph,
1052 			(len - IP_HDR_SIZE_NO_UDP) >> 1);
1053 		(void) eth_send((uchar *)et,
1054 				ETHER_HDR_SIZE + len);
1055 		break;
1056 #endif
1057 	default:
1058 #ifdef CONFIG_CMD_TFTPPUT
1059 		if (packet_icmp_handler)
1060 			packet_icmp_handler(icmph->type, icmph->code,
1061 				ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
1062 				icmph->un.data, ntohs(ip->udp_len));
1063 #endif
1064 		break;
1065 	}
1066 }
1067 
1068 void
1069 NetReceive(uchar *inpkt, int len)
1070 {
1071 	Ethernet_t *et;
1072 	IP_t	*ip;
1073 	ARP_t	*arp;
1074 	IPaddr_t tmp;
1075 	IPaddr_t src_ip;
1076 	int	x;
1077 	uchar *pkt;
1078 #if defined(CONFIG_CMD_CDP)
1079 	int iscdp;
1080 #endif
1081 	ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
1082 
1083 	debug("packet received\n");
1084 
1085 	NetRxPacket = inpkt;
1086 	NetRxPacketLen = len;
1087 	et = (Ethernet_t *)inpkt;
1088 
1089 	/* too small packet? */
1090 	if (len < ETHER_HDR_SIZE)
1091 		return;
1092 
1093 #ifdef CONFIG_API
1094 	if (push_packet) {
1095 		(*push_packet)(inpkt, len);
1096 		return;
1097 	}
1098 #endif
1099 
1100 #if defined(CONFIG_CMD_CDP)
1101 	/* keep track if packet is CDP */
1102 	iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
1103 #endif
1104 
1105 	myvlanid = ntohs(NetOurVLAN);
1106 	if (myvlanid == (ushort)-1)
1107 		myvlanid = VLAN_NONE;
1108 	mynvlanid = ntohs(NetOurNativeVLAN);
1109 	if (mynvlanid == (ushort)-1)
1110 		mynvlanid = VLAN_NONE;
1111 
1112 	x = ntohs(et->et_protlen);
1113 
1114 	debug("packet received\n");
1115 
1116 	if (x < 1514) {
1117 		/*
1118 		 *	Got a 802 packet.  Check the other protocol field.
1119 		 */
1120 		x = ntohs(et->et_prot);
1121 
1122 		ip = (IP_t *)(inpkt + E802_HDR_SIZE);
1123 		len -= E802_HDR_SIZE;
1124 
1125 	} else if (x != PROT_VLAN) {	/* normal packet */
1126 		ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
1127 		len -= ETHER_HDR_SIZE;
1128 
1129 	} else {			/* VLAN packet */
1130 		VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
1131 
1132 		debug("VLAN packet received\n");
1133 
1134 		/* too small packet? */
1135 		if (len < VLAN_ETHER_HDR_SIZE)
1136 			return;
1137 
1138 		/* if no VLAN active */
1139 		if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
1140 #if defined(CONFIG_CMD_CDP)
1141 				&& iscdp == 0
1142 #endif
1143 				)
1144 			return;
1145 
1146 		cti = ntohs(vet->vet_tag);
1147 		vlanid = cti & VLAN_IDMASK;
1148 		x = ntohs(vet->vet_type);
1149 
1150 		ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
1151 		len -= VLAN_ETHER_HDR_SIZE;
1152 	}
1153 
1154 	debug("Receive from protocol 0x%x\n", x);
1155 
1156 #if defined(CONFIG_CMD_CDP)
1157 	if (iscdp) {
1158 		CDPHandler((uchar *)ip, len);
1159 		return;
1160 	}
1161 #endif
1162 
1163 	if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1164 		if (vlanid == VLAN_NONE)
1165 			vlanid = (mynvlanid & VLAN_IDMASK);
1166 		/* not matched? */
1167 		if (vlanid != (myvlanid & VLAN_IDMASK))
1168 			return;
1169 	}
1170 
1171 	switch (x) {
1172 
1173 	case PROT_ARP:
1174 		/*
1175 		 * We have to deal with two types of ARP packets:
1176 		 * - REQUEST packets will be answered by sending  our
1177 		 *   IP address - if we know it.
1178 		 * - REPLY packates are expected only after we asked
1179 		 *   for the TFTP server's or the gateway's ethernet
1180 		 *   address; so if we receive such a packet, we set
1181 		 *   the server ethernet address
1182 		 */
1183 		debug("Got ARP\n");
1184 
1185 		arp = (ARP_t *)ip;
1186 		if (len < ARP_HDR_SIZE) {
1187 			printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1188 			return;
1189 		}
1190 		if (ntohs(arp->ar_hrd) != ARP_ETHER)
1191 			return;
1192 		if (ntohs(arp->ar_pro) != PROT_IP)
1193 			return;
1194 		if (arp->ar_hln != 6)
1195 			return;
1196 		if (arp->ar_pln != 4)
1197 			return;
1198 
1199 		if (NetOurIP == 0)
1200 			return;
1201 
1202 		if (NetReadIP(&arp->ar_data[16]) != NetOurIP)
1203 			return;
1204 
1205 		switch (ntohs(arp->ar_op)) {
1206 		case ARPOP_REQUEST:
1207 			/* reply with our IP address */
1208 			debug("Got ARP REQUEST, return our IP\n");
1209 			pkt = (uchar *)et;
1210 			pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
1211 			arp->ar_op = htons(ARPOP_REPLY);
1212 			memcpy(&arp->ar_data[10], &arp->ar_data[0], 6);
1213 			NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
1214 			memcpy(&arp->ar_data[0], NetOurEther, 6);
1215 			NetCopyIP(&arp->ar_data[6], &NetOurIP);
1216 			(void) eth_send((uchar *)et,
1217 					(pkt - (uchar *)et) + ARP_HDR_SIZE);
1218 			return;
1219 
1220 		case ARPOP_REPLY:		/* arp reply */
1221 			/* are we waiting for a reply */
1222 			if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
1223 				break;
1224 
1225 #ifdef CONFIG_KEEP_SERVERADDR
1226 			if (NetServerIP == NetArpWaitPacketIP) {
1227 				char buf[20];
1228 				sprintf(buf, "%pM", arp->ar_data);
1229 				setenv("serveraddr", buf);
1230 			}
1231 #endif
1232 
1233 			debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
1234 				arp->ar_data);
1235 
1236 			tmp = NetReadIP(&arp->ar_data[6]);
1237 
1238 			/* matched waiting packet's address */
1239 			if (tmp == NetArpWaitReplyIP) {
1240 				debug("Got it\n");
1241 
1242 				/* save address for later use */
1243 				memcpy(NetArpWaitPacketMAC,
1244 				       &arp->ar_data[0], 6);
1245 
1246 #ifdef CONFIG_NETCONSOLE
1247 				(*packetHandler)(0, 0, 0, 0, 0);
1248 #endif
1249 				/* modify header, and transmit it */
1250 				memcpy(((Ethernet_t *)NetArpWaitTxPacket)->
1251 					et_dest, NetArpWaitPacketMAC, 6);
1252 				(void) eth_send(NetArpWaitTxPacket,
1253 						NetArpWaitTxPacketSize);
1254 
1255 				/* no arp request pending now */
1256 				NetArpWaitPacketIP = 0;
1257 				NetArpWaitTxPacketSize = 0;
1258 				NetArpWaitPacketMAC = NULL;
1259 
1260 			}
1261 			return;
1262 		default:
1263 			debug("Unexpected ARP opcode 0x%x\n",
1264 			      ntohs(arp->ar_op));
1265 			return;
1266 		}
1267 		break;
1268 
1269 #ifdef CONFIG_CMD_RARP
1270 	case PROT_RARP:
1271 		debug("Got RARP\n");
1272 		arp = (ARP_t *)ip;
1273 		if (len < ARP_HDR_SIZE) {
1274 			printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1275 			return;
1276 		}
1277 
1278 		if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
1279 			(ntohs(arp->ar_hrd) != ARP_ETHER)   ||
1280 			(ntohs(arp->ar_pro) != PROT_IP)     ||
1281 			(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
1282 
1283 			puts("invalid RARP header\n");
1284 		} else {
1285 			NetCopyIP(&NetOurIP, &arp->ar_data[16]);
1286 			if (NetServerIP == 0)
1287 				NetCopyIP(&NetServerIP, &arp->ar_data[6]);
1288 			memcpy(NetServerEther, &arp->ar_data[0], 6);
1289 
1290 			(*packetHandler)(0, 0, 0, 0, 0);
1291 		}
1292 		break;
1293 #endif
1294 	case PROT_IP:
1295 		debug("Got IP\n");
1296 		/* Before we start poking the header, make sure it is there */
1297 		if (len < IP_HDR_SIZE) {
1298 			debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
1299 			return;
1300 		}
1301 		/* Check the packet length */
1302 		if (len < ntohs(ip->ip_len)) {
1303 			printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
1304 			return;
1305 		}
1306 		len = ntohs(ip->ip_len);
1307 		debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
1308 
1309 		/* Can't deal with anything except IPv4 */
1310 		if ((ip->ip_hl_v & 0xf0) != 0x40)
1311 			return;
1312 		/* Can't deal with IP options (headers != 20 bytes) */
1313 		if ((ip->ip_hl_v & 0x0f) > 0x05)
1314 			return;
1315 		/* Check the Checksum of the header */
1316 		if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
1317 			puts("checksum bad\n");
1318 			return;
1319 		}
1320 		/* If it is not for us, ignore it */
1321 		tmp = NetReadIP(&ip->ip_dst);
1322 		if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
1323 #ifdef CONFIG_MCAST_TFTP
1324 			if (Mcast_addr != tmp)
1325 #endif
1326 				return;
1327 		}
1328 		/* Read source IP address for later use */
1329 		src_ip = NetReadIP(&ip->ip_src);
1330 		/*
1331 		 * The function returns the unchanged packet if it's not
1332 		 * a fragment, and either the complete packet or NULL if
1333 		 * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
1334 		 */
1335 		ip = NetDefragment(ip, &len);
1336 		if (!ip)
1337 			return;
1338 		/*
1339 		 * watch for ICMP host redirects
1340 		 *
1341 		 * There is no real handler code (yet). We just watch
1342 		 * for ICMP host redirect messages. In case anybody
1343 		 * sees these messages: please contact me
1344 		 * (wd@denx.de), or - even better - send me the
1345 		 * necessary fixes :-)
1346 		 *
1347 		 * Note: in all cases where I have seen this so far
1348 		 * it was a problem with the router configuration,
1349 		 * for instance when a router was configured in the
1350 		 * BOOTP reply, but the TFTP server was on the same
1351 		 * subnet. So this is probably a warning that your
1352 		 * configuration might be wrong. But I'm not really
1353 		 * sure if there aren't any other situations.
1354 		 *
1355 		 * Simon Glass <sjg@chromium.org>: We get an ICMP when
1356 		 * we send a tftp packet to a dead connection, or when
1357 		 * there is no server at the other end.
1358 		 */
1359 		if (ip->ip_p == IPPROTO_ICMP) {
1360 			receive_icmp(ip, len, src_ip, et);
1361 			return;
1362 		} else if (ip->ip_p != IPPROTO_UDP) {	/* Only UDP packets */
1363 			return;
1364 		}
1365 
1366 #ifdef CONFIG_UDP_CHECKSUM
1367 		if (ip->udp_xsum != 0) {
1368 			ulong   xsum;
1369 			ushort *sumptr;
1370 			ushort  sumlen;
1371 
1372 			xsum  = ip->ip_p;
1373 			xsum += (ntohs(ip->udp_len));
1374 			xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
1375 			xsum += (ntohl(ip->ip_src) >>  0) & 0x0000ffff;
1376 			xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
1377 			xsum += (ntohl(ip->ip_dst) >>  0) & 0x0000ffff;
1378 
1379 			sumlen = ntohs(ip->udp_len);
1380 			sumptr = (ushort *) &(ip->udp_src);
1381 
1382 			while (sumlen > 1) {
1383 				ushort sumdata;
1384 
1385 				sumdata = *sumptr++;
1386 				xsum += ntohs(sumdata);
1387 				sumlen -= 2;
1388 			}
1389 			if (sumlen > 0) {
1390 				ushort sumdata;
1391 
1392 				sumdata = *(unsigned char *) sumptr;
1393 				sumdata = (sumdata << 8) & 0xff00;
1394 				xsum += sumdata;
1395 			}
1396 			while ((xsum >> 16) != 0) {
1397 				xsum = (xsum & 0x0000ffff) +
1398 				       ((xsum >> 16) & 0x0000ffff);
1399 			}
1400 			if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
1401 				printf(" UDP wrong checksum %08lx %08x\n",
1402 					xsum, ntohs(ip->udp_xsum));
1403 				return;
1404 			}
1405 		}
1406 #endif
1407 
1408 
1409 #ifdef CONFIG_NETCONSOLE
1410 		nc_input_packet((uchar *)ip + IP_HDR_SIZE,
1411 						ntohs(ip->udp_dst),
1412 						ntohs(ip->udp_src),
1413 						ntohs(ip->udp_len) - 8);
1414 #endif
1415 		/*
1416 		 *	IP header OK.  Pass the packet to the current handler.
1417 		 */
1418 		(*packetHandler)((uchar *)ip + IP_HDR_SIZE,
1419 						ntohs(ip->udp_dst),
1420 						src_ip,
1421 						ntohs(ip->udp_src),
1422 						ntohs(ip->udp_len) - 8);
1423 		break;
1424 	}
1425 }
1426 
1427 
1428 /**********************************************************************/
1429 
1430 static int net_check_prereq(enum proto_t protocol)
1431 {
1432 	switch (protocol) {
1433 		/* Fall through */
1434 #if defined(CONFIG_CMD_PING)
1435 	case PING:
1436 		if (NetPingIP == 0) {
1437 			puts("*** ERROR: ping address not given\n");
1438 			return 1;
1439 		}
1440 		goto common;
1441 #endif
1442 #if defined(CONFIG_CMD_SNTP)
1443 	case SNTP:
1444 		if (NetNtpServerIP == 0) {
1445 			puts("*** ERROR: NTP server address not given\n");
1446 			return 1;
1447 		}
1448 		goto common;
1449 #endif
1450 #if defined(CONFIG_CMD_DNS)
1451 	case DNS:
1452 		if (NetOurDNSIP == 0) {
1453 			puts("*** ERROR: DNS server address not given\n");
1454 			return 1;
1455 		}
1456 		goto common;
1457 #endif
1458 #if defined(CONFIG_CMD_NFS)
1459 	case NFS:
1460 #endif
1461 	case TFTPGET:
1462 	case TFTPPUT:
1463 		if (NetServerIP == 0) {
1464 			puts("*** ERROR: `serverip' not set\n");
1465 			return 1;
1466 		}
1467 #if	defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
1468 	defined(CONFIG_CMD_DNS)
1469 common:
1470 #endif
1471 		/* Fall through */
1472 
1473 	case NETCONS:
1474 	case TFTPSRV:
1475 		if (NetOurIP == 0) {
1476 			puts("*** ERROR: `ipaddr' not set\n");
1477 			return 1;
1478 		}
1479 		/* Fall through */
1480 
1481 #ifdef CONFIG_CMD_RARP
1482 	case RARP:
1483 #endif
1484 	case BOOTP:
1485 	case CDP:
1486 	case DHCP:
1487 		if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
1488 			int num = eth_get_dev_index();
1489 
1490 			switch (num) {
1491 			case -1:
1492 				puts("*** ERROR: No ethernet found.\n");
1493 				return 1;
1494 			case 0:
1495 				puts("*** ERROR: `ethaddr' not set\n");
1496 				break;
1497 			default:
1498 				printf("*** ERROR: `eth%daddr' not set\n",
1499 					num);
1500 				break;
1501 			}
1502 
1503 			NetStartAgain();
1504 			return 2;
1505 		}
1506 		/* Fall through */
1507 	default:
1508 		return 0;
1509 	}
1510 	return 0;		/* OK */
1511 }
1512 /**********************************************************************/
1513 
1514 int
1515 NetCksumOk(uchar *ptr, int len)
1516 {
1517 	return !((NetCksum(ptr, len) + 1) & 0xfffe);
1518 }
1519 
1520 
1521 unsigned
1522 NetCksum(uchar *ptr, int len)
1523 {
1524 	ulong	xsum;
1525 	ushort *p = (ushort *)ptr;
1526 
1527 	xsum = 0;
1528 	while (len-- > 0)
1529 		xsum += *p++;
1530 	xsum = (xsum & 0xffff) + (xsum >> 16);
1531 	xsum = (xsum & 0xffff) + (xsum >> 16);
1532 	return xsum & 0xffff;
1533 }
1534 
1535 int
1536 NetEthHdrSize(void)
1537 {
1538 	ushort myvlanid;
1539 
1540 	myvlanid = ntohs(NetOurVLAN);
1541 	if (myvlanid == (ushort)-1)
1542 		myvlanid = VLAN_NONE;
1543 
1544 	return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
1545 		VLAN_ETHER_HDR_SIZE;
1546 }
1547 
1548 int
1549 NetSetEther(uchar *xet, uchar * addr, uint prot)
1550 {
1551 	Ethernet_t *et = (Ethernet_t *)xet;
1552 	ushort myvlanid;
1553 
1554 	myvlanid = ntohs(NetOurVLAN);
1555 	if (myvlanid == (ushort)-1)
1556 		myvlanid = VLAN_NONE;
1557 
1558 	memcpy(et->et_dest, addr, 6);
1559 	memcpy(et->et_src, NetOurEther, 6);
1560 	if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
1561 		et->et_protlen = htons(prot);
1562 		return ETHER_HDR_SIZE;
1563 	} else {
1564 		VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
1565 
1566 		vet->vet_vlan_type = htons(PROT_VLAN);
1567 		vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1568 		vet->vet_type = htons(prot);
1569 		return VLAN_ETHER_HDR_SIZE;
1570 	}
1571 }
1572 
1573 void
1574 NetSetIP(uchar *xip, IPaddr_t dest, int dport, int sport, int len)
1575 {
1576 	IP_t *ip = (IP_t *)xip;
1577 
1578 	/*
1579 	 *	If the data is an odd number of bytes, zero the
1580 	 *	byte after the last byte so that the checksum
1581 	 *	will work.
1582 	 */
1583 	if (len & 1)
1584 		xip[IP_HDR_SIZE + len] = 0;
1585 
1586 	/*
1587 	 *	Construct an IP and UDP header.
1588 	 *	(need to set no fragment bit - XXX)
1589 	 */
1590 	/* IP_HDR_SIZE / 4 (not including UDP) */
1591 	ip->ip_hl_v  = 0x45;
1592 	ip->ip_tos   = 0;
1593 	ip->ip_len   = htons(IP_HDR_SIZE + len);
1594 	ip->ip_id    = htons(NetIPID++);
1595 	ip->ip_off   = htons(IP_FLAGS_DFRAG);	/* Don't fragment */
1596 	ip->ip_ttl   = 255;
1597 	ip->ip_p     = 17;		/* UDP */
1598 	ip->ip_sum   = 0;
1599 	/* already in network byte order */
1600 	NetCopyIP((void *)&ip->ip_src, &NetOurIP);
1601 	/* - "" - */
1602 	NetCopyIP((void *)&ip->ip_dst, &dest);
1603 	ip->udp_src  = htons(sport);
1604 	ip->udp_dst  = htons(dport);
1605 	ip->udp_len  = htons(8 + len);
1606 	ip->udp_xsum = 0;
1607 	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1608 }
1609 
1610 void copy_filename(char *dst, const char *src, int size)
1611 {
1612 	if (*src && (*src == '"')) {
1613 		++src;
1614 		--size;
1615 	}
1616 
1617 	while ((--size > 0) && *src && (*src != '"'))
1618 		*dst++ = *src++;
1619 	*dst = '\0';
1620 }
1621 
1622 #if	defined(CONFIG_CMD_NFS)		|| \
1623 	defined(CONFIG_CMD_SNTP)	|| \
1624 	defined(CONFIG_CMD_DNS)
1625 /*
1626  * make port a little random (1024-17407)
1627  * This keeps the math somewhat trivial to compute, and seems to work with
1628  * all supported protocols/clients/servers
1629  */
1630 unsigned int random_port(void)
1631 {
1632 	return 1024 + (get_timer(0) % 0x4000);
1633 }
1634 #endif
1635 
1636 void ip_to_string(IPaddr_t x, char *s)
1637 {
1638 	x = ntohl(x);
1639 	sprintf(s, "%d.%d.%d.%d",
1640 		(int) ((x >> 24) & 0xff),
1641 		(int) ((x >> 16) & 0xff),
1642 		(int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
1643 	);
1644 }
1645 
1646 void VLAN_to_string(ushort x, char *s)
1647 {
1648 	x = ntohs(x);
1649 
1650 	if (x == (ushort)-1)
1651 		x = VLAN_NONE;
1652 
1653 	if (x == VLAN_NONE)
1654 		strcpy(s, "none");
1655 	else
1656 		sprintf(s, "%d", x & VLAN_IDMASK);
1657 }
1658 
1659 ushort string_to_VLAN(const char *s)
1660 {
1661 	ushort id;
1662 
1663 	if (s == NULL)
1664 		return htons(VLAN_NONE);
1665 
1666 	if (*s < '0' || *s > '9')
1667 		id = VLAN_NONE;
1668 	else
1669 		id = (ushort)simple_strtoul(s, NULL, 10);
1670 
1671 	return htons(id);
1672 }
1673 
1674 ushort getenv_VLAN(char *var)
1675 {
1676 	return string_to_VLAN(getenv(var));
1677 }
1678