bootp.c 22.1 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 12 13 14
 */

#include <common.h>
#include <command.h>
#include <net.h>
#include "bootp.h"
15
#include "net_rand.h"
W
wdenk 已提交
16
#include "tftp.h"
17
#include "nfs.h"
W
wdenk 已提交
18 19 20
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#endif
21
#include <linux/compiler.h>
W
wdenk 已提交
22

23
#define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
W
wdenk 已提交
24

25
#define TIMEOUT		5000UL	/* Milliseconds before trying BOOTP again */
26
#ifndef CONFIG_NET_RETRY_COUNT
27
# define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
W
wdenk 已提交
28
#else
29
# define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
W
wdenk 已提交
30 31
#endif

32 33
#define PORT_BOOTPS	67		/* BOOTP server UDP port */
#define PORT_BOOTPC	68		/* BOOTP client UDP port */
W
wdenk 已提交
34

35
#ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list */
36
#define CONFIG_DHCP_MIN_EXT_LEN 64
W
wdenk 已提交
37 38 39 40 41
#endif

ulong		BootpID;
int		BootpTry;

42
#if defined(CONFIG_CMD_DHCP)
W
wdenk 已提交
43
dhcp_state_t dhcp_state = INIT;
44 45
unsigned long dhcp_leasetime;
IPaddr_t NetDHCPServerIP;
46 47
static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
			unsigned len);
W
wdenk 已提交
48 49

/* For Debug */
W
wdenk 已提交
50 51
#if 0
static char *dhcpmsg2str(int type)
W
wdenk 已提交
52 53
{
	switch (type) {
54 55 56 57 58 59 60
	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 已提交
61 62 63
	default: return "UNKNOWN/INVALID MSG TYPE"; break;
	}
}
W
wdenk 已提交
64
#endif
65
#endif
W
wdenk 已提交
66 67 68

static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
{
69
	struct Bootp_t *bp = (struct Bootp_t *) pkt;
W
wdenk 已提交
70 71 72 73
	int retval = 0;

	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
		retval = -1;
74
	else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE)
W
wdenk 已提交
75 76
		retval = -2;
	else if (bp->bp_op != OP_BOOTREQUEST &&
77 78 79 80
			bp->bp_op != OP_BOOTREPLY &&
			bp->bp_op != DHCP_OFFER &&
			bp->bp_op != DHCP_ACK &&
			bp->bp_op != DHCP_NAK)
W
wdenk 已提交
81 82 83 84 85
		retval = -3;
	else if (bp->bp_htype != HWT_ETHER)
		retval = -4;
	else if (bp->bp_hlen != HWL_ETHER)
		retval = -5;
86
	else if (NetReadLong((ulong *)&bp->bp_id) != BootpID)
W
wdenk 已提交
87 88
		retval = -6;

R
Robin Getz 已提交
89
	debug("Filtering pkt = %d\n", retval);
W
wdenk 已提交
90 91 92 93 94 95 96

	return retval;
}

/*
 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
 */
97
static void BootpCopyNetParams(struct Bootp_t *bp)
W
wdenk 已提交
98
{
99
	__maybe_unused IPaddr_t tmp_ip;
W
wdenk 已提交
100

W
wdenk 已提交
101
	NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
W
Wilson Callan 已提交
102
#if !defined(CONFIG_BOOTP_SERVERIP)
W
wdenk 已提交
103 104 105
	NetCopyIP(&tmp_ip, &bp->bp_siaddr);
	if (tmp_ip != 0)
		NetCopyIP(&NetServerIP, &bp->bp_siaddr);
106
	memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6);
W
Wilson Callan 已提交
107
#endif
W
wdenk 已提交
108
	if (strlen(bp->bp_file) > 0)
109
		copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
W
wdenk 已提交
110

R
Robin Getz 已提交
111
	debug("Bootfile: %s\n", BootFile);
W
wdenk 已提交
112 113

	/* Propagate to environment:
W
wdenk 已提交
114
	 * don't delete exising entry when BOOTP / DHCP reply does
W
wdenk 已提交
115 116
	 * not contain a new value
	 */
117 118
	if (*BootFile)
		setenv("bootfile", BootFile);
W
wdenk 已提交
119 120
}

