bootp.c 25.7 KB
Newer Older
wdenk's avatar
wdenk committed
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
wdenk's avatar
wdenk committed
9 10 11 12
 */

#include <common.h>
#include <command.h>
13
#include <efi_loader.h>
wdenk's avatar
wdenk committed
14
#include <net.h>
15
#include <net/tftp.h>
wdenk's avatar
wdenk committed
16
#include "bootp.h"
17
#include "nfs.h"
wdenk's avatar
wdenk committed
18 19 20
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#endif
21 22 23
#ifdef CONFIG_BOOTP_RANDOM_DELAY
#include "net_rand.h"
#endif
wdenk's avatar
wdenk committed
24

25
#define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
wdenk's avatar
wdenk committed
26

27 28 29 30 31 32 33 34 35 36
/*
 * The timeout for the initial BOOTP/DHCP request used to be described by a
 * counter of fixed-length timeout periods. TIMEOUT_COUNT represents
 * that counter
 *
 * Now that the timeout periods are variable (exponential backoff and retry)
 * we convert the timeout count to the absolute time it would have take to
 * execute that many retries, and keep sending retry packets until that time
 * is reached.
 */
37
#ifndef CONFIG_NET_RETRY_COUNT
38
# define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
wdenk's avatar
wdenk committed
39
#else
40
# define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
wdenk's avatar
wdenk committed
41
#endif
42
#define TIMEOUT_MS	((3 + (TIMEOUT_COUNT * 5)) * 1000)
wdenk's avatar
wdenk committed
43

44 45
#define PORT_BOOTPS	67		/* BOOTP server UDP port */
#define PORT_BOOTPC	68		/* BOOTP client UDP port */
wdenk's avatar
wdenk committed
46

47
#ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list */
48
#define CONFIG_DHCP_MIN_EXT_LEN 64
wdenk's avatar
wdenk committed
49 50
#endif

51 52 53 54
#ifndef CONFIG_BOOTP_ID_CACHE_SIZE
#define CONFIG_BOOTP_ID_CACHE_SIZE 4
#endif

55
u32		bootp_ids[CONFIG_BOOTP_ID_CACHE_SIZE];
56
unsigned int	bootp_num_ids;
57
int		bootp_try;
58 59
ulong		bootp_start;
ulong		bootp_timeout;
60 61 62
char net_nis_domain[32] = {0,}; /* Our NIS domain */
char net_hostname[32] = {0,}; /* Our hostname */
char net_root_path[64] = {0,}; /* Our bootpath */
wdenk's avatar
wdenk committed
63

64 65
static ulong time_taken_max;

66
#if defined(CONFIG_CMD_DHCP)
Kim Phillips's avatar
Kim Phillips committed
67
static dhcp_state_t dhcp_state = INIT;
68
static u32 dhcp_leasetime;
69
static struct in_addr dhcp_server_ip;
70 71 72
static u8 dhcp_option_overload;
#define OVERLOAD_FILE 1
#define OVERLOAD_SNAME 2
73 74
static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
			unsigned src, unsigned len);
wdenk's avatar
wdenk committed
75 76

/* For Debug */
77 78
#if 0
static char *dhcpmsg2str(int type)
wdenk's avatar
wdenk committed
79 80
{
	switch (type) {
81 82 83 84 85 86 87
	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;
wdenk's avatar
wdenk committed
88 89 90
	default: return "UNKNOWN/INVALID MSG TYPE"; break;
	}
}
91
#endif
92
#endif
wdenk's avatar
wdenk committed
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
static void bootp_add_id(ulong id)
{
	if (bootp_num_ids >= ARRAY_SIZE(bootp_ids)) {
		size_t size = sizeof(bootp_ids) - sizeof(id);

		memmove(bootp_ids, &bootp_ids[1], size);
		bootp_ids[bootp_num_ids - 1] = id;
	} else {
		bootp_ids[bootp_num_ids] = id;
		bootp_num_ids++;
	}
}

static bool bootp_match_id(ulong id)
{
	unsigned int i;

	for (i = 0; i < bootp_num_ids; i++)
		if (bootp_ids[i] == id)
			return true;

	return false;
}

118 119
static int check_reply_packet(uchar *pkt, unsigned dest, unsigned src,
			      unsigned len)
wdenk's avatar
wdenk committed
120
{
121
	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
wdenk's avatar
wdenk committed
122 123 124 125
	int retval = 0;

	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
		retval = -1;
126
	else if (len < sizeof(struct bootp_hdr) - OPT_FIELD_SIZE)
wdenk's avatar
wdenk committed
127
		retval = -2;
128
	else if (bp->bp_op != OP_BOOTREPLY)
wdenk's avatar
wdenk committed
129 130 131 132 133
		retval = -3;
	else if (bp->bp_htype != HWT_ETHER)
		retval = -4;
	else if (bp->bp_hlen != HWL_ETHER)
		retval = -5;
134
	else if (!bootp_match_id(net_read_u32(&bp->bp_id)))
wdenk's avatar
wdenk committed
135
		retval = -6;
136 137
	else if (memcmp(bp->bp_chaddr, net_ethaddr, HWL_ETHER) != 0)
		retval = -7;
wdenk's avatar
wdenk committed
138

139
	debug("Filtering pkt = %d\n", retval);
wdenk's avatar
wdenk committed
140 141 142 143 144 145 146

	return retval;
}

