bootp.c 21.8 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7
/*
 *	Based on LiMon - BOOTP.
 *
 *	Copyright 1994, 1995, 2000 Neil Russell.
 *	(See License)
 *	Copyright 2000 Roland Borde
 *	Copyright 2000 Paolo Scaffardi
8
 *	Copyright 2000-2004 Wolfgang Denk, wd@denx.de
W
wdenk 已提交
9 10 11
 */

#if 0
12 13
#define DEBUG		1	/* general debug */
#define DEBUG_BOOTP_EXT 1	/* Debug received vendor fields */
W
wdenk 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26
#endif

#ifdef DEBUG_BOOTP_EXT
#define debug_ext(fmt,args...)	printf (fmt ,##args)
#else
#define debug_ext(fmt,args...)
#endif

#include <common.h>
#include <command.h>
#include <net.h>
#include "bootp.h"
#include "tftp.h"
27
#include "nfs.h"
W
wdenk 已提交
28 29 30 31
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#endif

32
#define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie		*/
W
wdenk 已提交
33 34 35 36

#if (CONFIG_COMMANDS & CFG_CMD_NET)

#define TIMEOUT		5		/* Seconds before trying BOOTP again	*/
37
#ifndef CONFIG_NET_RETRY_COUNT
W
wdenk 已提交
38 39
# define TIMEOUT_COUNT	5		/* # of timeouts before giving up  */
#else
40
# define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
W
wdenk 已提交
41 42 43 44 45 46
#endif

#define PORT_BOOTPS	67		/* BOOTP server UDP port		*/
#define PORT_BOOTPC	68		/* BOOTP client UDP port		*/

#ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list	*/
47
#define CONFIG_DHCP_MIN_EXT_LEN 64
W
wdenk 已提交
48 49 50 51 52 53 54 55 56 57
#endif

ulong		BootpID;
int		BootpTry;
#ifdef CONFIG_BOOTP_RANDOM_DELAY
ulong		seed1, seed2;
#endif

#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
dhcp_state_t dhcp_state = INIT;
58
unsigned long dhcp_leasetime = 0;
59
IPaddr_t NetDHCPServerIP = 0;
W
wdenk 已提交
60 61 62
static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);

/* For Debug */
W
wdenk 已提交
63 64
#if 0
static char *dhcpmsg2str(int type)
W
wdenk 已提交
65 66
{
	switch (type) {
67 68 69 70 71 72 73
	case 1:	 return "DHCPDISCOVER"; break;
	case 2:	 return "DHCPOFFER";	break;
	case 3:	 return "DHCPREQUEST";	break;
	case 4:	 return "DHCPDECLINE";	break;
	case 5:	 return "DHCPACK";	break;
	case 6:	 return "DHCPNACK";	break;
	case 7:	 return "DHCPRELEASE";	break;
W
wdenk 已提交
74 75 76
	default: return "UNKNOWN/INVALID MSG TYPE"; break;
	}
}
W
wdenk 已提交
77
#endif
W
wdenk 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
extern u8 *dhcp_vendorex_prep (u8 *e); /*rtn new e after add own opts. */
extern u8 *dhcp_vendorex_proc (u8 *e); /*rtn next e if mine,else NULL  */
#endif

#endif	/* CFG_CMD_DHCP */

static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
{
	Bootp_t *bp = (Bootp_t *) pkt;
	int retval = 0;

	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
		retval = -1;
	else if (len < sizeof (Bootp_t) - OPT_SIZE)
		retval = -2;
	else if (bp->bp_op != OP_BOOTREQUEST &&
	    bp->bp_op != OP_BOOTREPLY &&
	    bp->bp_op != DHCP_OFFER &&
	    bp->bp_op != DHCP_ACK &&
	    bp->bp_op != DHCP_NAK ) {
		retval = -3;
	}
	else if (bp->bp_htype != HWT_ETHER)
		retval = -4;
	else if (bp->bp_hlen != HWL_ETHER)
		retval = -5;
	else if (NetReadLong((ulong*)&bp->bp_id) != BootpID) {
		retval = -6;
	}

	debug ("Filtering pkt = %d\n", retval);

	return retval;
}

/*
 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
 */