121
static int truncate_sz(const char *name, int maxlen, int curlen)
W
wdenk 已提交
122 123
{
	if (curlen >= maxlen) {
124 125
		printf("*** WARNING: %s is too long (%d - max: %d)"
			" - truncated\n", name, curlen, maxlen);
W
wdenk 已提交
126 127
		curlen = maxlen - 1;
	}
128
	return curlen;
W
wdenk 已提交
129 130
}

131
#if !defined(CONFIG_CMD_DHCP)
W
wdenk 已提交
132

133
static void BootpVendorFieldProcess(u8 *ext)
W
wdenk 已提交
134
{
135
	int size = *(ext + 1);
W
wdenk 已提交
136

R
Robin Getz 已提交
137
	debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
138
		*(ext + 1));
W
wdenk 已提交
139

140
	NetBootFileSize = 0;
W
wdenk 已提交
141

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

237
static void BootpVendorProcess(u8 *ext, int size)
W
wdenk 已提交
238
{
239
	u8 *end = ext + size;
W
wdenk 已提交
240

R
Robin Getz 已提交
241
	debug("[BOOTP] Checking extension (%d bytes)...\n", size);
W
wdenk 已提交
242

243 244 245 246 247 248 249 250
	while ((ext < end) && (*ext != 0xff)) {
		if (*ext == 0) {
			ext++;
		} else {
			u8 *opt = ext;

			ext += ext[1] + 2;
			if (ext <= end)
251
				BootpVendorFieldProcess(opt);
252
		}
W
wdenk 已提交
253 254
	}

255
	debug("[BOOTP] Received fields:\n");
M
Mike Frysinger 已提交
256
	if (NetOurSubnetMask)
R
Robin Getz 已提交
257
		debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
258

M
Mike Frysinger 已提交
259
	if (NetOurGatewayIP)
R
Robin Getz 已提交
260
		debug("NetOurGatewayIP	: %pI4", &NetOurGatewayIP);
261

R
Robin Getz 已提交
262 263
	if (NetBootFileSize)
		debug("NetBootFileSize : %d\n", NetBootFileSize);
W
wdenk 已提交
264

R
Robin Getz 已提交
265 266
	if (NetOurHostName[0])
		debug("NetOurHostName  : %s\n", NetOurHostName);
267

R
Robin Getz 已提交
268 269
	if (NetOurRootPath[0])
		debug("NetOurRootPath  : %s\n", NetOurRootPath);
270

R
Robin Getz 已提交
271 272
	if (NetOurNISDomain[0])
		debug("NetOurNISDomain : %s\n", NetOurNISDomain);
273

R
Robin Getz 已提交
274 275
	if (NetBootFileSize)
		debug("NetBootFileSize: %d\n", NetBootFileSize);
276 277 278 279 280

#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
	if (NetNtpServerIP)
		debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
#endif
281
}
282

W
wdenk 已提交
283 284 285 286
/*
 *	Handle a BOOTP received packet.
 */
static void
287 288
BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
	     unsigned len)
W
wdenk 已提交
289
{
290
	struct Bootp_t *bp;
W
wdenk 已提交
291

R
Robin Getz 已提交
292
	debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
293
		src, dest, len, sizeof(struct Bootp_t));
W
wdenk 已提交
294

295
	bp = (struct Bootp_t *)pkt;
W
wdenk 已提交
296

297 298
	/* Filter out pkts we don't want */
	if (BootpCheckPkt(pkt, dest, src, len))
W
wdenk 已提交
299 300 301
		return;

	/*
302
	 *	Got a good BOOTP reply.	 Copy the data into our variables.
W
wdenk 已提交
303 304
	 */
#ifdef CONFIG_STATUS_LED
305
	status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
W
wdenk 已提交
306 307 308 309 310
#endif

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

	/* Retrieve extended information (we must parse the vendor area) */