/*
 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
 */
147
static void store_net_params(struct bootp_hdr *bp)
wdenk's avatar
wdenk committed
148
{
149
#if !defined(CONFIG_BOOTP_SERVERIP)
150
	struct in_addr tmp_ip;
151

152 153 154
	net_copy_ip(&tmp_ip, &bp->bp_siaddr);
	if (tmp_ip.s_addr != 0)
		net_copy_ip(&net_server_ip, &bp->bp_siaddr);
155 156
	memcpy(net_server_ethaddr,
	       ((struct ethernet_hdr *)net_rx_packet)->et_src, 6);
157 158 159 160 161
	if (
#if defined(CONFIG_CMD_DHCP)
	    !(dhcp_option_overload & OVERLOAD_FILE) &&
#endif
	    (strlen(bp->bp_file) > 0)) {
162 163
		copy_filename(net_boot_file_name, bp->bp_file,
			      sizeof(net_boot_file_name));
164
	}
wdenk's avatar
wdenk committed
165

166
	debug("net_boot_file_name: %s\n", net_boot_file_name);
wdenk's avatar
wdenk committed
167 168

	/* Propagate to environment:
wdenk's avatar
wdenk committed
169
	 * don't delete exising entry when BOOTP / DHCP reply does
wdenk's avatar
wdenk committed
170 171
	 * not contain a new value
	 */
172 173
	if (*net_boot_file_name)
		setenv("bootfile", net_boot_file_name);
174
#endif
175
	net_copy_ip(&net_ip, &bp->bp_yiaddr);
wdenk's avatar
wdenk committed
176 177
}

178
static int truncate_sz(const char *name, int maxlen, int curlen)
wdenk's avatar
wdenk committed
179 180
{
	if (curlen >= maxlen) {
181 182
		printf("*** WARNING: %s is too long (%d - max: %d)"
			" - truncated\n", name, curlen, maxlen);
wdenk's avatar
wdenk committed
183 184
		curlen = maxlen - 1;
	}
185
	return curlen;
wdenk's avatar
wdenk committed
186 187
}

188
#if !defined(CONFIG_CMD_DHCP)
wdenk's avatar
wdenk committed
189

190
static void bootp_process_vendor_field(u8 *ext)
wdenk's avatar
wdenk committed
191
{
192
	int size = *(ext + 1);
wdenk's avatar
wdenk committed
193

194
	debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
195
	      *(ext + 1));
wdenk's avatar
wdenk committed
196

197
	net_boot_file_expected_size_in_blocks = 0;
wdenk's avatar
wdenk committed
198

199 200
	switch (*ext) {
		/* Fixed length fields */
201
	case 1:			/* Subnet mask */
202 203
		if (net_netmask.s_addr == 0)
			net_copy_ip(&net_netmask, (struct in_addr *)(ext + 2));
wdenk's avatar
wdenk committed
204
		break;
205
	case 2:			/* Time offset - Not yet supported */
wdenk's avatar
wdenk committed
206
		break;
207
		/* Variable length fields */
208
	case 3:			/* Gateways list */
209 210
		if (net_gateway.s_addr == 0)
			net_copy_ip(&net_gateway, (struct in_addr *)(ext + 2));
wdenk's avatar
wdenk committed
211
		break;
212
	case 4:			/* Time server - Not yet supported */
wdenk's avatar
wdenk committed
213
		break;
214
	case 5:			/* IEN-116 name server - Not yet supported */
wdenk's avatar
wdenk committed
215 216
		break;
	case 6:
217 218 219
		if (net_dns_server.s_addr == 0)
			net_copy_ip(&net_dns_server,
				    (struct in_addr *)(ext + 2));
220
#if defined(CONFIG_BOOTP_DNS2)
221 222 223
		if ((net_dns_server2.s_addr == 0) && (size > 4))
			net_copy_ip(&net_dns_server2,
				    (struct in_addr *)(ext + 2 + 4));
224
#endif
wdenk's avatar
wdenk committed
225
		break;
226
	case 7:			/* Log server - Not yet supported */
wdenk's avatar
wdenk committed
227
		break;
228
	case 8:			/* Cookie/Quote server - Not yet supported */
wdenk's avatar
wdenk committed
229
		break;
230
	case 9:			/* LPR server - Not yet supported */
wdenk's avatar
wdenk committed
231
		break;
232
	case 10:		/* Impress server - Not yet supported */
wdenk's avatar
wdenk committed
233
		break;
234
	case 11:		/* RPL server - Not yet supported */
wdenk's avatar
wdenk committed
235
		break;
236
	case 12:		/* Host name */
237
		if (net_hostname[0] == 0) {
238
			size = truncate_sz("Host Name",
239 240 241
				sizeof(net_hostname), size);
			memcpy(&net_hostname, ext + 2, size);
			net_hostname[size] = 0;
wdenk's avatar
wdenk committed
242 243
		}
		break;
244
	case 13:		/* Boot file size */
wdenk's avatar
wdenk committed
245
		if (size == 2)
246 247
			net_boot_file_expected_size_in_blocks =
				ntohs(*(ushort *)(ext + 2));
wdenk's avatar
wdenk committed
248
		else if (size == 4)
249 250
			net_boot_file_expected_size_in_blocks =
				ntohl(*(ulong *)(ext + 2));
wdenk's avatar
wdenk committed
251
		break;
252
	case 14:		/* Merit dump file - Not yet supported */
wdenk's avatar
wdenk committed
253
		break;
254
	case 15:		/* Domain name - Not yet supported */
wdenk's avatar
wdenk committed
255
		break;
256
	case 16:		/* Swap server - Not yet supported */
wdenk's avatar
wdenk committed
257
		break;
258
	case 17:		/* Root path */
259
		if (net_root_path[0] == 0) {
260
			size = truncate_sz("Root Path",
261 262 263
				sizeof(net_root_path), size);
			memcpy(&net_root_path, ext + 2, size);
			net_root_path[size] = 0;
wdenk's avatar
wdenk committed
264 265
		}
		break;
266
	case 18:		/* Extension path - Not yet supported */
wdenk's avatar
wdenk committed
267
		/*
wdenk's avatar
wdenk committed
268 269 270
		 * This can be used to send the information of the
		 * vendor area in another file that the client can
		 * access via TFTP.
wdenk's avatar
wdenk committed
271 272
		 */
		break;
273
		/* IP host layer fields */
274
	case 40:		/* NIS Domain name */
275
		if (net_nis_domain[0] == 0) {
276
			size = truncate_sz("NIS Domain Name",
277 278 279
				sizeof(net_nis_domain), size);
			memcpy(&net_nis_domain, ext + 2, size);
			net_nis_domain[size] = 0;
wdenk's avatar
wdenk committed
280 281
		}
		break;
282 283
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
	case 42:	/* NTP server IP */
284
		net_copy_ip(&net_ntp_server, (struct in_addr *)(ext + 2));
285 286
		break;
#endif
287
		/* Application layer fields */
288
	case 43:		/* Vendor specific info - Not yet supported */
wdenk's avatar
wdenk committed
289
		/*
wdenk's avatar
wdenk committed
290 291
		 * Binary information to exchange specific
		 * product information.
wdenk's avatar
wdenk committed
292 293
		 */
		break;
294 295
		/* Reserved (custom) fields (128..254) */
	}
