net.c 29.6 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 85
#include "bootp.h"
#include "tftp.h"
#include "rarp.h"
W
wdenk 已提交
86
#include "nfs.h"
W
wdenk 已提交
87 88 89 90
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#include <miiphy.h>
#endif
91
#if defined(CONFIG_CMD_SNTP)
W
wdenk 已提交
92 93
#include "sntp.h"
#endif
J
Joe Hershberger 已提交
94
#include "cdp.h"
R
Robin Getz 已提交
95 96 97
#if defined(CONFIG_CMD_DNS)
#include "dns.h"
#endif
J
Joe Hershberger 已提交
98
#include "ping.h"
W
wdenk 已提交
99

100 101
DECLARE_GLOBAL_DATA_PTR;

W
wdenk 已提交
102 103
/** BOOTP EXTENTIONS **/

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

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

W
wdenk 已提交
127 128
/** END OF BOOTP EXTENTIONS **/

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

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

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

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

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

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

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

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

R
Remy Bohmer 已提交
197 198
static int NetTryCount;

W
wdenk 已提交
199 200
/**********************************************************************/

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
/*
 * 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 已提交
231
static void NetInitLoop(enum proto_t protocol)
H
Heiko Schocher 已提交
232
{
233
	static int env_changed_id;
234
	int env_id = get_env_id();
H
Heiko Schocher 已提交
235 236

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

H
Heiko Schocher 已提交
250
	return;
H
Heiko Schocher 已提交
251 252
}

W
wdenk 已提交
253 254 255 256 257
/**********************************************************************/
/*
 *	Main network processing loop.
 */

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

	NetRestarted = 0;
	NetDevExists = 0;

W
wdenk 已提交
266
	NetTxPacket = NULL;
R
Remy Bohmer 已提交
267
	NetTryCount = 1;
W
wdenk 已提交
268

J
Joe Hershberger 已提交
269 270
	ArpInit();

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

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

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

	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 已提交
300
	NetInitLoop(protocol);
W
wdenk 已提交
301

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

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

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

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

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

		break;
	}

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

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

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

W
wdenk 已提交
424
		ArpTimeoutCheck();
W
wdenk 已提交
425 426 427 428 429

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

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


		switch (NetState) {

		case NETLOOP_RESTART:
			NetRestarted = 1;
			goto restart;

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

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

		case NETLOOP_FAIL:
477
			goto done;
W
wdenk 已提交
478 479
		}
	}
480 481

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

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

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

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

505
void NetStartAgain(void)
W
wdenk 已提交
506
{
W
wdenk 已提交
507
	char *nretry;
R
Remy Bohmer 已提交
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
	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();
526 527 528
		NetState = NETLOOP_FAIL;
		return;
	}
R
Remy Bohmer 已提交
529 530 531

	NetTryCount++;

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

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

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


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

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

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


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

594 595
int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport,
		int payload_len)
W
wdenk 已提交
596
{
597 598
	uchar *pkt;

W
wdenk 已提交
599 600 601 602 603 604 605 606
	/* 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;

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

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

W
wdenk 已提交
615 616
		NetArpWaitPacketIP = dest;
		NetArpWaitPacketMAC = ether;
617 618

		pkt = NetArpWaitTxPacket;
619
		pkt += NetSetEther(pkt, NetArpWaitPacketMAC, PROT_IP);
620

621
		NetSetIP(pkt, dest, dport, sport, payload_len);
J
Joe Hershberger 已提交
622 623
		memcpy(pkt + IP_UDP_HDR_SIZE, (uchar *)NetTxPacket +
		       (pkt - (uchar *)NetArpWaitTxPacket) +
624
		       IP_UDP_HDR_SIZE, payload_len);
W
wdenk 已提交
625 626

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

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

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

639
	pkt = (uchar *)NetTxPacket;
640
	pkt += NetSetEther(pkt, ether, PROT_IP);
641 642 643
	NetSetIP(pkt, dest, dport, sport, payload_len);
	eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_UDP_HDR_SIZE +
		payload_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
#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))

667
#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE)
A
Alessandro Rubini 已提交
668 669 670 671 672 673 674 675 676 677 678 679 680

/*
 * 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;
};

J
Joe Hershberger 已提交
681
static struct ip_udp_hdr *__NetDefragment(struct ip_udp_hdr *ip, int *lenp)
A
Alessandro Rubini 已提交
682
{
683
	static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
A
Alessandro Rubini 已提交
684 685
	static u16 first_hole, total_len;
	struct hole *payload, *thisfrag, *h, *newh;
J
Joe Hershberger 已提交
686
	struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
A
Alessandro Rubini 已提交
687 688 689 690 691
	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 */
692
	payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
A
Alessandro Rubini 已提交
693 694 695
	offset8 =  (ip_off & IP_OFFS);
	thisfrag = payload + offset8;
	start = offset8 * 8;
696
	len = ntohs(ip->ip_len) - IP_HDR_SIZE;
A
Alessandro Rubini 已提交
697 698 699 700 701 702 703 704 705 706 707 708

	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 */
709
		memcpy(localip, ip, IP_HDR_SIZE);
A
Alessandro Rubini 已提交
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	}

	/*
	 * 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
		/* 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 */