311
	if (NetReadLong((ulong *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
W
Wolfgang Denk 已提交
312
		BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
W
wdenk 已提交
313 314

	NetSetTimeout(0, (thand_f *)0);
315
	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
W
wdenk 已提交
316

R
Robin Getz 已提交
317
	debug("Got good BOOTP\n");
W
wdenk 已提交
318

319
	net_auto_load();
W
wdenk 已提交
320
}
321
#endif
W
wdenk 已提交
322 323 324 325 326 327 328 329

/*
 *	Timeout on BOOTP/DHCP request.
 */
static void
BootpTimeout(void)
{
	if (BootpTry >= TIMEOUT_COUNT) {
330 331
		puts("\nRetry count exceeded; starting again\n");
		NetStartAgain();
W
wdenk 已提交
332
	} else {
333 334
		NetSetTimeout(TIMEOUT, BootpTimeout);
		BootpRequest();
W
wdenk 已提交
335 336 337 338 339 340
	}
}

/*
 *	Initialize BOOTP extension fields in the request.
 */
341
#if defined(CONFIG_CMD_DHCP)
342 343
static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID,
			IPaddr_t RequestedIP)
W
wdenk 已提交
344
{
345 346
	u8 *start = e;
	u8 *cnt;
347 348 349 350 351
#if defined(CONFIG_BOOTP_PXE)
	char *uuid;
	size_t vci_strlen;
	u16 clientarch;
#endif
352

353
#if defined(CONFIG_BOOTP_VENDOREX)
354
	u8 *x;
W
wdenk 已提交
355
#endif
356
#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
W
Wolfgang Denk 已提交
357
	char *hostname;
358
#endif
W
wdenk 已提交
359

360 361 362 363
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
W
wdenk 已提交
364

365 366 367
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = message_type;
W
wdenk 已提交
368

369 370
	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
371 372
	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
W
wdenk 已提交
373

374
	if (ServerID) {
375
		int tmp = ntohl(ServerID);
W
wdenk 已提交
376

377 378 379 380 381 382 383
		*e++ = 54;	/* ServerID */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
W
wdenk 已提交
384

385
	if (RequestedIP) {
386
		int tmp = ntohl(RequestedIP);
W
wdenk 已提交
387

388 389 390 391 392 393 394
		*e++ = 50;	/* Requested IP */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
395
#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
396 397 398
	hostname = getenv("hostname");
	if (hostname) {
		int hostnamelen = strlen(hostname);
399 400 401

		*e++ = 12;	/* Hostname */
		*e++ = hostnamelen;
402
		memcpy(e, hostname, hostnamelen);
403 404
		e += hostnamelen;
	}
405 406
#endif

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
#if defined(CONFIG_BOOTP_PXE)
	clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
	*e++ = 93;	/* Client System Architecture */
	*e++ = 2;
	*e++ = (clientarch >> 8) & 0xff;
	*e++ = clientarch & 0xff;

	*e++ = 94;	/* Client Network Interface Identifier */
	*e++ = 3;
	*e++ = 1;	/* type field for UNDI */
	*e++ = 0;	/* major revision */
	*e++ = 0;	/* minor revision */

	uuid = getenv("pxeuuid");

	if (uuid) {
		if (uuid_str_valid(uuid)) {
			*e++ = 97;	/* Client Machine Identifier */
			*e++ = 17;
			*e++ = 0;	/* type 0 - UUID */

			uuid_str_to_bin(uuid, e);
			e += 16;
		} else {
			printf("Invalid pxeuuid: %s\n", uuid);
		}
	}

	*e++ = 60;	/* Vendor Class Identifier */
	vci_strlen = strlen(CONFIG_BOOTP_VCI_STRING);
	*e++ = vci_strlen;
	memcpy(e, CONFIG_BOOTP_VCI_STRING, vci_strlen);
	e += vci_strlen;
#endif

442
#if defined(CONFIG_BOOTP_VENDOREX)
443 444
	x = dhcp_vendorex_prep(e);
	if (x)
445
		return x - start;
W
wdenk 已提交
446 447
#endif

448 449 450
	*e++ = 55;		/* Parameter Request List */
	 cnt = e++;		/* Pointer to count of requested items */
	*cnt = 0;
451
#if defined(CONFIG_BOOTP_SUBNETMASK)
452 453
	*e++  = 1;		/* Subnet Mask */
	*cnt += 1;
W
wdenk 已提交
454
#endif
455
#if defined(CONFIG_BOOTP_TIMEOFFSET)
W
wdenk 已提交
456 457 458
	*e++  = 2;
	*cnt += 1;
#endif
459
#if defined(CONFIG_BOOTP_GATEWAY)
460 461
	*e++  = 3;		/* Router Option */
	*cnt += 1;
W
wdenk 已提交
462
#endif
463
#if defined(CONFIG_BOOTP_DNS)
464 465
	*e++  = 6;		/* DNS Server(s) */
	*cnt += 1;
W
wdenk 已提交
466
#endif
467
#if defined(CONFIG_BOOTP_HOSTNAME)
468 469
	*e++  = 12;		/* Hostname */
	*cnt += 1;
W
wdenk 已提交
470
#endif
471
#if defined(CONFIG_BOOTP_BOOTFILESIZE)
472 473
	*e++  = 13;		/* Boot File Size */
	*cnt += 1;
W
wdenk 已提交
474
#endif
475
#if defined(CONFIG_BOOTP_BOOTPATH)
476 477
	*e++  = 17;		/* Boot path */
	*cnt += 1;
W
wdenk 已提交
478
#endif
479
#if defined(CONFIG_BOOTP_NISDOMAIN)
480 481
	*e++  = 40;		/* NIS Domain name request */
	*cnt += 1;
W
wdenk 已提交
482
#endif
483
#if defined(CONFIG_BOOTP_NTPSERVER)
W
wdenk 已提交
484 485
	*e++  = 42;
	*cnt += 1;
W
wdenk 已提交
486
#endif
487 488 489 490
	/* no options, so back up to avoid sending an empty request list */
	if (*cnt == 0)
		e -= 2;

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

493
	/* Pad to minimal length */
W
wdenk 已提交
494
#ifdef	CONFIG_DHCP_MIN_EXT_LEN
495
	while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
496
		*e++ = 0;
W
wdenk 已提交
497 498
#endif

499
	return e - start;
W
wdenk 已提交
500 501
}

502
#else
W
wdenk 已提交
503
/*
504
 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
W
wdenk 已提交
505
 */
506
static int BootpExtended(u8 *e)
W
wdenk 已提交
507
{
508
	u8 *start = e;
W
wdenk 已提交
509

510 511 512 513
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
W
wdenk 已提交
514

515
#if defined(CONFIG_CMD_DHCP)
516 517 518 519 520 521
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = DHCP_DISCOVER;

	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
522 523
	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
524
#endif
W
wdenk 已提交
525

526
#if defined(CONFIG_BOOTP_SUBNETMASK)
527 528 529
	*e++ = 1;		/* Subnet mask request */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
530 531
#endif

532
#if defined(CONFIG_BOOTP_GATEWAY)
533 534 535
	*e++ = 3;		/* Default gateway request */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
536 537
#endif

538
#if defined(CONFIG_BOOTP_DNS)
539 540 541
	*e++ = 6;		/* Domain Name Server */
	*e++ = 4;
	e   += 4;
W
wdenk 已提交
542 543
#endif

544
#if defined(CONFIG_BOOTP_HOSTNAME)
545 546 547
	*e++ = 12;		/* Host name request */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
548 549
#endif

550
#if defined(CONFIG_BOOTP_BOOTFILESIZE)
551 552 553
	*e++ = 13;		/* Boot file size */
	*e++ = 2;
	e   += 2;
W
wdenk 已提交
554 555
#endif

556
#if defined(CONFIG_BOOTP_BOOTPATH)
557 558 559
	*e++ = 17;		/* Boot path */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
560 561
#endif

562
#if defined(CONFIG_BOOTP_NISDOMAIN)
563 564 565
	*e++ = 40;		/* NIS Domain name request */
	*e++ = 32;
	e   += 32;
W
wdenk 已提交
566
#endif
567 568 569 570 571
#if defined(CONFIG_BOOTP_NTPSERVER)
	*e++ = 42;
	*e++ = 4;
	e   += 4;
#endif
W
wdenk 已提交
572

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

575
	return e - start;
W
wdenk 已提交
576
}
577
#endif
W
wdenk 已提交
578 579

void
580
BootpRequest(void)
W
wdenk 已提交
581
{
582
	uchar *pkt, *iphdr;
583
	struct Bootp_t *bp;
W
wdenk 已提交
584
	int ext_len, pktlen, iplen;
585 586 587
#ifdef CONFIG_BOOTP_RANDOM_DELAY
	ulong i, rand_ms;
#endif
W
wdenk 已提交
588

589
	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
590
#if defined(CONFIG_CMD_DHCP)
W
wdenk 已提交
591 592 593 594
	dhcp_state = INIT;
#endif

#ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
595 596
	if (BootpTry == 0)
		srand_mac();
W
wdenk 已提交
597

598 599 600 601
	if (BootpTry <= 2)	/* Start with max 1024 * 1ms */
		rand_ms = rand() >> (22 - BootpTry);
	else		/* After 3rd BOOTP request max 8192 * 1ms */
		rand_ms = rand() >> 19;
W
wdenk 已提交
602

603 604
	printf("Random delay: %ld ms...\n", rand_ms);
	for (i = 0; i < rand_ms; i++)
W
wdenk 已提交
605
		udelay(1000); /*Wait 1ms*/
606

W
wdenk 已提交
607 608 609 610
#endif	/* CONFIG_BOOTP_RANDOM_DELAY */

	printf("BOOTP broadcast %d\n", ++BootpTry);
	pkt = NetTxPacket;
611
	memset((void *)pkt, 0, PKTSIZE);
W
wdenk 已提交
612

613
	pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
W
wdenk 已提交
614 615

	/*
616 617 618 619
	 * 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.
W
wdenk 已提交
620 621
	 * C. Hallinan, DS4.COM, Inc.
	 */
622 623
	/* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
		sizeof (struct Bootp_t)); */
W
wdenk 已提交
624
	iphdr = pkt;	/* We need this later for NetSetIP() */
J
Joe Hershberger 已提交
625
	pkt += IP_UDP_HDR_SIZE;
W
wdenk 已提交
626

627
	bp = (struct Bootp_t *)pkt;
W
wdenk 已提交
628 629 630 631
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
632
	bp->bp_secs = htons(get_timer(0) / 1000);
W
wdenk 已提交
633 634 635 636
	NetWriteIP(&bp->bp_ciaddr, 0);
	NetWriteIP(&bp->bp_yiaddr, 0);
	NetWriteIP(&bp->bp_siaddr, 0);
	NetWriteIP(&bp->bp_giaddr, 0);
637 638
	memcpy(bp->bp_chaddr, NetOurEther, 6);
	copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file));
W
wdenk 已提交
639 640

	/* Request additional information from the BOOTP/DHCP server */
641
#if defined(CONFIG_CMD_DHCP)
W
Wolfgang Denk 已提交
642
	ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
W
wdenk 已提交
643
#else
W
Wolfgang Denk 已提交
644
	ext_len = BootpExtended((u8 *)bp->bp_vend);
645
#endif
W
wdenk 已提交
646 647 648

	/*
	 *	Bootp ID is the lower 4 bytes of our ethernet address
649
	 *	plus the current time in ms.
W
wdenk 已提交
650 651 652 653 654 655
	 */
	BootpID = ((ulong)NetOurEther[2] << 24)
		| ((ulong)NetOurEther[3] << 16)
		| ((ulong)NetOurEther[4] << 8)
		| (ulong)NetOurEther[5];
	BootpID += get_timer(0);
656
	BootpID	 = htonl(BootpID);
W
wdenk 已提交
657 658 659 660 661 662
	NetCopyLong(&bp->bp_id, &BootpID);

	/*
	 * Calculate proper packet lengths taking into account the
	 * variable size of the options field
	 */
663 664
	pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE -
		sizeof(bp->bp_vend) + ext_len;
W
wdenk 已提交
665 666
	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
667
	NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
W
wdenk 已提交
668

669
#if defined(CONFIG_CMD_DHCP)
W
wdenk 已提交
670 671 672 673
	dhcp_state = SELECTING;
	NetSetHandler(DhcpHandler);
#else
	NetSetHandler(BootpHandler);
674
#endif
W
wdenk 已提交
675 676 677
	NetSendPacket(NetTxPacket, pktlen);
}

678
#if defined(CONFIG_CMD_DHCP)
679
static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp)
W
wdenk 已提交
680
{
W
wdenk 已提交
681
	uchar *end = popt + BOOTP_HDR_SIZE;
W
wdenk 已提交
682
	int oplen, size;
W
Wolfgang Denk 已提交
683 684 685
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
	int *to_ptr;
#endif
W
wdenk 已提交
686

687
	while (popt < end && *popt != 0xff) {
W
wdenk 已提交
688
		oplen = *(popt + 1);
689 690
		switch (*popt) {
		case 1:
691
			NetCopyIP(&NetOurSubnetMask, (popt + 2));
692
			break;
693
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
W
wdenk 已提交
694
		case 2:		/* Time offset	*/
W
Wolfgang Denk 已提交
695
			to_ptr = &NetTimeOffset;
696 697
			NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2));
			NetTimeOffset = ntohl(NetTimeOffset);
W
wdenk 已提交
698 699
			break;
#endif
700
		case 3:
701
			NetCopyIP(&NetOurGatewayIP, (popt + 2));
702 703
			break;
		case 6:
704
			NetCopyIP(&NetOurDNSIP, (popt + 2));
705
#if defined(CONFIG_BOOTP_DNS2)
706 707
			if (*(popt + 1) > 4)
				NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
708
#endif
709 710
			break;
		case 12:
711 712 713
			size = truncate_sz("Host Name",
				sizeof(NetOurHostName), oplen);
			memcpy(&NetOurHostName, popt + 2, size);
714 715 716 717 718
			NetOurHostName[size] = 0;
			break;
		case 15:	/* Ignore Domain Name Option */
			break;
		case 17:
719 720 721
			size = truncate_sz("Root Path",
				sizeof(NetOurRootPath), oplen);
			memcpy(&NetOurRootPath, popt + 2, size);
722 723
			NetOurRootPath[size] = 0;
			break;
724
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
W
wdenk 已提交
725
		case 42:	/* NTP server IP */
726
			NetCopyIP(&NetNtpServerIP, (popt + 2));
W
wdenk 已提交
727 728
			break;
#endif
729
		case 51:
730
			NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2));