wdenk's avatar
wdenk committed
296 297
}

298
static void bootp_process_vendor(u8 *ext, int size)
wdenk's avatar
wdenk committed
299
{
300
	u8 *end = ext + size;
wdenk's avatar
wdenk committed
301

302
	debug("[BOOTP] Checking extension (%d bytes)...\n", size);
wdenk's avatar
wdenk committed
303

304 305 306 307 308 309 310 311
	while ((ext < end) && (*ext != 0xff)) {
		if (*ext == 0) {
			ext++;
		} else {
			u8 *opt = ext;

			ext += ext[1] + 2;
			if (ext <= end)
312
				bootp_process_vendor_field(opt);
313
		}
wdenk's avatar
wdenk committed
314 315
	}

316
	debug("[BOOTP] Received fields:\n");
317 318
	if (net_netmask.s_addr)
		debug("net_netmask : %pI4\n", &net_netmask);
319

320 321
	if (net_gateway.s_addr)
		debug("net_gateway	: %pI4", &net_gateway);
322

323 324 325
	if (net_boot_file_expected_size_in_blocks)
		debug("net_boot_file_expected_size_in_blocks : %d\n",
		      net_boot_file_expected_size_in_blocks);
wdenk's avatar
wdenk committed
326

327 328
	if (net_hostname[0])
		debug("net_hostname  : %s\n", net_hostname);
329

330 331
	if (net_root_path[0])
		debug("net_root_path  : %s\n", net_root_path);
332

333 334
	if (net_nis_domain[0])
		debug("net_nis_domain : %s\n", net_nis_domain);
335

336
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
337 338
	if (net_ntp_server)
		debug("net_ntp_server : %pI4\n", &net_ntp_server);
339
#endif
340
}
341

wdenk's avatar
wdenk committed
342 343 344
/*
 *	Handle a BOOTP received packet.
 */
345 346
static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
			  unsigned src, unsigned len)
wdenk's avatar
wdenk committed
347
{
348
	struct bootp_hdr *bp;
wdenk's avatar
wdenk committed
349

350
	debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
351
	      src, dest, len, sizeof(struct bootp_hdr));
wdenk's avatar
wdenk committed
352

353
	bp = (struct bootp_hdr *)pkt;
wdenk's avatar
wdenk committed
354

355
	/* Filter out pkts we don't want */
356
	if (check_reply_packet(pkt, dest, src, len))
wdenk's avatar
wdenk committed
357 358 359
		return;

	/*
360
	 *	Got a good BOOTP reply.	 Copy the data into our variables.
wdenk's avatar
wdenk committed
361
	 */
362
#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
363
	status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
wdenk's avatar
wdenk committed
364 365
#endif

366
	store_net_params(bp);		/* Store net parameters from reply */
wdenk's avatar
wdenk committed
367 368

	/* Retrieve extended information (we must parse the vendor area) */