W
wdenk 已提交
118
static void BootpCopyNetParams(Bootp_t *bp)
W
wdenk 已提交
119 120 121 122 123 124 125 126 127
{
	NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
	NetCopyIP(&NetServerIP, &bp->bp_siaddr);
	memcpy (NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
	copy_filename (BootFile, bp->bp_file, sizeof(BootFile));

	debug ("Bootfile: %s\n", BootFile);

	/* Propagate to environment:
W
wdenk 已提交
128
	 * don't delete exising entry when BOOTP / DHCP reply does
W
wdenk 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
	 * not contain a new value
	 */
	if (*BootFile) {
		setenv ("bootfile", BootFile);
	}
}

static int truncate_sz (const char *name, int maxlen, int curlen)
{
	if (curlen >= maxlen) {
		printf("*** WARNING: %s is too long (%d - max: %d) - truncated\n",
			name, curlen, maxlen);
		curlen = maxlen - 1;
	}
	return (curlen);
}

#if !(CONFIG_COMMANDS & CFG_CMD_DHCP)

148
static void BootpVendorFieldProcess (u8 * ext)
W
wdenk 已提交
149
{
150
	int size = *(ext + 1);
W
wdenk 已提交
151

152 153
	debug_ext ("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
		   *(ext + 1));
W
wdenk 已提交
154

155
	NetBootFileSize = 0;
W
wdenk 已提交
156

157 158 159
	switch (*ext) {
		/* Fixed length fields */
	case 1:			/* Subnet mask                                  */
W
wdenk 已提交
160
		if (NetOurSubnetMask == 0)
161
			NetCopyIP (&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
W
wdenk 已提交
162
		break;
163
	case 2:			/* Time offset - Not yet supported              */
W
wdenk 已提交
164
		break;
165 166
		/* Variable length fields */
	case 3:			/* Gateways list                                */
W
wdenk 已提交
167
		if (NetOurGatewayIP == 0) {
168
			NetCopyIP (&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
W
wdenk 已提交
169 170
		}
		break;
171
	case 4:			/* Time server - Not yet supported              */
W
wdenk 已提交
172
		break;
173
	case 5:			/* IEN-116 name server - Not yet supported      */
W
wdenk 已提交
174 175 176
		break;
	case 6:
		if (NetOurDNSIP == 0) {
177
			NetCopyIP (&NetOurDNSIP, (IPaddr_t *) (ext + 2));
W
wdenk 已提交
178
		}
179 180
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
		if ((NetOurDNS2IP == 0) && (size > 4)) {
181
			NetCopyIP (&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
182 183
		}
#endif
W
wdenk 已提交
184
		break;
185
	case 7:			/* Log server - Not yet supported               */
W
wdenk 已提交
186
		break;
187
	case 8:			/* Cookie/Quote server - Not yet supported      */
W
wdenk 已提交
188
		break;
189
	case 9:			/* LPR server - Not yet supported               */
W
wdenk 已提交
190
		break;
191
	case 10:		/* Impress server - Not yet supported           */
W
wdenk 已提交
192
		break;
193
	case 11:		/* RPL server - Not yet supported               */
W
wdenk 已提交
194
		break;
195
	case 12:		/* Host name                                    */
W
wdenk 已提交
196
		if (NetOurHostName[0] == 0) {
197 198 199
			size = truncate_sz ("Host Name", sizeof (NetOurHostName), size);
			memcpy (&NetOurHostName, ext + 2, size);
			NetOurHostName[size] = 0;
W
wdenk 已提交
200 201
		}
		break;
202
	case 13:		/* Boot file size                               */
W
wdenk 已提交
203
		if (size == 2)
204
			NetBootFileSize = ntohs (*(ushort *) (ext + 2));
W
wdenk 已提交
205
		else if (size == 4)
206
			NetBootFileSize = ntohl (*(ulong *) (ext + 2));
W
wdenk 已提交
207
		break;
208
	case 14:		/* Merit dump file - Not yet supported          */
W
wdenk 已提交
209
		break;
210
	case 15:		/* Domain name - Not yet supported              */
W
wdenk 已提交
211
		break;
212
	case 16:		/* Swap server - Not yet supported              */
W
wdenk 已提交
213
		break;
214
	case 17:		/* Root path                                    */
W
wdenk 已提交
215
		if (NetOurRootPath[0] == 0) {
216 217 218
			size = truncate_sz ("Root Path", sizeof (NetOurRootPath), size);
			memcpy (&NetOurRootPath, ext + 2, size);
			NetOurRootPath[size] = 0;
W
wdenk 已提交
219 220
		}
		break;
221
	case 18:		/* Extension path - Not yet supported           */
W
wdenk 已提交
222
		/*
W
wdenk 已提交
223 224 225
		 * This can be used to send the information of the
		 * vendor area in another file that the client can
		 * access via TFTP.
W
wdenk 已提交
226 227
		 */
		break;
228 229
		/* IP host layer fields */
	case 40:		/* NIS Domain name                              */
W
wdenk 已提交
230
		if (NetOurNISDomain[0] == 0) {
231 232 233
			size = truncate_sz ("NIS Domain Name", sizeof (NetOurNISDomain), size);
			memcpy (&NetOurNISDomain, ext + 2, size);
			NetOurNISDomain[size] = 0;
W
wdenk 已提交
234 235
		}
		break;
236 237
		/* Application layer fields */
	case 43:		/* Vendor specific info - Not yet supported     */
W
wdenk 已提交
238
		/*
W
wdenk 已提交
239 240
		 * Binary information to exchange specific
		 * product information.
W
wdenk 已提交
241 242
		 */
		break;
243 244
		/* Reserved (custom) fields (128..254) */
	}
W
wdenk 已提交
245 246
}

247
static void BootpVendorProcess (u8 * ext, int size)
W
wdenk 已提交
248
{
249
	u8 *end = ext + size;
W
wdenk 已提交
250

251
	debug_ext ("[BOOTP] Checking extension (%d bytes)...\n", size);
W
wdenk 已提交
252

253 254 255 256 257 258 259 260 261 262
	while ((ext < end) && (*ext != 0xff)) {
		if (*ext == 0) {
			ext++;
		} else {
			u8 *opt = ext;

			ext += ext[1] + 2;
			if (ext <= end)
				BootpVendorFieldProcess (opt);
		}
W
wdenk 已提交
263 264 265
	}

#ifdef DEBUG_BOOTP_EXT
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
	printf ("[BOOTP] Received fields: \n");
	if (NetOurSubnetMask) {
		puts ("NetOurSubnetMask : ");
		print_IPaddr (NetOurSubnetMask);
		putc ('\n');
	}

	if (NetOurGatewayIP) {
		puts ("NetOurGatewayIP	: ");
		print_IPaddr (NetOurGatewayIP);
		putc ('\n');
	}

	if (NetBootFileSize) {
		printf ("NetBootFileSize : %d\n", NetBootFileSize);
	}
W
wdenk 已提交
282

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	if (NetOurHostName[0]) {
		printf ("NetOurHostName  : %s\n", NetOurHostName);
	}

	if (NetOurRootPath[0]) {
		printf ("NetOurRootPath  : %s\n", NetOurRootPath);
	}

	if (NetOurNISDomain[0]) {
		printf ("NetOurNISDomain : %s\n", NetOurNISDomain);
	}

	if (NetBootFileSize) {
		printf ("NetBootFileSize: %d\n", NetBootFileSize);
	}
#endif /* DEBUG_BOOTP_EXT */
}
W
wdenk 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313
/*
 *	Handle a BOOTP received packet.
 */
static void
BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
{
	Bootp_t *bp;
	char	*s;

	debug ("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%d)\n",
		src, dest, len, sizeof (Bootp_t));

	bp = (Bootp_t *)pkt;

314
	if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
W
wdenk 已提交
315 316 317
		return;

	/*
318
	 *	Got a good BOOTP reply.	 Copy the data into our variables.
W
wdenk 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
	 */
#ifdef CONFIG_STATUS_LED
	status_led_set (STATUS_LED_BOOT, STATUS_LED_OFF);
#endif

	BootpCopyNetParams(bp);		/* Store net parameters from reply */

	/* Retrieve extended information (we must parse the vendor area) */
	if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
		BootpVendorProcess(&bp->bp_vend[4], len);

	NetSetTimeout(0, (thand_f *)0);

	debug ("Got good BOOTP\n");

W
wdenk 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	if ((s = getenv("autoload")) != NULL) {
		if (*s == 'n') {
			/*
			 * Just use BOOTP to configure system;
			 * Do not use TFTP to load the bootfile.
			 */
			NetState = NETLOOP_SUCCESS;
			return;
		} else if (strcmp(s, "NFS") == 0) {
			/*
			 * Use NFS to load the bootfile.
			 */
			NfsStart();
			return;
		}
W
wdenk 已提交
349 350
	}

W
wdenk 已提交
351
	TftpStart();
W
wdenk 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
}
#endif	/* !CFG_CMD_DHCP */

/*
 *	Timeout on BOOTP/DHCP request.
 */
static void
BootpTimeout(void)
{
	if (BootpTry >= TIMEOUT_COUNT) {
		puts ("\nRetry count exceeded; starting again\n");
		NetStartAgain ();
	} else {
		NetSetTimeout (TIMEOUT * CFG_HZ, BootpTimeout);
		BootpRequest ();
	}
}

/*
 *	Initialize BOOTP extension fields in the request.
 */
#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
374
static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
W
wdenk 已提交
375
{
376 377 378
	u8 *start = e;
	u8 *cnt;

W
wdenk 已提交
379
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
380
	u8 *x;
W
wdenk 已提交
381
#endif
382
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
383
	uchar *hostname;
384
#endif
W
wdenk 已提交
385

386 387 388 389
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
W
wdenk 已提交
390

391 392 393
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = message_type;
W
wdenk 已提交
394

395 396 397 398
	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
	*e++ = (576 - 312 + OPT_SIZE) >> 8;
	*e++ = (576 - 312 + OPT_SIZE) & 0xff;
W
wdenk 已提交
399

400 401
	if (ServerID) {
		int tmp = ntohl (ServerID);
W
wdenk 已提交
402

403 404 405 406 407 408 409
		*e++ = 54;	/* ServerID */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
W
wdenk 已提交
410

411 412
	if (RequestedIP) {
		int tmp = ntohl (RequestedIP);
W
wdenk 已提交
413

414 415 416 417 418 419 420
		*e++ = 50;	/* Requested IP */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
421
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME)
422 423 424 425 426 427 428 429
	if ((hostname = getenv ("hostname"))) {
		int hostnamelen = strlen (hostname);

		*e++ = 12;	/* Hostname */
		*e++ = hostnamelen;
		memcpy (e, hostname, hostnamelen);
		e += hostnamelen;
	}
430 431
#endif

W
wdenk 已提交
432
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
433 434
	if ((x = dhcp_vendorex_prep (e)))
		return x - start;
W
wdenk 已提交
435 436
#endif

437 438 439
	*e++ = 55;		/* Parameter Request List */
	 cnt = e++;		/* Pointer to count of requested items */
	*cnt = 0;
W
wdenk 已提交
440
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
441 442
	*e++  = 1;		/* Subnet Mask */
	*cnt += 1;
W
wdenk 已提交
443 444
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
445 446
	*e++  = 3;		/* Router Option */
	*cnt += 1;
W
wdenk 已提交
447 448
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
449 450
	*e++  = 6;		/* DNS Server(s) */
	*cnt += 1;
W
wdenk 已提交
451 452
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
453 454
	*e++  = 12;		/* Hostname */
	*cnt += 1;
W
wdenk 已提交
455 456
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
457 458
	*e++  = 13;		/* Boot File Size */
	*cnt += 1;
W
wdenk 已提交
459 460
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
461 462
	*e++  = 17;		/* Boot path */
	*cnt += 1;
W
wdenk 已提交
463 464
#endif
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
465 466
	*e++  = 40;		/* NIS Domain name request */
	*cnt += 1;
W
wdenk 已提交
467
#endif
468
	*e++  = 255;		/* End of the list */
W
wdenk 已提交
469

470
	/* Pad to minimal length */
W
wdenk 已提交
471
#ifdef	CONFIG_DHCP_MIN_EXT_LEN
472 473
	while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN)
		*e++ = 0;
W
wdenk 已提交
474 475
#endif

476
	return e - start;
W
wdenk 已提交
477 478 479 480 481 482
}

#else	/* CFG_CMD_DHCP */
/*
 *	Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!
 */
483
static int BootpExtended (u8 * e)
W
wdenk 已提交
484
{
485
	u8 *start = e;
W
wdenk 已提交
486

487 488 489 490
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
W
wdenk 已提交
491 492

#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
493 494 495 496 497 498 499 500 501
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = DHCP_DISCOVER;

	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
	*e++ = (576 - 312 + OPT_SIZE) >> 16;
	*e++ = (576 - 312 + OPT_SIZE) & 0xff;
#endif /* CFG_CMD_DHCP */
W
wdenk 已提交
502 503

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK)
504 505 506
	*e++ = 1;		/* Subnet mask request */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
507 508 509
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY)
510 511 512
	*e++ = 3;		/* Default gateway request */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
513 514 515
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS)
516 517 518
	*e++ = 6;		/* Domain Name Server */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
519 520 521
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME)
522 523 524
	*e++ = 12;		/* Host name request */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
525 526 527
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE)
528 529 530
	*e++ = 13;		/* Boot file size */
	*e++ = 2;
	e   += 2;
