net.c 29.8 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 *	Copied from Linux Monitor (LiMon) - Networking.
 *
 *	Copyright 1994 - 2000 Neil Russell.
 *	(See License)
 *	Copyright 2000 Roland Borde
 *	Copyright 2000 Paolo Scaffardi
 *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de
 */

/*
 * General Desription:
 *
 * The user interface supports commands for BOOTP, RARP, and TFTP.
 * Also, we support ARP internally. Depending on available data,
 * these interact as follows:
 *
 * BOOTP:
 *
 *	Prerequisites:	- own ethernet address
 *	We want:	- own IP address
 *			- TFTP server IP address
 *			- name of bootfile
 *	Next step:	ARP
 *
 * RARP:
 *
 *	Prerequisites:	- own ethernet address
 *	We want:	- own IP address
 *			- TFTP server IP address
 *	Next step:	ARP
 *
 * ARP:
 *
 *	Prerequisites:	- own ethernet address
 *			- own IP address
 *			- TFTP server IP address
 *	We want:	- TFTP server ethernet address
 *	Next step:	TFTP
 *
 * DHCP:
 *
W
Wolfgang Denk 已提交
43 44 45 46
 *     Prerequisites:	- own ethernet address
 *     We want:		- IP, Netmask, ServerIP, Gateway IP
 *			- bootfilename, lease time
 *     Next step:	- TFTP
W
wdenk 已提交
47 48 49 50 51 52 53 54 55 56 57
 *
 * TFTP:
 *
 *	Prerequisites:	- own ethernet address
 *			- own IP address
 *			- TFTP server IP address
 *			- TFTP server ethernet address
 *			- name of bootfile (if unknown, we use a default name
 *			  derived from our own IP address)
 *	We want:	- load the boot file
 *	Next step:	none
W
wdenk 已提交
58 59 60 61 62 63 64 65 66
 *
 * NFS:
 *
 *	Prerequisites:	- own ethernet address
 *			- own IP address
 *			- name of bootfile (if unknown, we use a default name
 *			  derived from our own IP address)
 *	We want:	- load the boot file
 *	Next step:	none
W
wdenk 已提交
67 68 69
 *
 * SNTP:
 *
W
Wolfgang Denk 已提交
70
 *	Prerequisites:	- own ethernet address
W
wdenk 已提交
71 72 73
 *			- own IP address
 *	We want:	- network time
 *	Next step:	none
W
wdenk 已提交
74 75 76 77 78 79
 */


#include <common.h>
#include <watchdog.h>
#include <command.h>
80
#include <linux/compiler.h>
W
wdenk 已提交
81
#include <net.h>
J
Joe Hershberger 已提交
82
#include "arp.h"
W
wdenk 已提交
83 84
#include "bootp.h"
#include "tftp.h"
85
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
86
#include "rarp.h"
87
#endif
W
wdenk 已提交
88
#include "nfs.h"
W
wdenk 已提交
89 90 91 92
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#include <miiphy.h>
#endif
93
#if defined(CONFIG_CMD_SNTP)
W
wdenk 已提交
94 95
#include "sntp.h"
#endif
J
Joe Hershberger 已提交
96
#include "cdp.h"
R
Robin Getz 已提交
97 98 99
#if defined(CONFIG_CMD_DNS)
#include "dns.h"
#endif
J
Joe Hershberger 已提交
100
#include "ping.h"
W
wdenk 已提交
101

102 103
DECLARE_GLOBAL_DATA_PTR;

W
wdenk 已提交
104 105
/** BOOTP EXTENTIONS **/

106
/* Our subnet mask (0=unknown) */
107
IPaddr_t	NetOurSubnetMask;
108
/* Our gateways IP address */
109
IPaddr_t	NetOurGatewayIP;
110
/* Our DNS IP address */
111
IPaddr_t	NetOurDNSIP;
112
#if defined(CONFIG_BOOTP_DNS2)
113
/* Our 2nd DNS IP address */
114
IPaddr_t	NetOurDNS2IP;
115 116
#endif
/* Our NIS domain */
117
char		NetOurNISDomain[32] = {0,};
118
/* Our hostname */
119
char		NetOurHostName[32] = {0,};
120
/* Our bootpath */
121
char		NetOurRootPath[64] = {0,};
122
/* Our bootfile size in blocks */
123
ushort		NetBootFileSize;
W
wdenk 已提交
124

D
David Updegraff 已提交
125 126 127 128
#ifdef CONFIG_MCAST_TFTP	/* Multicast TFTP */
IPaddr_t Mcast_addr;
#endif

W
wdenk 已提交
129 130
/** END OF BOOTP EXTENTIONS **/

131 132 133 134 135
/* The actual transferred size of the bootfile (in bytes) */
ulong		NetBootFileXferSize;
/* Our ethernet address */
uchar		NetOurEther[6];
/* Boot server enet address */
136
uchar		NetServerEther[6];
137 138 139 140 141
/* Our IP addr (0 = unknown) */
IPaddr_t	NetOurIP;
/* Server IP addr (0 = unknown) */
IPaddr_t	NetServerIP;
/* Current receive packet */
142
uchar *NetRxPacket;
143 144 145 146 147
/* Current rx packet length */
int		NetRxPacketLen;
/* IP packet ID */
unsigned	NetIPID;
/* Ethernet bcast address */
148 149
uchar		NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uchar		NetEtherNullAddr[6];
150
#ifdef CONFIG_API
151
void		(*push_packet)(void *, int len) = 0;
152
#endif
153 154 155
/* Network loop state */
int		NetState;
/* Tried all network devices */
156
int		NetRestartWrap;
157
/* Network loop restarted */
158
static int	NetRestarted;
159
/* At least one device configured */
160
static int	NetDevExists;
W
wdenk 已提交
161

W
wdenk 已提交
162
/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
163 164 165 166
/* default is without VLAN */
ushort		NetOurVLAN = 0xFFFF;
/* ditto */
ushort		NetOurNativeVLAN = 0xFFFF;
167

168 169
/* Boot File name */
char		BootFile[128];
W
wdenk 已提交
170

171
#if defined(CONFIG_CMD_SNTP)
172 173 174
/* NTP server IP address */
IPaddr_t	NetNtpServerIP;
/* offset time from UTC */
175
int		NetTimeOffset;
W
wdenk 已提交
176 177
#endif