792
	memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
A
Alessandro Rubini 已提交
793 794 795 796
	if (!done)
		return NULL;

	localip->ip_len = htons(total_len);
797
	*lenp = total_len + IP_HDR_SIZE;
A
Alessandro Rubini 已提交
798 799 800
	return localip;
}

J
Joe Hershberger 已提交
801
static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp)
A
Alessandro Rubini 已提交
802 803 804 805 806 807 808 809 810
{
	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 */

J
Joe Hershberger 已提交
811
static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp)
A
Alessandro Rubini 已提交
812 813 814 815 816 817 818
{
	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
/**
 * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
 * drop others.
 *
 * @parma ip	IP packet containing the ICMP
 */
J
Joe Hershberger 已提交
826
static void receive_icmp(struct ip_udp_hdr *ip, int len,
827
			IPaddr_t src_ip, struct ethernet_hdr *et)
828
{
829
	struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
830 831 832 833 834 835 836 837

	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 已提交
838
	default:
839
#if defined(CONFIG_CMD_PING)
J
Joe Hershberger 已提交
840
		ping_receive(et, ip, len);
841
#endif
842
#ifdef CONFIG_CMD_TFTPPUT
843 844 845 846
		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));
847
#endif
848 849 850 851
		break;
	}
}

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

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

867 868
	NetRxPacket = inpkt;
	NetRxPacketLen = len;
869
	et = (struct ethernet_hdr *)inpkt;
870 871 872 873 874

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

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

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

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

	x = ntohs(et->et_protlen);

R
Robin Getz 已提交
896
	debug("packet received\n");
897

W
wdenk 已提交
898
	if (x < 1514) {
899
		struct e802_hdr *et802 = (struct e802_hdr *)et;
W
wdenk 已提交
900
		/*
901 902
		 *	Got a 802.2 packet.  Check the other protocol field.
		 *	XXX VLAN over 802.2+SNAP not implemented!
W
wdenk 已提交
903
		 */
904
		x = ntohs(et802->et_prot);
905

J
Joe Hershberger 已提交
906
		ip = (struct ip_udp_hdr *)(inpkt + E802_HDR_SIZE);
W
wdenk 已提交
907
		len -= E802_HDR_SIZE;
908 909

	} else if (x != PROT_VLAN) {	/* normal packet */
J
Joe Hershberger 已提交
910
		ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE);
W
wdenk 已提交
911
		len -= ETHER_HDR_SIZE;
912 913

	} else {			/* VLAN packet */
914 915
		struct vlan_ethernet_hdr *vet =
			(struct vlan_ethernet_hdr *)et;
916

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

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

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

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

J
Joe Hershberger 已提交
935
		ip = (struct ip_udp_hdr *)(inpkt + VLAN_ETHER_HDR_SIZE);
936
		len -= VLAN_ETHER_HDR_SIZE;
W
wdenk 已提交
937 938
	}

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

941
#if defined(CONFIG_CMD_CDP)
942 943 944 945 946 947 948 949 950 951 952 953 954 955
	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 已提交
956 957 958
	switch (x) {

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

962
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
963
	case PROT_RARP:
964
		rarp_receive(ip, len);
W
wdenk 已提交
965
		break;
966
#endif
W
wdenk 已提交
967
	case PROT_IP:
R
Robin Getz 已提交
968
		debug("Got IP\n");
A
Alessandro Rubini 已提交
969
		/* Before we start poking the header, make sure it is there */
J
Joe Hershberger 已提交
970 971 972
		if (len < IP_UDP_HDR_SIZE) {
			debug("len bad %d < %lu\n", len,
				(ulong)IP_UDP_HDR_SIZE);
W
wdenk 已提交
973 974
			return;
		}
A
Alessandro Rubini 已提交
975
		/* Check the packet length */
W
wdenk 已提交
976 977 978 979 980
		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 已提交
981 982
		debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);