369
	if (net_read_u32((u32 *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
370
		bootp_process_vendor((uchar *)&bp->bp_vend[4], len);
wdenk's avatar
wdenk committed
371

372
	net_set_timeout_handler(0, (thand_f *)0);
373
	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
wdenk's avatar
wdenk committed
374

375
	debug("Got good BOOTP\n");
wdenk's avatar
wdenk committed
376

377
	net_auto_load();
wdenk's avatar
wdenk committed
378
}
379
#endif
wdenk's avatar
wdenk committed
380 381 382 383

/*
 *	Timeout on BOOTP/DHCP request.
 */
384
static void bootp_timeout_handler(void)
wdenk's avatar
wdenk committed
385
{
386 387
	ulong time_taken = get_timer(bootp_start);

388
	if (time_taken >= time_taken_max) {
389
#ifdef CONFIG_BOOTP_MAY_FAIL
390
		puts("\nRetry time exceeded\n");
391
		net_set_state(NETLOOP_FAIL);
392
#else
393
		puts("\nRetry time exceeded; starting again\n");
394
		net_start_again();
395
#endif
wdenk's avatar
wdenk committed
396
	} else {
397
		bootp_timeout *= 2;
398 399
		if (bootp_timeout > 2000)
			bootp_timeout = 2000;
400
		net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
401
		bootp_request();
wdenk's avatar
wdenk committed
402 403 404
	}
}

405 406 407 408 409 410 411 412 413
#define put_vci(e, str)						\
	do {							\
		size_t vci_strlen = strlen(str);		\
		*e++ = 60;	/* Vendor Class Identifier */	\
		*e++ = vci_strlen;				\
		memcpy(e, str, vci_strlen);			\
		e += vci_strlen;				\
	} while (0)

414 415
static u8 *add_vci(u8 *e)
{
416 417 418
	char *vci = NULL;
	char *env_vci = getenv("bootp_vci");

419
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
420
	vci = CONFIG_SPL_NET_VCI_STRING;
421
#elif defined(CONFIG_BOOTP_VCI_STRING)
422
	vci = CONFIG_BOOTP_VCI_STRING;
423 424
#endif

425 426 427 428 429 430
	if (env_vci)
		vci = env_vci;

	if (vci)
		put_vci(e, vci);

431 432 433
	return e;
}

wdenk's avatar
wdenk committed
434 435 436
/*
 *	Initialize BOOTP extension fields in the request.
 */
437
#if defined(CONFIG_CMD_DHCP)
438 439
static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
			struct in_addr requested_ip)
wdenk's avatar
wdenk committed
440
{
441 442
	u8 *start = e;
	u8 *cnt;
443 444 445 446
#if defined(CONFIG_BOOTP_PXE)
	char *uuid;
	u16 clientarch;
#endif
447

448
#if defined(CONFIG_BOOTP_VENDOREX)
449
	u8 *x;
wdenk's avatar
wdenk committed
450
#endif
451
#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
Wolfgang Denk's avatar
Wolfgang Denk committed
452
	char *hostname;
453
#endif
wdenk's avatar
wdenk committed
454

455 456 457 458
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
wdenk's avatar
wdenk committed
459

460 461 462
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = message_type;
wdenk's avatar
wdenk committed
463

464 465
	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
466 467
	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
wdenk's avatar
wdenk committed
468

469 470
	if (server_ip.s_addr) {
		int tmp = ntohl(server_ip.s_addr);
wdenk's avatar
wdenk committed
471

472 473 474 475 476 477 478
		*e++ = 54;	/* ServerID */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
wdenk's avatar
wdenk committed
479

480 481
	if (requested_ip.s_addr) {
		int tmp = ntohl(requested_ip.s_addr);
wdenk's avatar
wdenk committed
482

483 484 485 486 487 488 489
		*e++ = 50;	/* Requested IP */
		*e++ = 4;
		*e++ = tmp >> 24;
		*e++ = tmp >> 16;
		*e++ = tmp >> 8;
		*e++ = tmp & 0xff;
	}
490
#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
491 492 493
	hostname = getenv("hostname");
	if (hostname) {
		int hostnamelen = strlen(hostname);
494 495 496

		*e++ = 12;	/* Hostname */
		*e++ = hostnamelen;
497
		memcpy(e, hostname, hostnamelen);
498 499
		e += hostnamelen;
	}
500 501
#endif

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
#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 */

523
			uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD);
524 525 526 527 528
			e += 16;
		} else {
			printf("Invalid pxeuuid: %s\n", uuid);
		}
	}
529
#endif
530

531
	e = add_vci(e);
532

533
#if defined(CONFIG_BOOTP_VENDOREX)
534 535
	x = dhcp_vendorex_prep(e);
	if (x)
536
		return x - start;
wdenk's avatar
wdenk committed
537 538
#endif

539 540 541
	*e++ = 55;		/* Parameter Request List */
	 cnt = e++;		/* Pointer to count of requested items */
	*cnt = 0;
542
#if defined(CONFIG_BOOTP_SUBNETMASK)
543 544
	*e++  = 1;		/* Subnet Mask */
	*cnt += 1;