731 732 733 734
			break;
		case 53:	/* Ignore Message Type Option */
			break;
		case 54:
735
			NetCopyIP(&NetDHCPServerIP, (popt + 2));
736 737 738 739 740
			break;
		case 58:	/* Ignore Renewal Time Option */
			break;
		case 59:	/* Ignore Rebinding Time Option */
			break;
741 742 743 744 745 746 747 748 749
		case 66:	/* Ignore TFTP server name */
			break;
		case 67:	/* vendor opt bootfile */
			/*
			 * I can't use dhcp_vendorex_proc here because I need
			 * to write into the bootp packet - even then I had to
			 * pass the bootp packet pointer into here as the
			 * second arg
			 */
750
			size = truncate_sz("Opt Boot File",
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
					    sizeof(bp->bp_file),
					    oplen);
			if (bp->bp_file[0] == '\0' && size > 0) {
				/*
				 * only use vendor boot file if we didn't
				 * receive a boot file in the main non-vendor
				 * part of the packet - god only knows why
				 * some vendors chose not to use this perfectly
				 * good spot to store the boot file (join on
				 * Tru64 Unix) it seems mind bogglingly crazy
				 * to me
				 */
				printf("*** WARNING: using vendor "
					"optional boot file\n");
				memcpy(bp->bp_file, popt + 2, size);
				bp->bp_file[size] = '\0';
			}
			break;