178
uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
W
wdenk 已提交
179

180
/* Receive packet */
181
uchar *NetRxPackets[PKTBUFSRX];
W
wdenk 已提交
182

183 184
/* Current RX packet handler */
static rxhand_f *packetHandler;
185
#ifdef CONFIG_CMD_TFTPPUT
186
static rxhand_icmp_f *packet_icmp_handler;	/* Current ICMP rx handler */
187
#endif
188 189 190 191 192 193 194
/* Current timeout handler */
static thand_f *timeHandler;
/* Time base value */
static ulong	timeStart;
/* Current timeout value */
static ulong	timeDelta;
/* THE transmit packet */
195
uchar *NetTxPacket;
W
wdenk 已提交
196

S
Simon Glass 已提交
197
static int net_check_prereq(enum proto_t protocol);
W
wdenk 已提交
198

R
Remy Bohmer 已提交
199 200
static int NetTryCount;

W
wdenk 已提交
201 202
/**********************************************************************/

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
/*
 * Check if autoload is enabled. If so, use either NFS or TFTP to download
 * the boot file.
 */
void net_auto_load(void)
{
	const char *s = getenv("autoload");

	if (s != NULL) {
		if (*s == 'n') {
			/*
			 * Just use BOOTP/RARP to configure system;
			 * Do not use TFTP to load the bootfile.
			 */
			NetState = NETLOOP_SUCCESS;
			return;
		}
#if defined(CONFIG_CMD_NFS)
		if (strcmp(s, "NFS") == 0) {
			/*
			 * Use NFS to load the bootfile.
			 */
			NfsStart();
			return;
		}
#endif
	}
	TftpStart(TFTPGET);
}

S
Simon Glass 已提交
233
static void NetInitLoop(enum proto_t protocol)
H
Heiko Schocher 已提交
234
{
235
	static int env_changed_id;
236
	int env_id = get_env_id();
H
Heiko Schocher 已提交
237 238

	/* update only when the environment has changed */
M
Michael Zaidman 已提交
239
	if (env_changed_id != env_id) {
240
		NetOurIP = getenv_IPaddr("ipaddr");
241 242 243
		NetOurGatewayIP = getenv_IPaddr("gatewayip");
		NetOurSubnetMask = getenv_IPaddr("netmask");
		NetServerIP = getenv_IPaddr("serverip");
H
Heiko Schocher 已提交
244
		NetOurNativeVLAN = getenv_VLAN("nvlan");
M
Michael Zaidman 已提交
245
		NetOurVLAN = getenv_VLAN("vlan");
R
Robin Getz 已提交
246 247 248
#if defined(CONFIG_CMD_DNS)
		NetOurDNSIP = getenv_IPaddr("dnsip");
#endif
M
Michael Zaidman 已提交
249
		env_changed_id = env_id;
H
Heiko Schocher 已提交
250
	}
M
Michael Zaidman 已提交
251

H
Heiko Schocher 已提交
252
	return;
H
Heiko Schocher 已提交
253 254
}

W
wdenk 已提交
255 256 257 258 259
/**********************************************************************/
/*
 *	Main network processing loop.
 */