wdenk's avatar
wdenk committed
545
#endif
546
#if defined(CONFIG_BOOTP_TIMEOFFSET)
547 548 549
	*e++  = 2;
	*cnt += 1;
#endif
550
#if defined(CONFIG_BOOTP_GATEWAY)
551 552
	*e++  = 3;		/* Router Option */
	*cnt += 1;
wdenk's avatar
wdenk committed
553
#endif
554
#if defined(CONFIG_BOOTP_DNS)
555 556
	*e++  = 6;		/* DNS Server(s) */
	*cnt += 1;
wdenk's avatar
wdenk committed
557
#endif
558
#if defined(CONFIG_BOOTP_HOSTNAME)
559 560
	*e++  = 12;		/* Hostname */
	*cnt += 1;
wdenk's avatar
wdenk committed
561
#endif
562
#if defined(CONFIG_BOOTP_BOOTFILESIZE)
563 564
	*e++  = 13;		/* Boot File Size */
	*cnt += 1;
wdenk's avatar
wdenk committed
565
#endif
566
#if defined(CONFIG_BOOTP_BOOTPATH)
567 568
	*e++  = 17;		/* Boot path */
	*cnt += 1;
wdenk's avatar
wdenk committed
569
#endif
570
#if defined(CONFIG_BOOTP_NISDOMAIN)
571 572
	*e++  = 40;		/* NIS Domain name request */
	*cnt += 1;
573
#endif
574
#if defined(CONFIG_BOOTP_NTPSERVER)
575 576
	*e++  = 42;
	*cnt += 1;
wdenk's avatar
wdenk committed
577
#endif
578 579 580 581
	/* no options, so back up to avoid sending an empty request list */
	if (*cnt == 0)
		e -= 2;

582
	*e++  = 255;		/* End of the list */
wdenk's avatar
wdenk committed
583

584
	/* Pad to minimal length */
wdenk's avatar
wdenk committed
585
#ifdef	CONFIG_DHCP_MIN_EXT_LEN
586
	while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
587
		*e++ = 0;
wdenk's avatar
wdenk committed
588 589
#endif

590
	return e - start;
wdenk's avatar
wdenk committed
591 592
}

593
#else
wdenk's avatar
wdenk committed
594
/*
595
 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
wdenk's avatar
wdenk committed
596
 */
597
static int bootp_extended(u8 *e)
wdenk's avatar
wdenk committed
598
{
599
	u8 *start = e;
wdenk's avatar
wdenk committed
600

601 602 603 604
	*e++ = 99;		/* RFC1048 Magic Cookie */
	*e++ = 130;
	*e++ = 83;
	*e++ = 99;
wdenk's avatar
wdenk committed
605

606
#if defined(CONFIG_CMD_DHCP)
607 608 609 610 611 612
	*e++ = 53;		/* DHCP Message Type */
	*e++ = 1;
	*e++ = DHCP_DISCOVER;

	*e++ = 57;		/* Maximum DHCP Message Size */
	*e++ = 2;
613 614
	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
615
#endif
wdenk's avatar
wdenk committed
616

617
	add_vci(e);
618

619
#if defined(CONFIG_BOOTP_SUBNETMASK)
620 621 622
	*e++ = 1;		/* Subnet mask request */
	*e++ = 4;
	e   += 4;
wdenk's avatar
wdenk committed
623 624
#endif

625
#if defined(CONFIG_BOOTP_GATEWAY)
626 627 628
	*e++ = 3;		/* Default gateway request */
	*e++ = 4;
	e   += 4;
wdenk's avatar
wdenk committed
629 630
#endif

631
#if defined(CONFIG_BOOTP_DNS)
632 633 634
	*e++ = 6;		/* Domain Name Server */
	*e++ = 4;
	e   += 4;
wdenk's avatar
wdenk committed
635 636
#endif

637
#if defined(CONFIG_BOOTP_HOSTNAME)
638 639 640
	*e++ = 12;		/* Host name request */
	*e++ = 32;
	e   += 32;
wdenk's avatar
wdenk committed
641 642
#endif

643
#if defined(CONFIG_BOOTP_BOOTFILESIZE)
644 645 646
	*e++ = 13;		/* Boot file size */
	*e++ = 2;
	e   += 2;
wdenk's avatar
wdenk committed
647 648
#endif

649
#if defined(CONFIG_BOOTP_BOOTPATH)
650 651 652
	*e++ = 17;		/* Boot path */
	*e++ = 32;
	e   += 32;
wdenk's avatar
wdenk committed
653 654
#endif

655
#if defined(CONFIG_BOOTP_NISDOMAIN)
656 657 658
	*e++ = 40;		/* NIS Domain name request */
	*e++ = 32;
	e   += 32;
wdenk's avatar
wdenk committed
659
#endif
660 661 662 663 664
#if defined(CONFIG_BOOTP_NTPSERVER)
	*e++ = 42;
	*e++ = 4;
	e   += 4;
#endif
wdenk's avatar
wdenk committed
665

666
	*e++ = 255;		/* End of the list */
wdenk's avatar
wdenk committed
667

668
	return e - start;
wdenk's avatar
wdenk committed
669
}
670
#endif
wdenk's avatar
wdenk committed
671