769
		default:
770
#if defined(CONFIG_BOOTP_VENDOREX)
771
			if (dhcp_vendorex_proc(popt))
W
wdenk 已提交
772
				break;
W
wdenk 已提交
773
#endif
774 775
			printf("*** Unhandled DHCP Option in OFFER/ACK:"
				" %d\n", *popt);
776
			break;
W
wdenk 已提交
777 778 779 780 781 782 783
		}
		popt += oplen + 2;	/* Process next option */
	}
}

static int DhcpMessageType(unsigned char *popt)
{
784
	if (NetReadLong((ulong *)popt) != htonl(BOOTP_VENDOR_MAGIC))
W
wdenk 已提交
785 786 787
		return -1;

	popt += 4;
788 789
	while (*popt != 0xff) {
		if (*popt == 53)	/* DHCP Message Type */
W
wdenk 已提交
790 791 792 793 794 795
			return *(popt + 2);
		popt += *(popt + 1) + 2;	/* Scan through all options */
	}
	return -1;
}

796
static void DhcpSendRequestPkt(struct Bootp_t *bp_offer)
W
wdenk 已提交
797
{
798
	uchar *pkt, *iphdr;
799
	struct Bootp_t *bp;
W
wdenk 已提交
800
	int pktlen, iplen, extlen;
801
	IPaddr_t OfferedIP;
W
wdenk 已提交
802

R
Robin Getz 已提交
803
	debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
W
wdenk 已提交
804
	pkt = NetTxPacket;
805
	memset((void *)pkt, 0, PKTSIZE);
W
wdenk 已提交
806

807
	pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
W
wdenk 已提交
808

809
	iphdr = pkt;	/* We'll need this later to set proper pkt size */
J
Joe Hershberger 已提交
810
	pkt += IP_UDP_HDR_SIZE;
W
wdenk 已提交
811

812
	bp = (struct Bootp_t *)pkt;
W
wdenk 已提交
813 814 815 816
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
817
	bp->bp_secs = htons(get_timer(0) / 1000);
818 819
	/* Do not set the client IP, your IP, or server IP yet, since it
	 * hasn't been ACK'ed by the server yet */
J
Justin Flammia 已提交
820

W
Wolfgang Denk 已提交
821
	/*
822 823 824 825 826
	 * RFC3046 requires Relay Agents to discard packets with
	 * nonzero and offered giaddr
	 */
	NetWriteIP(&bp->bp_giaddr, 0);

827
	memcpy(bp->bp_chaddr, NetOurEther, 6);
W
wdenk 已提交
828 829 830 831 832 833 834 835 836 837

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

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

	/*
	 * Copy options from OFFER packet if present
	 */
J
Justin Flammia 已提交
838 839 840

	/* Copy offered IP into the parameters request list */
	NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
841 842
	extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST,
		NetDHCPServerIP, OfferedIP);