S
Simon Glass 已提交
260
int NetLoop(enum proto_t protocol)
W
wdenk 已提交
261 262
{
	bd_t *bd = gd->bd;
263
	int ret = -1;
W
wdenk 已提交
264 265 266 267

	NetRestarted = 0;
	NetDevExists = 0;

W
wdenk 已提交
268
	NetTxPacket = NULL;
R
Remy Bohmer 已提交
269
	NetTryCount = 1;
W
wdenk 已提交
270

J
Joe Hershberger 已提交
271 272
	ArpInit();

W
wdenk 已提交
273 274 275 276 277 278 279
	if (!NetTxPacket) {
		int	i;
		/*
		 *	Setup packet buffers, aligned correctly.
		 */
		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
280
		for (i = 0; i < PKTBUFSRX; i++)
W
wdenk 已提交
281
			NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
W
wdenk 已提交
282 283
	}

284
	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
W
wdenk 已提交
285
	eth_halt();
286
	eth_set_current();
287 288
	if (eth_init(bd) < 0) {
		eth_halt();
289
		return -1;
290
	}
W
wdenk 已提交
291 292

restart:
293
	memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
W
wdenk 已提交
294 295 296 297 298 299 300 301

	NetState = NETLOOP_CONTINUE;

	/*
	 *	Start the ball rolling with the given start function.  From
	 *	here on, this code is a state machine driven by received
	 *	packets and timer events.
	 */
H
Heiko Schocher 已提交
302
	NetInitLoop(protocol);
W
wdenk 已提交
303

304
	switch (net_check_prereq(protocol)) {
W
wdenk 已提交
305 306
	case 1:
		/* network not configured */
307
		eth_halt();
308
		return -1;
W
wdenk 已提交
309 310 311 312 313 314 315

	case 2:
		/* network device not configured */
		break;

	case 0:
		NetDevExists = 1;
S
Simon Glass 已提交
316
		NetBootFileXferSize = 0;
W
wdenk 已提交
317
		switch (protocol) {
S
Simon Glass 已提交
318
		case TFTPGET:
S
Simon Glass 已提交
319 320 321
#ifdef CONFIG_CMD_TFTPPUT
		case TFTPPUT:
#endif
W
wdenk 已提交
322
			/* always use ARP to get server ethernet address */
S
Simon Glass 已提交
323
			TftpStart(protocol);
W
wdenk 已提交
324
			break;
L
Luca Ceresoli 已提交
325 326 327 328 329
#ifdef CONFIG_CMD_TFTPSRV
		case TFTPSRV:
			TftpStartServer();
			break;
#endif
330
#if defined(CONFIG_CMD_DHCP)
W
wdenk 已提交
331
		case DHCP:
W
wdenk 已提交
332
			BootpTry = 0;
M
Michael Zaidman 已提交
333
			NetOurIP = 0;
W
wdenk 已提交
334 335
			DhcpRequest();		/* Basically same as BOOTP */
			break;
336
#endif
W
wdenk 已提交
337 338 339

		case BOOTP:
			BootpTry = 0;
M
Michael Zaidman 已提交
340
			NetOurIP = 0;
341
			BootpRequest();
W
wdenk 已提交
342 343
			break;

344
#if defined(CONFIG_CMD_RARP)
W
wdenk 已提交
345 346
		case RARP:
			RarpTry = 0;
M
Michael Zaidman 已提交
347
			NetOurIP = 0;
348
			RarpRequest();
W
wdenk 已提交
349
			break;
350
#endif
351
#if defined(CONFIG_CMD_PING)
W
wdenk 已提交
352
		case PING:
J
Joe Hershberger 已提交
353
			ping_start();
W
wdenk 已提交
354
			break;
W
wdenk 已提交
355
#endif
356
#if defined(CONFIG_CMD_NFS)
W
wdenk 已提交
357 358 359
		case NFS:
			NfsStart();
			break;
360
#endif
361
#if defined(CONFIG_CMD_CDP)
362 363 364
		case CDP:
			CDPStart();
			break;
365 366 367 368 369
#endif
#ifdef CONFIG_NETCONSOLE
		case NETCONS:
			NcStart();
			break;
W
wdenk 已提交
370
#endif
371
#if defined(CONFIG_CMD_SNTP)
W
wdenk 已提交
372 373 374
		case SNTP:
			SntpStart();
			break;
R
Robin Getz 已提交
375 376 377 378 379
#endif
#if defined(CONFIG_CMD_DNS)
		case DNS:
			DnsStart();
			break;
W
wdenk 已提交
380
#endif
W
wdenk 已提交
381 382 383 384 385 386 387
		default:
			break;
		}

		break;
	}

388
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
389 390 391
#if	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)	&& \
	defined(CONFIG_STATUS_LED)			&& \
	defined(STATUS_LED_RED)
W
wdenk 已提交
392
	/*
W
wdenk 已提交
393
	 * Echo the inverted link state to the fault LED.
W
wdenk 已提交
394
	 */
395
	if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
396
		status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
397
	else
398
		status_led_set(STATUS_LED_RED, STATUS_LED_ON);
399
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
W
wdenk 已提交
400
#endif /* CONFIG_MII, ... */
W
wdenk 已提交
401 402 403

	/*
	 *	Main packet reception loop.  Loop receiving packets until
W
wdenk 已提交
404
	 *	someone sets `NetState' to a state that terminates.
W
wdenk 已提交
405 406 407 408
	 */
	for (;;) {
		WATCHDOG_RESET();
#ifdef CONFIG_SHOW_ACTIVITY
409
		show_activity(1);
W
wdenk 已提交
410 411 412 413 414
#endif
		/*
		 *	Check the ethernet for a new packet.  The ethernet
		 *	receive routine will process it.
		 */
415
		eth_rx();
W
wdenk 已提交
416 417 418 419 420

		/*
		 *	Abort if ctrl-c was pressed.
		 */
		if (ctrlc()) {
W
wdenk 已提交
421
			eth_halt();
422
			puts("\nAbort\n");
423
			goto done;
W
wdenk 已提交
424 425
		}

W
wdenk 已提交
426
		ArpTimeoutCheck();
W
wdenk 已提交
427 428 429 430 431

		/*
		 *	Check for a timeout, and run the timeout handler
		 *	if we have one.
		 */
432
		if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
W
wdenk 已提交
433 434
			thand_f *x;

435
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
436 437 438
#if	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)	&& \
	defined(CONFIG_STATUS_LED)			&& \
	defined(STATUS_LED_RED)
W
wdenk 已提交
439
			/*
W
wdenk 已提交
440
			 * Echo the inverted link state to the fault LED.
W
wdenk 已提交
441
			 */
442
			if (miiphy_link(eth_get_dev()->name,
443
				       CONFIG_SYS_FAULT_MII_ADDR)) {
444
				status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
W
wdenk 已提交
445
			} else {
446
				status_led_set(STATUS_LED_RED, STATUS_LED_ON);
W
wdenk 已提交
447
			}
448
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
W
wdenk 已提交
449
#endif /* CONFIG_MII, ... */
W
wdenk 已提交
450 451 452 453 454 455 456 457 458 459 460 461 462 463
			x = timeHandler;
			timeHandler = (thand_f *)0;
			(*x)();
		}


		switch (NetState) {

		case NETLOOP_RESTART:
			NetRestarted = 1;
			goto restart;

		case NETLOOP_SUCCESS:
			if (NetBootFileXferSize > 0) {
464
				char buf[20];
W
wdenk 已提交
465 466 467
				printf("Bytes transferred = %ld (%lx hex)\n",
					NetBootFileXferSize,
					NetBootFileXferSize);
468
				sprintf(buf, "%lX", NetBootFileXferSize);
W
wdenk 已提交
469
				setenv("filesize", buf);
470 471 472

				sprintf(buf, "%lX", (unsigned long)load_addr);
				setenv("fileaddr", buf);
W
wdenk 已提交
473 474
			}
			eth_halt();
475 476
			ret = NetBootFileXferSize;
			goto done;
W
wdenk 已提交
477 478

		case NETLOOP_FAIL:
479
			goto done;
W
wdenk 已提交
480 481
		}
	}
482 483

done:
484
#ifdef CONFIG_CMD_TFTPPUT
485 486 487
	/* Clear out the handlers */
	NetSetHandler(NULL);
	net_set_icmp_handler(NULL);
488
#endif
489
	return ret;
W
wdenk 已提交
490 491 492 493 494 495 496 497 498 499 500
}

/**********************************************************************/

static void
startAgainTimeout(void)
{
	NetState = NETLOOP_RESTART;
}

static void
501 502
startAgainHandler(uchar *pkt, unsigned dest, IPaddr_t sip,
		  unsigned src, unsigned len)
W
wdenk 已提交
503 504 505 506
{
	/* Totally ignore the packet */
}