672
void bootp_reset(void)
673
{
674
	bootp_num_ids = 0;
675
	bootp_try = 0;
676
	bootp_start = get_timer(0);
677
	bootp_timeout = 250;
678 679
}

680
void bootp_request(void)
wdenk's avatar
wdenk committed
681
{
682
	uchar *pkt, *iphdr;
683
	struct bootp_hdr *bp;
684 685
	int extlen, pktlen, iplen;
	int eth_hdr_size;
686
#ifdef CONFIG_BOOTP_RANDOM_DELAY
Pavel Machek's avatar
Pavel Machek committed
687
	ulong rand_ms;
688
#endif
689
	u32 bootp_id;
690 691
	struct in_addr zero_ip;
	struct in_addr bcast_ip;
692
	char *ep;  /* Environment pointer */
wdenk's avatar
wdenk committed
693

694
	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
695
#if defined(CONFIG_CMD_DHCP)
wdenk's avatar
wdenk committed
696 697 698
	dhcp_state = INIT;
#endif

699 700 701 702 703 704
	ep = getenv("bootpretryperiod");
	if (ep != NULL)
		time_taken_max = simple_strtoul(ep, NULL, 10);
	else
		time_taken_max = TIMEOUT_MS;

wdenk's avatar
wdenk committed
705
#ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
706
	if (bootp_try == 0)
707
		srand_mac();
wdenk's avatar
wdenk committed
708

709 710
	if (bootp_try <= 2)	/* Start with max 1024 * 1ms */
		rand_ms = rand() >> (22 - bootp_try);
711 712
	else		/* After 3rd BOOTP request max 8192 * 1ms */
		rand_ms = rand() >> 19;
wdenk's avatar
wdenk committed
713

714
	printf("Random delay: %ld ms...\n", rand_ms);
Pavel Machek's avatar
Pavel Machek committed
715
	mdelay(rand_ms);
716

wdenk's avatar
wdenk committed
717 718
#endif	/* CONFIG_BOOTP_RANDOM_DELAY */

719
	printf("BOOTP broadcast %d\n", ++bootp_try);
720
	pkt = net_tx_packet;
721
	memset((void *)pkt, 0, PKTSIZE);
wdenk's avatar
wdenk committed
722

723
	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
724
	pkt += eth_hdr_size;
wdenk's avatar
wdenk committed
725 726

	/*
727 728 729 730
	 * 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.
wdenk's avatar
wdenk committed
731 732
	 * C. Hallinan, DS4.COM, Inc.
	 */
733
	/* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
734
		sizeof (struct bootp_hdr)); */
735
	iphdr = pkt;	/* We need this later for net_set_udp_header() */
736
	pkt += IP_UDP_HDR_SIZE;
wdenk's avatar
wdenk committed
737

738
	bp = (struct bootp_hdr *)pkt;
wdenk's avatar
wdenk committed
739 740 741 742
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
743 744 745 746 747
	/*
	 * according to RFC1542, should be 0 on first request, secs since
	 * first request otherwise
	 */
	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
748 749 750 751 752
	zero_ip.s_addr = 0;
	net_write_ip(&bp->bp_ciaddr, zero_ip);
	net_write_ip(&bp->bp_yiaddr, zero_ip);
	net_write_ip(&bp->bp_siaddr, zero_ip);
	net_write_ip(&bp->bp_giaddr, zero_ip);
753
	memcpy(bp->bp_chaddr, net_ethaddr, 6);
754
	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
wdenk's avatar
wdenk committed
755 756

	/* Request additional information from the BOOTP/DHCP server */
757
#if defined(CONFIG_CMD_DHCP)
758 759
	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_DISCOVER, zero_ip,
			       zero_ip);
wdenk's avatar
wdenk committed
760
#else
761
	extlen = bootp_extended((u8 *)bp->bp_vend);
762
#endif
wdenk's avatar
wdenk committed
763 764 765

	/*
	 *	Bootp ID is the lower 4 bytes of our ethernet address
766
	 *	plus the current time in ms.
wdenk's avatar
wdenk committed
767
	 */
768 769 770 771
	bootp_id = ((u32)net_ethaddr[2] << 24)
		| ((u32)net_ethaddr[3] << 16)
		| ((u32)net_ethaddr[4] << 8)
		| (u32)net_ethaddr[5];
772 773 774
	bootp_id += get_timer(0);
	bootp_id = htonl(bootp_id);
	bootp_add_id(bootp_id);
775
	net_copy_u32(&bp->bp_id, &bootp_id);
wdenk's avatar
wdenk committed
776 777 778 779 780

	/*
	 * Calculate proper packet lengths taking into account the
	 * variable size of the options field
	 */
781 782
	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
783 784
	bcast_ip.s_addr = 0xFFFFFFFFL;
	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
785
	net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
wdenk's avatar
wdenk committed
786

787
#if defined(CONFIG_CMD_DHCP)
wdenk's avatar
wdenk committed
788
	dhcp_state = SELECTING;
789
	net_set_udp_handler(dhcp_handler);
wdenk's avatar
wdenk committed
790
#else
791
	net_set_udp_handler(bootp_handler);
792
#endif
793
	net_send_packet(net_tx_packet, pktlen);
wdenk's avatar
wdenk committed
794 795
}