W
wdenk 已提交
843

844 845
	pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE -
		sizeof(bp->bp_vend) + extlen;
W
wdenk 已提交
846 847 848
	iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
	NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);

R
Robin Getz 已提交
849
	debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
850 851 852
#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
	udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
#endif	/* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
W
wdenk 已提交
853 854 855 856 857 858 859
	NetSendPacket(NetTxPacket, pktlen);
}

/*
 *	Handle DHCP received packets.
 */
static void
860 861
DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
	    unsigned len)
W
wdenk 已提交
862
{
863
	struct Bootp_t *bp = (struct Bootp_t *)pkt;
W
wdenk 已提交
864

R
Robin Getz 已提交
865
	debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
W
wdenk 已提交
866 867
		src, dest, len, dhcp_state);

868 869
	/* Filter out pkts we don't want */
	if (BootpCheckPkt(pkt, dest, src, len))
W
wdenk 已提交
870 871
		return;

872 873
	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state:"
		" %d\n", src, dest, len, dhcp_state);
W
wdenk 已提交
874 875 876 877 878

	switch (dhcp_state) {
	case SELECTING:
		/*
		 * Wait an appropriate time for any potential DHCPOFFER packets
879 880 881
		 * 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.
W
wdenk 已提交
882
		 */
R
Robin Getz 已提交
883
		debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
884
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
W
wdenk 已提交
885
		if (strncmp(bp->bp_file,
886
			    CONFIG_SYS_BOOTFILE_PREFIX,
887
			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
888
#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
W
wdenk 已提交
889

R
Robin Getz 已提交
890
			debug("TRANSITIONING TO REQUESTING STATE\n");
W
wdenk 已提交
891
			dhcp_state = REQUESTING;
892

893 894
			if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
						htonl(BOOTP_VENDOR_MAGIC))
895
				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
W
wdenk 已提交
896

897
			NetSetTimeout(TIMEOUT, BootpTimeout);
W
wdenk 已提交
898
			DhcpSendRequestPkt(bp);
899
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
W
wdenk 已提交
900
		}
901
#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
W
wdenk 已提交
902 903 904 905

		return;
		break;
	case REQUESTING:
R
Robin Getz 已提交
906
		debug("DHCP State: REQUESTING\n");
W
wdenk 已提交
907

908 909 910
		if (DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK) {
			if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
						htonl(BOOTP_VENDOR_MAGIC))
911
				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
912 913
			/* Store net params from reply */
			BootpCopyNetParams(bp);
W
wdenk 已提交
914
			dhcp_state = BOUND;
915 916
			printf("DHCP client bound to address %pI4\n",
				&NetOurIP);
917
			bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
918
				"bootp_stop");
W
wdenk 已提交
919

920
			net_auto_load();
W
wdenk 已提交
921 922 923
			return;
		}
		break;
924 925 926
	case BOUND:
		/* DHCP client bound to address */
		break;
W
wdenk 已提交
927
	default:
928
		puts("DHCP: INVALID STATE\n");
W
wdenk 已提交
929 930 931 932 933 934 935 936 937
		break;
	}

}

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