507
void NetStartAgain(void)
W
wdenk 已提交
508
{
W
wdenk 已提交
509
	char *nretry;
R
Remy Bohmer 已提交
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	int retry_forever = 0;
	unsigned long retrycnt = 0;

	nretry = getenv("netretry");
	if (nretry) {
		if (!strcmp(nretry, "yes"))
			retry_forever = 1;
		else if (!strcmp(nretry, "no"))
			retrycnt = 0;
		else if (!strcmp(nretry, "once"))
			retrycnt = 1;
		else
			retrycnt = simple_strtoul(nretry, NULL, 0);
	} else
		retry_forever = 1;

	if ((!retry_forever) && (NetTryCount >= retrycnt)) {
		eth_halt();
528 529 530
		NetState = NETLOOP_FAIL;
		return;
	}
R
Remy Bohmer 已提交
531 532 533

	NetTryCount++;

534
	eth_halt();
535
#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
536
	eth_try_another(!NetRestarted);
537
#endif
538
	eth_init(gd->bd);
W
wdenk 已提交
539
	if (NetRestartWrap) {
W
wdenk 已提交
540
		NetRestartWrap = 0;
R
Remy Bohmer 已提交
541
		if (NetDevExists) {
542 543
			NetSetTimeout(10000UL, startAgainTimeout);
			NetSetHandler(startAgainHandler);
W
wdenk 已提交
544
		} else {
W
wdenk 已提交
545 546
			NetState = NETLOOP_FAIL;
		}
W
wdenk 已提交
547
	} else {
W
wdenk 已提交
548 549 550 551 552 553 554 555 556
		NetState = NETLOOP_RESTART;
	}
}

/**********************************************************************/
/*
 *	Miscelaneous bits.
 */

J
Joe Hershberger 已提交
557 558 559 560 561 562 563
rxhand_f *
NetGetHandler(void)
{
	return packetHandler;
}


W
wdenk 已提交
564
void
565
NetSetHandler(rxhand_f *f)
W
wdenk 已提交
566 567 568 569
{
	packetHandler = f;
}

570
#ifdef CONFIG_CMD_TFTPPUT
571 572 573 574
void net_set_icmp_handler(rxhand_icmp_f *f)
{
	packet_icmp_handler = f;
}
575
#endif
W
wdenk 已提交
576 577

void
578
NetSetTimeout(ulong iv, thand_f *f)
W
wdenk 已提交
579 580 581 582 583
{
	if (iv == 0) {
		timeHandler = (thand_f *)0;
	} else {
		timeHandler = f;
584 585
		timeStart = get_timer(0);
		timeDelta = iv;
W
wdenk 已提交
586 587 588 589 590
	}
}


void
591
NetSendPacket(uchar *pkt, int len)
W
wdenk 已提交
592 593 594 595
{
	(void) eth_send(pkt, len);
}

W
wdenk 已提交
596 597 598
int
NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
{
599 600
	uchar *pkt;

W
wdenk 已提交
601 602 603 604 605 606 607 608
	/* convert to new style broadcast */
	if (dest == 0)
		dest = 0xFFFFFFFF;

	/* if broadcast, make the ether address a broadcast and don't do ARP */
	if (dest == 0xFFFFFFFF)
		ether = NetBcastAddr;

609 610 611 612
	/*
	 * if MAC address was not discovered yet, save the packet and do
	 * an ARP request
	 */
W
wdenk 已提交
613 614
	if (memcmp(ether, NetEtherNullAddr, 6) == 0) {

615
		debug("sending ARP for %08x\n", dest);
R
Robin Getz 已提交
616

W
wdenk 已提交
617 618
		NetArpWaitPacketIP = dest;
		NetArpWaitPacketMAC = ether;
619 620

		pkt = NetArpWaitTxPacket;
621
		pkt += NetSetEther(pkt, NetArpWaitPacketMAC, PROT_IP);
622

623
		NetSetIP(pkt, dest, dport, sport, len);
624 625
		memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket +
		       (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
W
wdenk 已提交
626 627

		/* size of the waiting packet */
628 629
		NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) +
			IP_HDR_SIZE + len;
W
wdenk 已提交
630 631 632 633 634 635 636 637

		/* and do the ARP request */
		NetArpWaitTry = 1;
		NetArpWaitTimerStart = get_timer(0);
		ArpRequest();
		return 1;	/* waiting */
	}

638
	debug("sending UDP to %08x/%pM\n", dest, ether);
W
wdenk 已提交
639

640
	pkt = (uchar *)NetTxPacket;
641 642
	pkt += NetSetEther(pkt, ether, PROT_IP);
	NetSetIP(pkt, dest, dport, sport, len);
643
	(void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
W
wdenk 已提交
644

W
wdenk 已提交
645
	return 0;	/* transmitted */
W
wdenk 已提交
646 647
}

A
Alessandro Rubini 已提交
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
#ifdef CONFIG_IP_DEFRAG
/*
 * This function collects fragments in a single packet, according
 * to the algorithm in RFC815. It returns NULL or the pointer to
 * a complete packet, in static storage
 */
#ifndef CONFIG_NET_MAXDEFRAG
#define CONFIG_NET_MAXDEFRAG 16384
#endif
/*
 * MAXDEFRAG, above, is chosen in the config file and  is real data
 * so we need to add the NFS overhead, which is more than TFTP.
 * To use sizeof in the internal unnamed structures, we need a real
 * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately).
 * The compiler doesn't complain nor allocates the actual structure
 */
static struct rpc_t rpc_specimen;
#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))

#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE_NO_UDP)

/*
 * this is the packet being assembled, either data or frag control.
 * Fragments go by 8 bytes, so this union must be 8 bytes long
 */
struct hole {
	/* first_byte is address of this structure */
	u16 last_byte;	/* last byte in this hole + 1 (begin of next hole) */
	u16 next_hole;	/* index of next (in 8-b blocks), 0 == none */
	u16 prev_hole;	/* index of prev, 0 == none */
	u16 unused;
};

static IP_t *__NetDefragment(IP_t *ip, int *lenp)
{
683
	static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
A
Alessandro Rubini 已提交
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	static u16 first_hole, total_len;
	struct hole *payload, *thisfrag, *h, *newh;
	IP_t *localip = (IP_t *)pkt_buff;
	uchar *indata = (uchar *)ip;
	int offset8, start, len, done = 0;
	u16 ip_off = ntohs(ip->ip_off);

	/* payload starts after IP header, this fragment is in there */
	payload = (struct hole *)(pkt_buff + IP_HDR_SIZE_NO_UDP);
	offset8 =  (ip_off & IP_OFFS);
	thisfrag = payload + offset8;
	start = offset8 * 8;
	len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;

	if (start + len > IP_MAXUDP) /* fragment extends too far */
		return NULL;

	if (!total_len || localip->ip_id != ip->ip_id) {
		/* new (or different) packet, reset structs */
		total_len = 0xffff;
		payload[0].last_byte = ~0;
		payload[0].next_hole = 0;
		payload[0].prev_hole = 0;
		first_hole = 0;
		/* any IP header will work, copy the first we received */
		memcpy(localip, ip, IP_HDR_SIZE_NO_UDP);
	}

	/*
	 * What follows is the reassembly algorithm. We use the payload
	 * array as a linked list of hole descriptors, as each hole starts
	 * at a multiple of 8 bytes. However, last byte can be whatever value,
	 * so it is represented as byte count, not as 8-byte blocks.
	 */

	h = payload + first_hole;
	while (h->last_byte < start) {
		if (!h->next_hole) {
			/* no hole that far away */
			return NULL;
		}
		h = payload + h->next_hole;
	}

728 729
	/* last fragment may be 1..7 bytes, the "+7" forces acceptance */
	if (offset8 + ((len + 7) / 8) <= h - payload) {
A
Alessandro Rubini 已提交
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
		/* no overlap with holes (dup fragment?) */
		return NULL;
	}

	if (!(ip_off & IP_FLAGS_MFRAG)) {
		/* no more fragmentss: truncate this (last) hole */
		total_len = start + len;
		h->last_byte = start + len;
	}

	/*
	 * There is some overlap: fix the hole list. This code doesn't
	 * deal with a fragment that overlaps with two different holes
	 * (thus being a superset of a previously-received fragment).
	 */

746
	if ((h >= thisfrag) && (h->last_byte <= start + len)) {
A
Alessandro Rubini 已提交
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
		/* complete overlap with hole: remove hole */
		if (!h->prev_hole && !h->next_hole) {
			/* last remaining hole */
			done = 1;
		} else if (!h->prev_hole) {
			/* first hole */
			first_hole = h->next_hole;
			payload[h->next_hole].prev_hole = 0;
		} else if (!h->next_hole) {
			/* last hole */
			payload[h->prev_hole].next_hole = 0;
		} else {
			/* in the middle of the list */
			payload[h->next_hole].prev_hole = h->prev_hole;
			payload[h->prev_hole].next_hole = h->next_hole;
		}

	} else if (h->last_byte <= start + len) {
		/* overlaps with final part of the hole: shorten this hole */
		h->last_byte = start;

	} else if (h >= thisfrag) {
		/* overlaps with initial part of the hole: move this hole */
		newh = thisfrag + (len / 8);
		*newh = *h;
		h = newh;
		if (h->next_hole)
			payload[h->next_hole].prev_hole = (h - payload);
		if (h->prev_hole)
			payload[h->prev_hole].next_hole = (h - payload);
		else
			first_hole = (h - payload);

	} else {
		/* fragment sits in the middle: split the hole */
		newh = thisfrag + (len / 8);
		*newh = *h;
		h->last_byte = start;
		h->next_hole = (newh - payload);
		newh->prev_hole = (h - payload);
		if (newh->next_hole)
			payload[newh->next_hole].prev_hole = (newh - payload);
	}

	/* finally copy this fragment and possibly return whole packet */
	memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE_NO_UDP, len);
	if (!done)
		return NULL;

	localip->ip_len = htons(total_len);
	*lenp = total_len + IP_HDR_SIZE_NO_UDP;
	return localip;
}