796
#if defined(CONFIG_CMD_DHCP)
797
static void dhcp_process_options(uchar *popt, uchar *end)
wdenk's avatar
wdenk committed
798 799
{
	int oplen, size;
800 801 802
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
	int *to_ptr;
#endif
wdenk's avatar
wdenk committed
803

804
	while (popt < end && *popt != 0xff) {
wdenk's avatar
wdenk committed
805
		oplen = *(popt + 1);
806
		switch (*popt) {
807 808 809
		case 0:
			oplen = -1; /* Pad omits len byte */
			break;
810
		case 1:
811
			net_copy_ip(&net_netmask, (popt + 2));
812
			break;
813
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
814
		case 2:		/* Time offset	*/
815
			to_ptr = &net_ntp_time_offset;
816
			net_copy_u32((u32 *)to_ptr, (u32 *)(popt + 2));
817
			net_ntp_time_offset = ntohl(net_ntp_time_offset);
818 819
			break;
#endif
820
		case 3:
821
			net_copy_ip(&net_gateway, (popt + 2));
822 823
			break;
		case 6:
824
			net_copy_ip(&net_dns_server, (popt + 2));
825
#if defined(CONFIG_BOOTP_DNS2)
826
			if (*(popt + 1) > 4)
827
				net_copy_ip(&net_dns_server2, (popt + 2 + 4));
828
#endif
829 830
			break;
		case 12:
831
			size = truncate_sz("Host Name",
832 833 834
				sizeof(net_hostname), oplen);
			memcpy(&net_hostname, popt + 2, size);
			net_hostname[size] = 0;
835 836 837 838
			break;
		case 15:	/* Ignore Domain Name Option */
			break;
		case 17:
839
			size = truncate_sz("Root Path",
840 841 842
				sizeof(net_root_path), oplen);
			memcpy(&net_root_path, popt + 2, size);
			net_root_path[size] = 0;
843
			break;
844 845
		case 28:	/* Ignore Broadcast Address Option */
			break;
846
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
847
		case 42:	/* NTP server IP */
848
			net_copy_ip(&net_ntp_server, (popt + 2));
849 850
			break;
#endif
851
		case 51:
852
			net_copy_u32(&dhcp_leasetime, (u32 *)(popt + 2));
853
			break;
854 855 856
		case 52:
			dhcp_option_overload = popt[2];
			break;
857 858 859
		case 53:	/* Ignore Message Type Option */
			break;
		case 54:
860
			net_copy_ip(&dhcp_server_ip, (popt + 2));
861 862 863 864 865
			break;
		case 58:	/* Ignore Renewal Time Option */
			break;
		case 59:	/* Ignore Rebinding Time Option */
			break;
866 867
		case 66:	/* Ignore TFTP server name */
			break;
868 869 870 871 872
		case 67:	/* Bootfile option */
			size = truncate_sz("Bootfile",
					   sizeof(net_boot_file_name), oplen);
			memcpy(&net_boot_file_name, popt + 2, size);
			net_boot_file_name[size] = 0;
873
			break;
874
		default:
875
#if defined(CONFIG_BOOTP_VENDOREX)
876
			if (dhcp_vendorex_proc(popt))
wdenk's avatar
wdenk committed
877
				break;
wdenk's avatar
wdenk committed
878
#endif
879
			printf("*** Unhandled DHCP Option in OFFER/ACK:"
880
			       " %d\n", *popt);
881
			break;
wdenk's avatar
wdenk committed
882 883 884 885 886
		}
		popt += oplen + 2;	/* Process next option */
	}
}

887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
static void dhcp_packet_process_options(struct bootp_hdr *bp)
{
	uchar *popt = (uchar *)&bp->bp_vend[4];
	uchar *end = popt + BOOTP_HDR_SIZE;

	if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
		return;

	dhcp_option_overload = 0;

	/*
	 * The 'options' field MUST be interpreted first, 'file' next,
	 * 'sname' last.
	 */
	dhcp_process_options(popt, end);

	if (dhcp_option_overload & OVERLOAD_FILE) {
		popt = (uchar *)bp->bp_file;
		end = popt + sizeof(bp->bp_file);
		dhcp_process_options(popt, end);
	}

	if (dhcp_option_overload & OVERLOAD_SNAME) {
		popt = (uchar *)bp->bp_sname;
		end = popt + sizeof(bp->bp_sname);
		dhcp_process_options(popt, end);
	}
}

916
static int dhcp_message_type(unsigned char *popt)
wdenk's avatar
wdenk committed
917
{
918
	if (net_read_u32((u32 *)popt) != htonl(BOOTP_VENDOR_MAGIC))
wdenk's avatar
wdenk committed
919 920 921
		return -1;

	popt += 4;
922 923
	while (*popt != 0xff) {
		if (*popt == 53)	/* DHCP Message Type */
wdenk's avatar
wdenk committed
924
			return *(popt + 2);
925 926 927 928 929 930 931
		if (*popt == 0)	{
			/* Pad */
			popt += 1;
		} else {
			/* Scan through all options */
			popt += *(popt + 1) + 2;
		}
wdenk's avatar
wdenk committed
932 933 934 935
	}
	return -1;
}