W
wdenk 已提交
531 532 533
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH)
534 535 536
	*e++ = 17;		/* Boot path */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
537 538 539
#endif

#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN)
540 541 542
	*e++ = 40;		/* NIS Domain name request */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
543 544
#endif

545
	*e++ = 255;		/* End of the list */
W
wdenk 已提交
546

547
	return e - start;
W
wdenk 已提交
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
}
#endif	/* CFG_CMD_DHCP */

void
BootpRequest (void)
{
	volatile uchar *pkt, *iphdr;
	Bootp_t *bp;
	int ext_len, pktlen, iplen;

#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
	dhcp_state = INIT;
#endif

#ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
	unsigned char bi_enetaddr[6];
	int   reg;
	char  *e,*s;
	uchar tmp[64];
	ulong tst1, tst2, sum, m_mask, m_value = 0;

	if (BootpTry ==0) {
		/* get our mac */
		reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
		s = (reg > 0) ? tmp : NULL;

		for (reg=0; reg<6; ++reg) {
			bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
			if (s) {
				s = (*e) ? e+1 : e;
			}
		}
#ifdef DEBUG
		printf("BootpRequest => Our Mac: ");
		for (reg=0; reg<6; reg++) {
			printf ("%x%c",
				bi_enetaddr[reg],
				reg==5 ? '\n' : ':');
		}
#endif /* DEBUG */

		/* Mac-Manipulation 2 get seed1 */
		tst1=0;
		tst2=0;
		for (reg=2; reg<6; reg++) {
			tst1 = tst1 << 8;
			tst1 = tst1 | bi_enetaddr[reg];
		}
		for (reg=0; reg<2; reg++) {
			tst2 = tst2 | bi_enetaddr[reg];
			tst2 = tst2 << 8;
		}

		seed1 = tst1^tst2;

		/* Mirror seed1*/
		m_mask=0x1;
		for (reg=1;reg<=32;reg++) {
			m_value |= (m_mask & seed1);
			seed1 = seed1 >> 1;
			m_value = m_value << 1;
		}
		seed1 = m_value;
		seed2 = 0xB78D0945;
	}

	/* Random Number Generator */

	for (reg=0;reg<=0;reg++) {
		sum = seed1 + seed2;
		if (sum < seed1 || sum < seed2)
			sum++;
W
wdenk 已提交
620
		seed2 = seed1;
W
wdenk 已提交
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 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
		seed1 = sum;

		if (BootpTry<=2) {	/* Start with max 1024 * 1ms */
			sum = sum >> (22-BootpTry);
		} else {		/*After 3rd BOOTP request max 8192 * 1ms */
			sum = sum >> 19;
		}
	}

	printf ("Random delay: %ld ms...\n", sum);
	for (reg=0; reg <sum; reg++) {
		udelay(1000); /*Wait 1ms*/
	}
#endif	/* CONFIG_BOOTP_RANDOM_DELAY */

	printf("BOOTP broadcast %d\n", ++BootpTry);
	pkt = NetTxPacket;
	memset ((void*)pkt, 0, PKTSIZE);

	NetSetEther(pkt, NetBcastAddr, PROT_IP);
	pkt += ETHER_HDR_SIZE;

	/*
	 * Next line results in incorrect packet size being transmitted, resulting
	 * in errors in some DHCP servers, reporting missing bytes.  Size must be
	 * set in packet header after extension length has been determined.
	 * C. Hallinan, DS4.COM, Inc.
	 */
	/* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
	iphdr = pkt;	/* We need this later for NetSetIP() */
	pkt += IP_HDR_SIZE;

	bp = (Bootp_t *)pkt;
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
	bp->bp_secs = htons(get_timer(0) / CFG_HZ);
	NetWriteIP(&bp->bp_ciaddr, 0);
	NetWriteIP(&bp->bp_yiaddr, 0);
	NetWriteIP(&bp->bp_siaddr, 0);
	NetWriteIP(&bp->bp_giaddr, 0);
	memcpy (bp->bp_chaddr, NetOurEther, 6);
	copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));

	/* Request additional information from the BOOTP/DHCP server */