static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
{
	u16 ip_off = ntohs(ip->ip_off);
	if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
		return ip; /* not a fragment */
	return __NetDefragment(ip, lenp);
}

#else /* !CONFIG_IP_DEFRAG */

static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
{
	u16 ip_off = ntohs(ip->ip_off);
	if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
		return ip; /* not a fragment */
	return NULL;
}
#endif
819

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
/**
 * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
 * drop others.
 *
 * @parma ip	IP packet containing the ICMP
 */
static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
{
	ICMP_t *icmph = (ICMP_t *)&ip->udp_src;

	switch (icmph->type) {
	case ICMP_REDIRECT:
		if (icmph->code != ICMP_REDIR_HOST)
			return;
		printf(" ICMP Host Redirect to %pI4 ",
			&icmph->un.gateway);
		break;
J
Joe Hershberger 已提交
837
	default:
838
#if defined(CONFIG_CMD_PING)
J
Joe Hershberger 已提交
839
		ping_receive(et, ip, len);
840
#endif
841
#ifdef CONFIG_CMD_TFTPPUT
842 843 844 845
		if (packet_icmp_handler)
			packet_icmp_handler(icmph->type, icmph->code,
				ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
				icmph->un.data, ntohs(ip->udp_len));
846
#endif
847 848 849 850
		break;
	}
}

W
wdenk 已提交
851
void
852
NetReceive(uchar *inpkt, int len)
W
wdenk 已提交
853 854 855
{
	Ethernet_t *et;
	IP_t	*ip;
J
Joe Hershberger 已提交
856
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
857
	ARP_t	*arp;
J
Joe Hershberger 已提交
858
#endif
W
wdenk 已提交
859
	IPaddr_t tmp;
860
	IPaddr_t src_ip;
W
wdenk 已提交
861
	int	x;
862
#if defined(CONFIG_CMD_CDP)
863 864 865 866
	int iscdp;
#endif
	ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;

R
Robin Getz 已提交
867
	debug("packet received\n");
W
wdenk 已提交
868

869 870
	NetRxPacket = inpkt;
	NetRxPacketLen = len;
871 872 873 874 875 876
	et = (Ethernet_t *)inpkt;

	/* too small packet? */
	if (len < ETHER_HDR_SIZE)
		return;

877 878 879 880 881 882 883
#ifdef CONFIG_API
	if (push_packet) {
		(*push_packet)(inpkt, len);
		return;
	}
#endif

884
#if defined(CONFIG_CMD_CDP)
885
	/* keep track if packet is CDP */
886
	iscdp = is_cdp_packet(et->et_dest);
887 888 889 890 891 892 893 894
#endif

	myvlanid = ntohs(NetOurVLAN);
	if (myvlanid == (ushort)-1)
		myvlanid = VLAN_NONE;
	mynvlanid = ntohs(NetOurNativeVLAN);
	if (mynvlanid == (ushort)-1)
		mynvlanid = VLAN_NONE;
W
wdenk 已提交
895 896 897

	x = ntohs(et->et_protlen);

R
Robin Getz 已提交
898
	debug("packet received\n");
899

W
wdenk 已提交
900 901 902 903 904
	if (x < 1514) {
		/*
		 *	Got a 802 packet.  Check the other protocol field.
		 */
		x = ntohs(et->et_prot);
905 906

		ip = (IP_t *)(inpkt + E802_HDR_SIZE);
W
wdenk 已提交
907
		len -= E802_HDR_SIZE;
908 909 910

	} else if (x != PROT_VLAN) {	/* normal packet */
		ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
W
wdenk 已提交
911
		len -= ETHER_HDR_SIZE;
912 913 914 915

	} else {			/* VLAN packet */
		VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;

R
Robin Getz 已提交
916 917
		debug("VLAN packet received\n");

918 919 920 921 922 923
		/* too small packet? */
		if (len < VLAN_ETHER_HDR_SIZE)
			return;

		/* if no VLAN active */
		if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
924
#if defined(CONFIG_CMD_CDP)
925 926 927 928 929 930 931 932 933 934 935
				&& iscdp == 0
#endif
				)
			return;

		cti = ntohs(vet->vet_tag);
		vlanid = cti & VLAN_IDMASK;
		x = ntohs(vet->vet_type);

		ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
		len -= VLAN_ETHER_HDR_SIZE;
W
wdenk 已提交
936 937
	}