936
static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
wdenk's avatar
wdenk committed
937
{
938
	uchar *pkt, *iphdr;
939
	struct bootp_hdr *bp;
wdenk's avatar
wdenk committed
940
	int pktlen, iplen, extlen;
941
	int eth_hdr_size;
942 943 944
	struct in_addr offered_ip;
	struct in_addr zero_ip;
	struct in_addr bcast_ip;
wdenk's avatar
wdenk committed
945

946
	debug("dhcp_send_request_packet: Sending DHCPREQUEST\n");
947
	pkt = net_tx_packet;
948
	memset((void *)pkt, 0, PKTSIZE);
wdenk's avatar
wdenk committed
949

950
	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
951
	pkt += eth_hdr_size;
wdenk's avatar
wdenk committed
952

953
	iphdr = pkt;	/* We'll need this later to set proper pkt size */
954
	pkt += IP_UDP_HDR_SIZE;
wdenk's avatar
wdenk committed
955

956
	bp = (struct bootp_hdr *)pkt;
wdenk's avatar
wdenk committed
957 958 959 960
	bp->bp_op = OP_BOOTREQUEST;
	bp->bp_htype = HWT_ETHER;
	bp->bp_hlen = HWL_ETHER;
	bp->bp_hops = 0;
961
	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
962 963
	/* Do not set the client IP, your IP, or server IP yet, since it
	 * hasn't been ACK'ed by the server yet */
Justin Flammia's avatar
Justin Flammia committed
964

Wolfgang Denk's avatar
Wolfgang Denk committed
965
	/*
966 967 968
	 * RFC3046 requires Relay Agents to discard packets with
	 * nonzero and offered giaddr
	 */
969 970
	zero_ip.s_addr = 0;
	net_write_ip(&bp->bp_giaddr, zero_ip);
971

972
	memcpy(bp->bp_chaddr, net_ethaddr, 6);
973
	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
wdenk's avatar
wdenk committed
974 975 976 977 978

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

979
	net_copy_u32(&bp->bp_id, &bp_offer->bp_id);
wdenk's avatar
wdenk committed
980 981 982 983

	/*
	 * Copy options from OFFER packet if present
	 */
Justin Flammia's avatar
Justin Flammia committed
984 985

	/* Copy offered IP into the parameters request list */
986 987 988
	net_copy_ip(&offered_ip, &bp_offer->bp_yiaddr);
	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_REQUEST,
		dhcp_server_ip, offered_ip);
wdenk's avatar
wdenk committed
989

990 991
	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
992 993
	bcast_ip.s_addr = 0xFFFFFFFFL;
	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
wdenk's avatar
wdenk committed
994

995 996 997
#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
	udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
#endif	/* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
998
	debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
999
	net_send_packet(net_tx_packet, pktlen);
wdenk's avatar
wdenk committed
1000 1001 1002 1003 1004
}

/*
 *	Handle DHCP received packets.
 */
1005 1006
static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
			 unsigned src, unsigned len)
wdenk's avatar
wdenk committed
1007
{
1008
	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
wdenk's avatar
wdenk committed
1009

1010
	debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
1011
	      src, dest, len, dhcp_state);
wdenk's avatar
wdenk committed
1012

1013
	/* Filter out pkts we don't want */
1014
	if (check_reply_packet(pkt, dest, src, len))
wdenk's avatar
wdenk committed
1015 1016
		return;

1017 1018
	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
	      "%d\n", src, dest, len, dhcp_state);
wdenk's avatar
wdenk committed
1019

1020 1021 1022
	if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
		return;

wdenk's avatar
wdenk committed
1023 1024 1025 1026
	switch (dhcp_state) {
	case SELECTING:
		/*
		 * Wait an appropriate time for any potential DHCPOFFER packets
1027 1028 1029
		 * 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.
wdenk's avatar
wdenk committed
1030
		 */
1031
		debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
1032
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk's avatar
wdenk committed
1033
		if (strncmp(bp->bp_file,
1034
			    CONFIG_SYS_BOOTFILE_PREFIX,
1035
			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
1036
#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
1037
			dhcp_packet_process_options(bp);
1038
			efi_net_set_dhcp_ack(pkt, len);
wdenk's avatar
wdenk committed
1039

1040
			debug("TRANSITIONING TO REQUESTING STATE\n");
wdenk's avatar
wdenk committed
1041
			dhcp_state = REQUESTING;
1042

1043
			net_set_timeout_handler(5000, bootp_timeout_handler);
1044
			dhcp_send_request_packet(bp);
1045
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
wdenk's avatar
wdenk committed
1046
		}
1047
#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
wdenk's avatar
wdenk committed
1048 1049 1050 1051

		return;
		break;
	case REQUESTING:
1052
		debug("DHCP State: REQUESTING\n");
wdenk's avatar
wdenk committed
1053

1054
		if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
1055
			dhcp_packet_process_options(bp);
1056
			/* Store net params from reply */
1057
			store_net_params(bp);
wdenk's avatar
wdenk committed
1058
			dhcp_state = BOUND;
1059
			printf("DHCP client bound to address %pI4 (%lu ms)\n",
1060
			       &net_ip, get_timer(bootp_start));
1061
			net_set_timeout_handler(0, (thand_f *)0