bootp.c 22.2 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;
584 585
	int extlen, pktlen, iplen;
	int eth_hdr_size;
586 587 588
#ifdef CONFIG_BOOTP_RANDOM_DELAY
	ulong i, rand_ms;
#endif
W
wdenk 已提交
589

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

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

599 600 601 602
	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 已提交
603

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

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

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

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

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

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

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

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

	/*
	 * Calculate proper packet lengths taking into account the
	 * variable size of the options field
	 */
665 666
	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
667
	net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
668
	NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
W
wdenk 已提交
669

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

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

688
	while (popt < end && *popt != 0xff) {
W
wdenk 已提交
689
		oplen = *(popt + 1);
690 691
		switch (*popt) {
		case 1:
692
			NetCopyIP(&NetOurSubnetMask, (popt + 2));
693
			break;
694
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
W
wdenk 已提交
695
		case 2:		/* Time offset	*/
W
Wolfgang Denk 已提交
696
			to_ptr = &NetTimeOffset;
697 698
			NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2));
			NetTimeOffset = ntohl(NetTimeOffset);
W
wdenk 已提交
699 700
			break;
#endif
701
		case 3:
702
			NetCopyIP(&NetOurGatewayIP, (popt + 2));
703 704
			break;
		case 6:
705
			NetCopyIP(&NetOurDNSIP, (popt + 2));
706
#if defined(CONFIG_BOOTP_DNS2)
707 708
			if (*(popt + 1) > 4)
				NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
709
#endif
710 711
			break;
		case 12:
712 713 714
			size = truncate_sz("Host Name",
				sizeof(NetOurHostName), oplen);
			memcpy(&NetOurHostName, popt + 2, size);
715 716 717 718 719
			NetOurHostName[size] = 0;
			break;
		case 15:	/* Ignore Domain Name Option */
			break;
		case 17:
720 721 722
			size = truncate_sz("Root Path",
				sizeof(NetOurRootPath), oplen);
			memcpy(&NetOurRootPath, popt + 2, size);
723 724
			NetOurRootPath[size] = 0;
			break;
725
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
W
wdenk 已提交
726
		case 42:	/* NTP server IP */
727
			NetCopyIP(&NetNtpServerIP, (popt + 2));
W
wdenk 已提交
728 729
			break;
#endif
730
		case 51:
731
			NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2));
732 733 734 735
			break;
		case 53:	/* Ignore Message Type Option */
			break;
		case 54:
736
			NetCopyIP(&NetDHCPServerIP, (popt + 2));
737 738 739 740 741
			break;
		case 58:	/* Ignore Renewal Time Option */
			break;
		case 59:	/* Ignore Rebinding Time Option */
			break;
742 743 744 745 746 747 748 749 750
		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
			 */
751
			size = truncate_sz("Opt Boot File",
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
					    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;
770
		default:
771
#if defined(CONFIG_BOOTP_VENDOREX)
772
			if (dhcp_vendorex_proc(popt))
W
wdenk 已提交
773
				break;
W
wdenk 已提交
774
#endif
775 776
			printf("*** Unhandled DHCP Option in OFFER/ACK:"
				" %d\n", *popt);
777
			break;
W
wdenk 已提交
778 779 780 781 782 783 784
		}
		popt += oplen + 2;	/* Process next option */
	}
}

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

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

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

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

809 810
	eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
	pkt += eth_hdr_size;
W
wdenk 已提交
811

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

815
	bp = (struct Bootp_t *)pkt;
W
wdenk 已提交
816 817 818 819
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
820
	bp->bp_secs = htons(get_timer(0) / 1000);
821 822
	/* 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 已提交
823

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

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

	/*
	 * 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 已提交
841 842 843

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

847 848
	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
849
	net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
W
wdenk 已提交
850

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

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

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

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

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

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

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

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

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

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

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

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

}

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