R
Robin Getz 已提交
938
	debug("Receive from protocol 0x%x\n", x);
W
wdenk 已提交
939

940
#if defined(CONFIG_CMD_CDP)
941 942 943 944 945 946 947 948 949 950 951 952 953 954
	if (iscdp) {
		CDPHandler((uchar *)ip, len);
		return;
	}
#endif

	if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
		if (vlanid == VLAN_NONE)
			vlanid = (mynvlanid & VLAN_IDMASK);
		/* not matched? */
		if (vlanid != (myvlanid & VLAN_IDMASK))
			return;
	}

W
wdenk 已提交
955 956 957
	switch (x) {

	case PROT_ARP:
J
Joe Hershberger 已提交
958
		ArpReceive(et, ip, len);
W
wdenk 已提交
959
		break;
W
wdenk 已提交
960

961
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
962
	case PROT_RARP:
R
Robin Getz 已提交
963
		debug("Got RARP\n");
W
wdenk 已提交
964 965 966 967 968 969 970 971 972 973 974
		arp = (ARP_t *)ip;
		if (len < ARP_HDR_SIZE) {
			printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
			return;
		}

		if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
			(ntohs(arp->ar_hrd) != ARP_ETHER)   ||
			(ntohs(arp->ar_pro) != PROT_IP)     ||
			(arp->ar_hln != 6) || (arp->ar_pln != 4)) {

975
			puts("invalid RARP header\n");
W
wdenk 已提交
976
		} else {
977
			NetCopyIP(&NetOurIP, &arp->ar_data[16]);
W
wdenk 已提交
978
			if (NetServerIP == 0)
979 980
				NetCopyIP(&NetServerIP, &arp->ar_data[6]);
			memcpy(NetServerEther, &arp->ar_data[0], 6);
W
wdenk 已提交
981

982
			(*packetHandler)(0, 0, 0, 0, 0);
W
wdenk 已提交
983 984
		}
		break;
985
#endif
W
wdenk 已提交
986
	case PROT_IP:
R
Robin Getz 已提交
987
		debug("Got IP\n");
A
Alessandro Rubini 已提交
988
		/* Before we start poking the header, make sure it is there */
W
wdenk 已提交
989
		if (len < IP_HDR_SIZE) {
R
Robin Getz 已提交
990
			debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
W
wdenk 已提交
991 992
			return;
		}
A
Alessandro Rubini 已提交
993
		/* Check the packet length */
W
wdenk 已提交
994 995 996 997 998
		if (len < ntohs(ip->ip_len)) {
			printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
			return;
		}
		len = ntohs(ip->ip_len);
R
Robin Getz 已提交
999 1000
		debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);

A
Alessandro Rubini 已提交
1001
		/* Can't deal with anything except IPv4 */
1002
		if ((ip->ip_hl_v & 0xf0) != 0x40)
W
wdenk 已提交
1003
			return;
A
Alessandro Rubini 已提交
1004
		/* Can't deal with IP options (headers != 20 bytes) */
1005
		if ((ip->ip_hl_v & 0x0f) > 0x05)
1006
			return;
A
Alessandro Rubini 已提交
1007
		/* Check the Checksum of the header */
W
wdenk 已提交
1008
		if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
1009
			puts("checksum bad\n");
W
wdenk 已提交
1010 1011
			return;
		}
A
Alessandro Rubini 已提交
1012
		/* If it is not for us, ignore it */
W
wdenk 已提交
1013 1014
		tmp = NetReadIP(&ip->ip_dst);
		if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
D
David Updegraff 已提交
1015
#ifdef CONFIG_MCAST_TFTP
1016
			if (Mcast_addr != tmp)
D
David Updegraff 已提交
1017
#endif
1018
				return;
W
wdenk 已提交
1019
		}
1020 1021
		/* Read source IP address for later use */
		src_ip = NetReadIP(&ip->ip_src);
A
Alessandro Rubini 已提交
1022 1023 1024 1025 1026
		/*
		 * The function returns the unchanged packet if it's not
		 * a fragment, and either the complete packet or NULL if
		 * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
		 */
1027 1028
		ip = NetDefragment(ip, &len);
		if (!ip)
A
Alessandro Rubini 已提交
1029
			return;
W
wdenk 已提交
1030 1031 1032
		/*
		 * watch for ICMP host redirects
		 *
W
wdenk 已提交
1033 1034 1035 1036 1037
		 * There is no real handler code (yet). We just watch
		 * for ICMP host redirect messages. In case anybody
		 * sees these messages: please contact me
		 * (wd@denx.de), or - even better - send me the
		 * necessary fixes :-)
W
wdenk 已提交
1038
		 *
W
wdenk 已提交
1039 1040 1041 1042 1043 1044 1045
		 * Note: in all cases where I have seen this so far
		 * it was a problem with the router configuration,
		 * for instance when a router was configured in the
		 * BOOTP reply, but the TFTP server was on the same
		 * subnet. So this is probably a warning that your
		 * configuration might be wrong. But I'm not really
		 * sure if there aren't any other situations.
1046 1047 1048 1049
		 *
		 * Simon Glass <sjg@chromium.org>: We get an ICMP when
		 * we send a tftp packet to a dead connection, or when
		 * there is no server at the other end.
W
wdenk 已提交
1050 1051
		 */
		if (ip->ip_p == IPPROTO_ICMP) {
1052 1053
			receive_icmp(ip, len, src_ip, et);
			return;
W
wdenk 已提交
1054 1055 1056 1057
		} else if (ip->ip_p != IPPROTO_UDP) {	/* Only UDP packets */
			return;
		}