#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
	ext_len = DhcpExtended(bp->bp_vend, DHCP_DISCOVER, 0, 0);
#else
	ext_len = BootpExtended(bp->bp_vend);
#endif	/* CFG_CMD_DHCP */

	/*
	 *	Bootp ID is the lower 4 bytes of our ethernet address
	 *	plus the current time in HZ.
	 */
	BootpID = ((ulong)NetOurEther[2] << 24)
		| ((ulong)NetOurEther[3] << 16)
		| ((ulong)NetOurEther[4] << 8)
		| (ulong)NetOurEther[5];
	BootpID += get_timer(0);
682
	BootpID	 = htonl(BootpID);
W
wdenk 已提交
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	NetCopyLong(&bp->bp_id, &BootpID);

	/*
	 * Calculate proper packet lengths taking into account the
	 * variable size of the options field
	 */
	pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len;
	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
	NetSetTimeout(SELECT_TIMEOUT * CFG_HZ, BootpTimeout);

#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
	dhcp_state = SELECTING;
	NetSetHandler(DhcpHandler);
#else
	NetSetHandler(BootpHandler);
#endif	/* CFG_CMD_DHCP */
	NetSendPacket(NetTxPacket, pktlen);
}

#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
704
static void DhcpOptionsProcess (uchar * popt)
W
wdenk 已提交
705
{
W
wdenk 已提交
706
	uchar *end = popt + BOOTP_HDR_SIZE;
W
wdenk 已提交
707 708
	int oplen, size;

709
	while (popt < end && *popt != 0xff) {
W
wdenk 已提交
710
		oplen = *(popt + 1);
711 712 713 714 715 716 717 718 719
		switch (*popt) {
		case 1:
			NetCopyIP (&NetOurSubnetMask, (popt + 2));
			break;
		case 3:
			NetCopyIP (&NetOurGatewayIP, (popt + 2));
			break;
		case 6:
			NetCopyIP (&NetOurDNSIP, (popt + 2));
720
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
721 722 723
			if (*(popt + 1) > 4) {
				NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4));
			}
724
#endif
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
			break;
		case 12:
			size = truncate_sz ("Host Name", sizeof (NetOurHostName), oplen);
			memcpy (&NetOurHostName, popt + 2, size);
			NetOurHostName[size] = 0;
			break;
		case 15:	/* Ignore Domain Name Option */
			break;
		case 17:
			size = truncate_sz ("Root Path", sizeof (NetOurRootPath), oplen);
			memcpy (&NetOurRootPath, popt + 2, size);
			NetOurRootPath[size] = 0;
			break;
		case 51:
			NetCopyLong (&dhcp_leasetime, (ulong *) (popt + 2));
			break;
		case 53:	/* Ignore Message Type Option */
			break;
		case 54:
			NetCopyIP (&NetDHCPServerIP, (popt + 2));
			break;
		case 58:	/* Ignore Renewal Time Option */
			break;
		case 59:	/* Ignore Rebinding Time Option */
			break;
		default:
W
wdenk 已提交
751
#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX)
752
			if (dhcp_vendorex_proc (popt))
W
wdenk 已提交
753
				break;
W
wdenk 已提交
754
#endif
755 756
			printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt);
			break;