A
Alessandro Rubini 已提交
983
		/* Can't deal with anything except IPv4 */
984
		if ((ip->ip_hl_v & 0xf0) != 0x40)
W
wdenk 已提交
985
			return;
A
Alessandro Rubini 已提交
986
		/* Can't deal with IP options (headers != 20 bytes) */
987
		if ((ip->ip_hl_v & 0x0f) > 0x05)
988
			return;
A
Alessandro Rubini 已提交
989
		/* Check the Checksum of the header */
990
		if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE / 2)) {
991
			puts("checksum bad\n");
W
wdenk 已提交
992 993
			return;
		}
A
Alessandro Rubini 已提交
994
		/* If it is not for us, ignore it */
W
wdenk 已提交
995 996
		tmp = NetReadIP(&ip->ip_dst);
		if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
D
David Updegraff 已提交
997
#ifdef CONFIG_MCAST_TFTP
998
			if (Mcast_addr != tmp)
D
David Updegraff 已提交
999
#endif
1000
				return;
W
wdenk 已提交
1001
		}
1002 1003
		/* Read source IP address for later use */
		src_ip = NetReadIP(&ip->ip_src);
A
Alessandro Rubini 已提交
1004 1005 1006 1007 1008
		/*
		 * 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)
		 */
1009 1010
		ip = NetDefragment(ip, &len);
		if (!ip)
A
Alessandro Rubini 已提交
1011
			return;
W
wdenk 已提交
1012 1013 1014
		/*
		 * watch for ICMP host redirects
		 *
W
wdenk 已提交
1015 1016 1017 1018 1019
		 * 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 已提交
1020
		 *
W
wdenk 已提交
1021 1022 1023 1024 1025 1026 1027
		 * 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.
1028 1029 1030 1031
		 *
		 * 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 已提交
1032 1033
		 */
		if (ip->ip_p == IPPROTO_ICMP) {
1034 1035
			receive_icmp(ip, len, src_ip, et);
			return;
W
wdenk 已提交
1036 1037 1038 1039
		} else if (ip->ip_p != IPPROTO_UDP) {	/* Only UDP packets */
			return;
		}

1040 1041
#ifdef CONFIG_UDP_CHECKSUM
		if (ip->udp_xsum != 0) {
W
Wolfgang Denk 已提交
1042
			ulong   xsum;
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
			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 已提交
1057
				ushort sumdata;
1058 1059 1060 1061 1062 1063

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

				sumdata = *(unsigned char *) sumptr;
W
Wolfgang Denk 已提交
1067
				sumdata = (sumdata << 8) & 0xff00;
1068 1069 1070
				xsum += sumdata;
			}
			while ((xsum >> 16) != 0) {
1071 1072
				xsum = (xsum & 0x0000ffff) +
				       ((xsum >> 16) & 0x0000ffff);
1073 1074
			}
			if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
1075 1076
				printf(" UDP wrong checksum %08lx %08x\n",
					xsum, ntohs(ip->udp_xsum));
1077 1078 1079 1080 1081
				return;
			}
		}
#endif

D
David Updegraff 已提交
1082

1083
#ifdef CONFIG_NETCONSOLE
J
Joe Hershberger 已提交
1084 1085 1086 1087
		nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
					ntohs(ip->udp_dst),
					ntohs(ip->udp_src),
					ntohs(ip->udp_len) - UDP_HDR_SIZE);
1088
#endif
W
wdenk 已提交
1089 1090 1091
		/*
		 *	IP header OK.  Pass the packet to the current handler.
		 */
J
Joe Hershberger 已提交
1092 1093 1094 1095 1096
		(*packetHandler)((uchar *)ip + IP_UDP_HDR_SIZE,
					ntohs(ip->udp_dst),
					src_ip,
					ntohs(ip->udp_src),
					ntohs(ip->udp_len) - UDP_HDR_SIZE);
W
wdenk 已提交
1097 1098 1099 1100 1101 1102 1103
		break;
	}
}


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