1058 1059
#ifdef CONFIG_UDP_CHECKSUM
		if (ip->udp_xsum != 0) {
W
Wolfgang Denk 已提交
1060
			ulong   xsum;
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
			ushort *sumptr;
			ushort  sumlen;

			xsum  = ip->ip_p;
			xsum += (ntohs(ip->udp_len));
			xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
			xsum += (ntohl(ip->ip_src) >>  0) & 0x0000ffff;
			xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
			xsum += (ntohl(ip->ip_dst) >>  0) & 0x0000ffff;

			sumlen = ntohs(ip->udp_len);
			sumptr = (ushort *) &(ip->udp_src);

			while (sumlen > 1) {
W
Wolfgang Denk 已提交
1075
				ushort sumdata;
1076 1077 1078 1079 1080 1081

				sumdata = *sumptr++;
				xsum += ntohs(sumdata);
				sumlen -= 2;
			}
			if (sumlen > 0) {
W
Wolfgang Denk 已提交
1082
				ushort sumdata;
1083 1084

				sumdata = *(unsigned char *) sumptr;
W
Wolfgang Denk 已提交
1085
				sumdata = (sumdata << 8) & 0xff00;
1086 1087 1088
				xsum += sumdata;
			}
			while ((xsum >> 16) != 0) {
1089 1090
				xsum = (xsum & 0x0000ffff) +
				       ((xsum >> 16) & 0x0000ffff);
1091 1092
			}
			if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
1093 1094
				printf(" UDP wrong checksum %08lx %08x\n",
					xsum, ntohs(ip->udp_xsum));
1095 1096 1097 1098 1099
				return;
			}
		}
#endif

D
David Updegraff 已提交
1100

1101
#ifdef CONFIG_NETCONSOLE
1102
		nc_input_packet((uchar *)ip + IP_HDR_SIZE,
1103 1104 1105 1106
						ntohs(ip->udp_dst),
						ntohs(ip->udp_src),
						ntohs(ip->udp_len) - 8);
#endif
W
wdenk 已提交
1107 1108 1109
		/*
		 *	IP header OK.  Pass the packet to the current handler.
		 */
1110
		(*packetHandler)((uchar *)ip + IP_HDR_SIZE,
W
wdenk 已提交
1111
						ntohs(ip->udp_dst),
1112
						src_ip,
W
wdenk 已提交
1113 1114 1115 1116 1117 1118 1119 1120 1121
						ntohs(ip->udp_src),
						ntohs(ip->udp_len) - 8);
		break;
	}
}


/**********************************************************************/

S
Simon Glass 已提交
1122
static int net_check_prereq(enum proto_t protocol)
W
wdenk 已提交
1123 1124
{
	switch (protocol) {
W
wdenk 已提交
1125
		/* Fall through */
1126
#if defined(CONFIG_CMD_PING)
W
wdenk 已提交
1127
	case PING:
W
wdenk 已提交
1128
		if (NetPingIP == 0) {
1129
			puts("*** ERROR: ping address not given\n");
1130
			return 1;
W
wdenk 已提交
1131 1132
		}
		goto common;
W
wdenk 已提交
1133
#endif
1134
#if defined(CONFIG_CMD_SNTP)
W
wdenk 已提交
1135 1136
	case SNTP:
		if (NetNtpServerIP == 0) {
1137
			puts("*** ERROR: NTP server address not given\n");
1138
			return 1;
W
wdenk 已提交
1139 1140 1141
		}
		goto common;
#endif
R
Robin Getz 已提交
1142 1143 1144 1145 1146 1147 1148 1149
#if defined(CONFIG_CMD_DNS)
	case DNS:
		if (NetOurDNSIP == 0) {
			puts("*** ERROR: DNS server address not given\n");
			return 1;
		}
		goto common;
#endif
1150
#if defined(CONFIG_CMD_NFS)
W
wdenk 已提交
1151
	case NFS:
W
wdenk 已提交
1152
#endif
S
Simon Glass 已提交
1153
	case TFTPGET:
S
Simon Glass 已提交
1154
	case TFTPPUT:
W
wdenk 已提交
1155
		if (NetServerIP == 0) {
1156
			puts("*** ERROR: `serverip' not set\n");
1157
			return 1;
W
wdenk 已提交
1158
		}
1159 1160 1161
#if	defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
	defined(CONFIG_CMD_DNS)
common:
W
wdenk 已提交
1162
#endif
1163
		/* Fall through */
W
wdenk 已提交
1164

1165
	case NETCONS:
L
Luca Ceresoli 已提交
1166
	case TFTPSRV:
W
wdenk 已提交
1167
		if (NetOurIP == 0) {
1168
			puts("*** ERROR: `ipaddr' not set\n");
1169
			return 1;
W
wdenk 已提交
1170 1171
		}
		/* Fall through */
W
wdenk 已提交
1172

1173
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
1174
	case RARP:
1175
#endif
W
wdenk 已提交
1176
	case BOOTP:
1177
	case CDP:
1178
	case DHCP:
1179 1180
		if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
			int num = eth_get_dev_index();
W
wdenk 已提交
1181

W
wdenk 已提交
1182 1183
			switch (num) {
			case -1:
1184
				puts("*** ERROR: No ethernet found.\n");
1185
				return 1;
W
wdenk 已提交
1186
			case 0:
1187
				puts("*** ERROR: `ethaddr' not set\n");
W
wdenk 已提交
1188
				break;
W
wdenk 已提交
1189
			default:
1190
				printf("*** ERROR: `eth%daddr' not set\n",
W
wdenk 已提交
1191 1192
					num);
				break;
W
wdenk 已提交
1193
			}
W
wdenk 已提交
1194

1195
			NetStartAgain();
1196
			return 2;
W
wdenk 已提交
1197 1198 1199
		}
		/* Fall through */
	default:
1200
		return 0;
W
wdenk 已提交
1201
	}
1202
	return 0;		/* OK */
W
wdenk 已提交
1203 1204 1205 1206
}
/**********************************************************************/