W
wdenk 已提交
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
		}
		popt += oplen + 2;	/* Process next option */
	}
}

static int DhcpMessageType(unsigned char *popt)
{
	if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
		return -1;

	popt += 4;
	while ( *popt != 0xff ) {
		if ( *popt == 53 )	/* DHCP Message Type */
			return *(popt + 2);
		popt += *(popt + 1) + 2;	/* Scan through all options */
	}
	return -1;
}

W
wdenk 已提交
776
static void DhcpSendRequestPkt(Bootp_t *bp_offer)
W
wdenk 已提交
777 778 779 780
{
	volatile uchar *pkt, *iphdr;
	Bootp_t *bp;
	int pktlen, iplen, extlen;
781
	IPaddr_t OfferedIP;
W
wdenk 已提交
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

	debug ("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
	pkt = NetTxPacket;
	memset ((void*)pkt, 0, PKTSIZE);

	NetSetEther(pkt, NetBcastAddr, PROT_IP);
	pkt += ETHER_HDR_SIZE;

	iphdr = pkt;		/* We'll need this later to set proper pkt size */
	pkt += IP_HDR_SIZE;

	bp = (Bootp_t *)pkt;
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
	bp->bp_secs = htons(get_timer(0) / CFG_HZ);
	NetCopyIP(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */
	NetCopyIP(&bp->bp_yiaddr, &bp_offer->bp_yiaddr);
	NetCopyIP(&bp->bp_siaddr, &bp_offer->bp_siaddr);
	NetCopyIP(&bp->bp_giaddr, &bp_offer->bp_giaddr);
	memcpy (bp->bp_chaddr, NetOurEther, 6);

	/*
	 * ID is the id of the OFFER packet
	 */

	NetCopyLong(&bp->bp_id, &bp_offer->bp_id);

	/*
	 * Copy options from OFFER packet if present
	 */
814
	NetCopyIP(&OfferedIP, &bp->bp_yiaddr);
815
	extlen = DhcpExtended(bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
W
wdenk 已提交
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835

	pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen;
	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);

	debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
	NetSendPacket(NetTxPacket, pktlen);
}

/*
 *	Handle DHCP received packets.
 */
static void
DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
{
	Bootp_t *bp = (Bootp_t *)pkt;

	debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
		src, dest, len, dhcp_state);

836
	if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
W
wdenk 已提交
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
		return;

	debug ("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
		src, dest, len, dhcp_state);

	switch (dhcp_state) {
	case SELECTING:
		/*
		 * Wait an appropriate time for any potential DHCPOFFER packets
		 * to arrive.  Then select one, and generate DHCPREQUEST response.
		 * If filename is in format we recognize, assume it is a valid
		 * OFFER from a server we want.
		 */
		debug ("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
#ifdef CFG_BOOTFILE_PREFIX
		if (strncmp(bp->bp_file,
			    CFG_BOOTFILE_PREFIX,
			    strlen(CFG_BOOTFILE_PREFIX)) == 0 ) {
#endif	/* CFG_BOOTFILE_PREFIX */

			debug ("TRANSITIONING TO REQUESTING STATE\n");
			dhcp_state = REQUESTING;
859

W
wdenk 已提交
860 861 862
			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
				DhcpOptionsProcess(&bp->bp_vend[4]);

863
			BootpCopyNetParams(bp); /* Store net params from reply */
W
wdenk 已提交
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

			NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);
			DhcpSendRequestPkt(bp);
#ifdef CFG_BOOTFILE_PREFIX
		}
#endif	/* CFG_BOOTFILE_PREFIX */

		return;
		break;
	case REQUESTING:
		debug ("DHCP State: REQUESTING\n");

		if ( DhcpMessageType(bp->bp_vend) == DHCP_ACK ) {
			char *s;

			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
				DhcpOptionsProcess(&bp->bp_vend[4]);
881
			BootpCopyNetParams(bp); /* Store net params from reply */
W
wdenk 已提交
882 883 884 885 886 887
			dhcp_state = BOUND;
			printf("DHCP client bound to address ");
			print_IPaddr(NetOurIP);
			printf("\n");

			/* Obey the 'autoload' setting */
W
wdenk 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
			if ((s = getenv("autoload")) != NULL) {
				if (*s == 'n') {
					/*
					 * Just use BOOTP to configure system;
					 * Do not use TFTP to load the bootfile.
					 */
					NetState = NETLOOP_SUCCESS;
					return;
				} else if (strcmp(s, "NFS") == 0) {
					/*
					 * Use NFS to load the bootfile.
					 */
					NfsStart();
					return;
				}
W
wdenk 已提交
903
			}
W
wdenk 已提交
904
			TftpStart();
W
wdenk 已提交
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
			return;
		}
		break;
	default:
		printf("DHCP: INVALID STATE\n");
		break;
	}

}

void DhcpRequest(void)
{
	BootpRequest();
}
#endif	/* CFG_CMD_DHCP */

#endif /* CFG_CMD_NET */