S
Simon Glass 已提交
1104
static int net_check_prereq(enum proto_t protocol)
W
wdenk 已提交
1105 1106
{
	switch (protocol) {
W
wdenk 已提交
1107
		/* Fall through */
1108
#if defined(CONFIG_CMD_PING)
W
wdenk 已提交
1109
	case PING:
W
wdenk 已提交
1110
		if (NetPingIP == 0) {
1111
			puts("*** ERROR: ping address not given\n");
1112
			return 1;
W
wdenk 已提交
1113 1114
		}
		goto common;
W
wdenk 已提交
1115
#endif
1116
#if defined(CONFIG_CMD_SNTP)
W
wdenk 已提交
1117 1118
	case SNTP:
		if (NetNtpServerIP == 0) {
1119
			puts("*** ERROR: NTP server address not given\n");
1120
			return 1;
W
wdenk 已提交
1121 1122 1123
		}
		goto common;
#endif
R
Robin Getz 已提交
1124 1125 1126 1127 1128 1129 1130 1131
#if defined(CONFIG_CMD_DNS)
	case DNS:
		if (NetOurDNSIP == 0) {
			puts("*** ERROR: DNS server address not given\n");
			return 1;
		}
		goto common;
#endif
1132
#if defined(CONFIG_CMD_NFS)
W
wdenk 已提交
1133
	case NFS:
W
wdenk 已提交
1134
#endif
S
Simon Glass 已提交
1135
	case TFTPGET:
S
Simon Glass 已提交
1136
	case TFTPPUT:
W
wdenk 已提交
1137
		if (NetServerIP == 0) {
1138
			puts("*** ERROR: `serverip' not set\n");
1139
			return 1;
W
wdenk 已提交
1140
		}
1141 1142 1143
#if	defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
	defined(CONFIG_CMD_DNS)
common:
W
wdenk 已提交
1144
#endif
1145
		/* Fall through */
W
wdenk 已提交
1146

1147
	case NETCONS:
L
Luca Ceresoli 已提交
1148
	case TFTPSRV:
W
wdenk 已提交
1149
		if (NetOurIP == 0) {
1150
			puts("*** ERROR: `ipaddr' not set\n");
1151
			return 1;
W
wdenk 已提交
1152 1153
		}
		/* Fall through */
W
wdenk 已提交
1154

1155
#ifdef CONFIG_CMD_RARP
W
wdenk 已提交
1156
	case RARP:
1157
#endif
W
wdenk 已提交
1158
	case BOOTP:
1159
	case CDP:
1160
	case DHCP:
1161 1162
		if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
			int num = eth_get_dev_index();
W
wdenk 已提交
1163

W
wdenk 已提交
1164 1165
			switch (num) {
			case -1:
1166
				puts("*** ERROR: No ethernet found.\n");
1167
				return 1;
W
wdenk 已提交
1168
			case 0:
1169
				puts("*** ERROR: `ethaddr' not set\n");
W
wdenk 已提交
1170
				break;
W
wdenk 已提交
1171
			default:
1172
				printf("*** ERROR: `eth%daddr' not set\n",
W
wdenk 已提交
1173 1174
					num);
				break;
W
wdenk 已提交
1175
			}
W
wdenk 已提交
1176

1177
			NetStartAgain();
1178
			return 2;
W
wdenk 已提交
1179 1180 1181
		}
		/* Fall through */
	default:
1182
		return 0;
W
wdenk 已提交
1183
	}
1184
	return 0;		/* OK */
W
wdenk 已提交
1185 1186 1187 1188
}
/**********************************************************************/

int
1189
NetCksumOk(uchar *ptr, int len)
W
wdenk 已提交
1190 1191 1192 1193 1194 1195
{
	return !((NetCksum(ptr, len) + 1) & 0xfffe);
}


unsigned
1196
NetCksum(uchar *ptr, int len)
W
wdenk 已提交
1197 1198
{
	ulong	xsum;
1199
	ushort *p = (ushort *)ptr;
W
wdenk 已提交
1200 1201 1202

	xsum = 0;
	while (len-- > 0)
W
Wolfgang Denk 已提交
1203
		xsum += *p++;
W
wdenk 已提交
1204 1205
	xsum = (xsum & 0xffff) + (xsum >> 16);
	xsum = (xsum & 0xffff) + (xsum >> 16);
1206
	return xsum & 0xffff;
W
wdenk 已提交
1207 1208
}

1209 1210 1211 1212
int
NetEthHdrSize(void)
{
	ushort myvlanid;
W
wdenk 已提交
1213

1214 1215 1216 1217
	myvlanid = ntohs(NetOurVLAN);
	if (myvlanid == (ushort)-1)
		myvlanid = VLAN_NONE;

1218 1219
	return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
		VLAN_ETHER_HDR_SIZE;
1220 1221 1222
}