int
1207
NetCksumOk(uchar *ptr, int len)
W
wdenk 已提交
1208 1209 1210 1211 1212 1213
{
	return !((NetCksum(ptr, len) + 1) & 0xfffe);
}


unsigned
1214
NetCksum(uchar *ptr, int len)
W
wdenk 已提交
1215 1216
{
	ulong	xsum;
1217
	ushort *p = (ushort *)ptr;
W
wdenk 已提交
1218 1219 1220

	xsum = 0;
	while (len-- > 0)
W
Wolfgang Denk 已提交
1221
		xsum += *p++;
W
wdenk 已提交
1222 1223
	xsum = (xsum & 0xffff) + (xsum >> 16);
	xsum = (xsum & 0xffff) + (xsum >> 16);
1224
	return xsum & 0xffff;
W
wdenk 已提交
1225 1226
}

1227 1228 1229 1230
int
NetEthHdrSize(void)
{
	ushort myvlanid;
W
wdenk 已提交
1231

1232 1233 1234 1235
	myvlanid = ntohs(NetOurVLAN);
	if (myvlanid == (ushort)-1)
		myvlanid = VLAN_NONE;

1236 1237
	return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
		VLAN_ETHER_HDR_SIZE;
1238 1239 1240
}

int
1241
NetSetEther(uchar *xet, uchar * addr, uint prot)
W
wdenk 已提交
1242 1243
{
	Ethernet_t *et = (Ethernet_t *)xet;
1244 1245 1246 1247 1248
	ushort myvlanid;

	myvlanid = ntohs(NetOurVLAN);
	if (myvlanid == (ushort)-1)
		myvlanid = VLAN_NONE;
W
wdenk 已提交
1249

1250 1251
	memcpy(et->et_dest, addr, 6);
	memcpy(et->et_src, NetOurEther, 6);
1252
	if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
1253
		et->et_protlen = htons(prot);
1254 1255 1256
		return ETHER_HDR_SIZE;
	} else {
		VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
W
wdenk 已提交
1257

1258 1259 1260 1261 1262 1263
		vet->vet_vlan_type = htons(PROT_VLAN);
		vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
		vet->vet_type = htons(prot);
		return VLAN_ETHER_HDR_SIZE;
	}
}
W
wdenk 已提交
1264 1265

void
1266
NetSetIP(uchar *xip, IPaddr_t dest, int dport, int sport, int len)
W
wdenk 已提交
1267
{
O
Olav Morken 已提交
1268
	IP_t *ip = (IP_t *)xip;
W
wdenk 已提交
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279

	/*
	 *	If the data is an odd number of bytes, zero the
	 *	byte after the last byte so that the checksum
	 *	will work.
	 */
	if (len & 1)
		xip[IP_HDR_SIZE + len] = 0;

	/*
	 *	Construct an IP and UDP header.
W
wdenk 已提交
1280
	 *	(need to set no fragment bit - XXX)
W
wdenk 已提交
1281
	 */
1282 1283
	/* IP_HDR_SIZE / 4 (not including UDP) */
	ip->ip_hl_v  = 0x45;
W
wdenk 已提交
1284 1285 1286
	ip->ip_tos   = 0;
	ip->ip_len   = htons(IP_HDR_SIZE + len);
	ip->ip_id    = htons(NetIPID++);
P
Peter Tyser 已提交
1287
	ip->ip_off   = htons(IP_FLAGS_DFRAG);	/* Don't fragment */
W
wdenk 已提交
1288 1289 1290
	ip->ip_ttl   = 255;
	ip->ip_p     = 17;		/* UDP */
	ip->ip_sum   = 0;
1291
	/* already in network byte order */
1292
	NetCopyIP((void *)&ip->ip_src, &NetOurIP);
1293
	/* - "" - */
1294
	NetCopyIP((void *)&ip->ip_dst, &dest);
W
wdenk 已提交
1295 1296 1297 1298 1299 1300 1301
	ip->udp_src  = htons(sport);
	ip->udp_dst  = htons(dport);
	ip->udp_len  = htons(8 + len);
	ip->udp_xsum = 0;
	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
}

1302
void copy_filename(char *dst, const char *src, int size)
W
wdenk 已提交
1303 1304 1305 1306 1307 1308
{
	if (*src && (*src == '"')) {
		++src;
		--size;
	}

1309
	while ((--size > 0) && *src && (*src != '"'))
W
wdenk 已提交
1310 1311 1312 1313
		*dst++ = *src++;
	*dst = '\0';
}

1314 1315 1316
#if	defined(CONFIG_CMD_NFS)		|| \
	defined(CONFIG_CMD_SNTP)	|| \
	defined(CONFIG_CMD_DNS)
R
Robin Getz 已提交
1317
/*
1318 1319 1320
 * make port a little random (1024-17407)
 * This keeps the math somewhat trivial to compute, and seems to work with
 * all supported protocols/clients/servers
R
Robin Getz 已提交
1321 1322 1323
 */
unsigned int random_port(void)
{
1324
	return 1024 + (get_timer(0) % 0x4000);
R
Robin Getz 已提交
1325 1326 1327
}
#endif

1328
void ip_to_string(IPaddr_t x, char *s)
W
wdenk 已提交
1329
{
1330 1331 1332 1333 1334
	x = ntohl(x);
	sprintf(s, "%d.%d.%d.%d",
		(int) ((x >> 24) & 0xff),
		(int) ((x >> 16) & 0xff),
		(int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
W
wdenk 已提交
1335
	);
W
wdenk 已提交
1336 1337
}

1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
void VLAN_to_string(ushort x, char *s)
{
	x = ntohs(x);

	if (x == (ushort)-1)
		x = VLAN_NONE;

	if (x == VLAN_NONE)
		strcpy(s, "none");
	else
		sprintf(s, "%d", x & VLAN_IDMASK);
}

1351
ushort string_to_VLAN(const char *s)
1352 1353 1354 1355
{
	ushort id;

	if (s == NULL)
W
wdenk 已提交
1356
		return htons(VLAN_NONE);
1357 1358 1359 1360 1361 1362

	if (*s < '0' || *s > '9')
		id = VLAN_NONE;
	else
		id = (ushort)simple_strtoul(s, NULL, 10);

W
wdenk 已提交
1363
	return htons(id);
1364 1365 1366 1367
}

ushort getenv_VLAN(char *var)
{
1368
	return string_to_VLAN(getenv(var));
1369
}