int
1223
NetSetEther(uchar *xet, uchar * addr, uint prot)
W
wdenk 已提交
1224
{
1225
	struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
1226 1227 1228 1229 1230
	ushort myvlanid;

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

1232 1233
	memcpy(et->et_dest, addr, 6);
	memcpy(et->et_src, NetOurEther, 6);
1234
	if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
1235
		et->et_protlen = htons(prot);
1236 1237
		return ETHER_HDR_SIZE;
	} else {
1238 1239
		struct vlan_ethernet_hdr *vet =
			(struct vlan_ethernet_hdr *)xet;
W
wdenk 已提交
1240

1241 1242 1243 1244 1245 1246
		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 已提交
1247

J
Joe Hershberger 已提交
1248
void NetSetIP(uchar *xip, IPaddr_t dest, int dport, int sport, int len)
W
wdenk 已提交
1249
{
J
Joe Hershberger 已提交
1250
	struct ip_udp_hdr *ip = (struct ip_udp_hdr *)xip;
W
wdenk 已提交
1251 1252 1253 1254 1255 1256 1257

	/*
	 *	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)
J
Joe Hershberger 已提交
1258
		xip[IP_UDP_HDR_SIZE + len] = 0;
W
wdenk 已提交
1259 1260 1261

	/*
	 *	Construct an IP and UDP header.
W
wdenk 已提交
1262
	 *	(need to set no fragment bit - XXX)
W
wdenk 已提交
1263
	 */
1264 1265
	/* IP_HDR_SIZE / 4 (not including UDP) */
	ip->ip_hl_v  = 0x45;
W
wdenk 已提交
1266
	ip->ip_tos   = 0;
J
Joe Hershberger 已提交
1267
	ip->ip_len   = htons(IP_UDP_HDR_SIZE + len);
W
wdenk 已提交
1268
	ip->ip_id    = htons(NetIPID++);
P
Peter Tyser 已提交
1269
	ip->ip_off   = htons(IP_FLAGS_DFRAG);	/* Don't fragment */
W
wdenk 已提交
1270 1271 1272
	ip->ip_ttl   = 255;
	ip->ip_p     = 17;		/* UDP */
	ip->ip_sum   = 0;
1273
	/* already in network byte order */
1274
	NetCopyIP((void *)&ip->ip_src, &NetOurIP);
1275
	/* - "" - */
1276
	NetCopyIP((void *)&ip->ip_dst, &dest);
W
wdenk 已提交
1277 1278
	ip->udp_src  = htons(sport);
	ip->udp_dst  = htons(dport);
J
Joe Hershberger 已提交
1279
	ip->udp_len  = htons(UDP_HDR_SIZE + len);
W
wdenk 已提交
1280
	ip->udp_xsum = 0;
1281
	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE / 2);
W
wdenk 已提交
1282 1283
}

1284
void copy_filename(char *dst, const char *src, int size)
W
wdenk 已提交
1285 1286 1287 1288 1289 1290
{
	if (*src && (*src == '"')) {
		++src;
		--size;
	}

1291
	while ((--size > 0) && *src && (*src != '"'))
W
wdenk 已提交
1292 1293 1294 1295
		*dst++ = *src++;
	*dst = '\0';
}

1296 1297 1298
#if	defined(CONFIG_CMD_NFS)		|| \
	defined(CONFIG_CMD_SNTP)	|| \
	defined(CONFIG_CMD_DNS)
R
Robin Getz 已提交
1299
/*
1300 1301 1302
 * 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 已提交
1303 1304 1305
 */
unsigned int random_port(void)
{
1306
	return 1024 + (get_timer(0) % 0x4000);
R
Robin Getz 已提交
1307 1308 1309
}
#endif

1310
void ip_to_string(IPaddr_t x, char *s)
W
wdenk 已提交
1311
{
1312 1313 1314 1315 1316
	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 已提交
1317
	);
W
wdenk 已提交
1318 1319
}

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
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);
}

1333
ushort string_to_VLAN(const char *s)
1334 1335 1336 1337
{
	ushort id;

	if (s == NULL)
W
wdenk 已提交
1338
		return htons(VLAN_NONE);
1339 1340 1341 1342 1343 1344

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

W
wdenk 已提交
1345
	return htons(id);
1346 1347 1348 1349
}

ushort getenv_VLAN(char *var)
{
1350
	return string_to_VLAN(getenv(var));
1351
}