xref: /openbmc/u-boot/net/bootp.c (revision d4c7a9348f27c8e3fdb1b754d8f0d1fa27375d1c)
13861aa5cSwdenk /*
23861aa5cSwdenk  *	Based on LiMon - BOOTP.
33861aa5cSwdenk  *
43861aa5cSwdenk  *	Copyright 1994, 1995, 2000 Neil Russell.
53861aa5cSwdenk  *	(See License)
63861aa5cSwdenk  *	Copyright 2000 Roland Borde
73861aa5cSwdenk  *	Copyright 2000 Paolo Scaffardi
8232c150aSwdenk  *	Copyright 2000-2004 Wolfgang Denk, wd@denx.de
93861aa5cSwdenk  */
103861aa5cSwdenk 
113861aa5cSwdenk #include <common.h>
123861aa5cSwdenk #include <command.h>
130efe1bcfSAlexander Graf #include <efi_loader.h>
143861aa5cSwdenk #include <net.h>
1534696958SLukasz Majewski #include <net/tftp.h>
163861aa5cSwdenk #include "bootp.h"
172d8d190cSUri Mashiach #ifdef CONFIG_LED_STATUS
183861aa5cSwdenk #include <status_led.h>
193861aa5cSwdenk #endif
20db7720baSKim Phillips #ifdef CONFIG_BOOTP_RANDOM_DELAY
21db7720baSKim Phillips #include "net_rand.h"
22db7720baSKim Phillips #endif
233861aa5cSwdenk 
243861aa5cSwdenk #define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
253861aa5cSwdenk 
26f59be6e8SStephen Warren /*
27f59be6e8SStephen Warren  * The timeout for the initial BOOTP/DHCP request used to be described by a
28f59be6e8SStephen Warren  * counter of fixed-length timeout periods. TIMEOUT_COUNT represents
29f59be6e8SStephen Warren  * that counter
30f59be6e8SStephen Warren  *
31f59be6e8SStephen Warren  * Now that the timeout periods are variable (exponential backoff and retry)
32f59be6e8SStephen Warren  * we convert the timeout count to the absolute time it would have take to
33f59be6e8SStephen Warren  * execute that many retries, and keep sending retry packets until that time
34f59be6e8SStephen Warren  * is reached.
35f59be6e8SStephen Warren  */
363861aa5cSwdenk #ifndef CONFIG_NET_RETRY_COUNT
373861aa5cSwdenk # define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
383861aa5cSwdenk #else
393861aa5cSwdenk # define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
403861aa5cSwdenk #endif
41f59be6e8SStephen Warren #define TIMEOUT_MS	((3 + (TIMEOUT_COUNT * 5)) * 1000)
423861aa5cSwdenk 
433861aa5cSwdenk #define PORT_BOOTPS	67		/* BOOTP server UDP port */
443861aa5cSwdenk #define PORT_BOOTPC	68		/* BOOTP client UDP port */
453861aa5cSwdenk 
463861aa5cSwdenk #ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list */
473861aa5cSwdenk #define CONFIG_DHCP_MIN_EXT_LEN 64
483861aa5cSwdenk #endif
493861aa5cSwdenk 
5092ac8accSThierry Reding #ifndef CONFIG_BOOTP_ID_CACHE_SIZE
5192ac8accSThierry Reding #define CONFIG_BOOTP_ID_CACHE_SIZE 4
5292ac8accSThierry Reding #endif
5392ac8accSThierry Reding 
545917e7d1SSergey Temerkhanov u32		bootp_ids[CONFIG_BOOTP_ID_CACHE_SIZE];
5592ac8accSThierry Reding unsigned int	bootp_num_ids;
567044c6bbSJoe Hershberger int		bootp_try;
57f59be6e8SStephen Warren ulong		bootp_start;
58f59be6e8SStephen Warren ulong		bootp_timeout;
59586cbe51SJoe Hershberger char net_nis_domain[32] = {0,}; /* Our NIS domain */
60586cbe51SJoe Hershberger char net_hostname[32] = {0,}; /* Our hostname */
61586cbe51SJoe Hershberger char net_root_path[64] = {0,}; /* Our bootpath */
623861aa5cSwdenk 
6350768f5bSAlexandre Messier static ulong time_taken_max;
6450768f5bSAlexandre Messier 
65643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
6606370590SKim Phillips static dhcp_state_t dhcp_state = INIT;
675917e7d1SSergey Temerkhanov static u32 dhcp_leasetime;
68049a95a7SJoe Hershberger static struct in_addr dhcp_server_ip;
69ec87b1b3SStefan Brüns static u8 dhcp_option_overload;
70ec87b1b3SStefan Brüns #define OVERLOAD_FILE 1
71ec87b1b3SStefan Brüns #define OVERLOAD_SNAME 2
72049a95a7SJoe Hershberger static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
73049a95a7SJoe Hershberger 			unsigned src, unsigned len);
743861aa5cSwdenk 
753861aa5cSwdenk /* For Debug */
763e38691eSwdenk #if 0
773e38691eSwdenk static char *dhcpmsg2str(int type)
783861aa5cSwdenk {
793861aa5cSwdenk 	switch (type) {
803861aa5cSwdenk 	case 1:	 return "DHCPDISCOVER"; break;
813861aa5cSwdenk 	case 2:	 return "DHCPOFFER";	break;
823861aa5cSwdenk 	case 3:	 return "DHCPREQUEST";	break;
833861aa5cSwdenk 	case 4:	 return "DHCPDECLINE";	break;
843861aa5cSwdenk 	case 5:	 return "DHCPACK";	break;
853861aa5cSwdenk 	case 6:	 return "DHCPNACK";	break;
863861aa5cSwdenk 	case 7:	 return "DHCPRELEASE";	break;
873861aa5cSwdenk 	default: return "UNKNOWN/INVALID MSG TYPE"; break;
883861aa5cSwdenk 	}
893861aa5cSwdenk }
903e38691eSwdenk #endif
91610f2e9cSJon Loeliger #endif
923861aa5cSwdenk 
bootp_add_id(ulong id)9392ac8accSThierry Reding static void bootp_add_id(ulong id)
9492ac8accSThierry Reding {
9592ac8accSThierry Reding 	if (bootp_num_ids >= ARRAY_SIZE(bootp_ids)) {
9692ac8accSThierry Reding 		size_t size = sizeof(bootp_ids) - sizeof(id);
9792ac8accSThierry Reding 
9892ac8accSThierry Reding 		memmove(bootp_ids, &bootp_ids[1], size);
9992ac8accSThierry Reding 		bootp_ids[bootp_num_ids - 1] = id;
10092ac8accSThierry Reding 	} else {
10192ac8accSThierry Reding 		bootp_ids[bootp_num_ids] = id;
10292ac8accSThierry Reding 		bootp_num_ids++;
10392ac8accSThierry Reding 	}
10492ac8accSThierry Reding }
10592ac8accSThierry Reding 
bootp_match_id(ulong id)10692ac8accSThierry Reding static bool bootp_match_id(ulong id)
10792ac8accSThierry Reding {
10892ac8accSThierry Reding 	unsigned int i;
10992ac8accSThierry Reding 
11092ac8accSThierry Reding 	for (i = 0; i < bootp_num_ids; i++)
11192ac8accSThierry Reding 		if (bootp_ids[i] == id)
11292ac8accSThierry Reding 			return true;
11392ac8accSThierry Reding 
11492ac8accSThierry Reding 	return false;
11592ac8accSThierry Reding }
11692ac8accSThierry Reding 
check_reply_packet(uchar * pkt,unsigned dest,unsigned src,unsigned len)117867d6ae2SStefan Brüns static int check_reply_packet(uchar *pkt, unsigned dest, unsigned src,
118867d6ae2SStefan Brüns 			      unsigned len)
1193861aa5cSwdenk {
1207044c6bbSJoe Hershberger 	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
1213861aa5cSwdenk 	int retval = 0;
1223861aa5cSwdenk 
1233861aa5cSwdenk 	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
1243861aa5cSwdenk 		retval = -1;
1257044c6bbSJoe Hershberger 	else if (len < sizeof(struct bootp_hdr) - OPT_FIELD_SIZE)
1263861aa5cSwdenk 		retval = -2;
127867d6ae2SStefan Brüns 	else if (bp->bp_op != OP_BOOTREPLY)
1283861aa5cSwdenk 		retval = -3;
1293861aa5cSwdenk 	else if (bp->bp_htype != HWT_ETHER)
1303861aa5cSwdenk 		retval = -4;
1313861aa5cSwdenk 	else if (bp->bp_hlen != HWL_ETHER)
1323861aa5cSwdenk 		retval = -5;
1335917e7d1SSergey Temerkhanov 	else if (!bootp_match_id(net_read_u32(&bp->bp_id)))
1343861aa5cSwdenk 		retval = -6;
135214cc905SAnton Persson 	else if (memcmp(bp->bp_chaddr, net_ethaddr, HWL_ETHER) != 0)
136214cc905SAnton Persson 		retval = -7;
1373861aa5cSwdenk 
1383861aa5cSwdenk 	debug("Filtering pkt = %d\n", retval);
1393861aa5cSwdenk 
1403861aa5cSwdenk 	return retval;
1413861aa5cSwdenk }
1423861aa5cSwdenk 
1433861aa5cSwdenk /*
1443861aa5cSwdenk  * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
1453861aa5cSwdenk  */
store_net_params(struct bootp_hdr * bp)1467044c6bbSJoe Hershberger static void store_net_params(struct bootp_hdr *bp)
1473861aa5cSwdenk {
1485d110f0aSWilson Callan #if !defined(CONFIG_BOOTP_SERVERIP)
149049a95a7SJoe Hershberger 	struct in_addr tmp_ip;
150*bdce340cSAlexander Graf 	bool overwrite_serverip = true;
151*bdce340cSAlexander Graf 
152*bdce340cSAlexander Graf #if defined(CONFIG_BOOTP_PREFER_SERVERIP)
153*bdce340cSAlexander Graf 	overwrite_serverip = false;
154*bdce340cSAlexander Graf #endif
1551752f0fdSJoe Hershberger 
156049a95a7SJoe Hershberger 	net_copy_ip(&tmp_ip, &bp->bp_siaddr);
157*bdce340cSAlexander Graf 	if (tmp_ip.s_addr != 0 && (overwrite_serverip || !net_server_ip.s_addr))
158049a95a7SJoe Hershberger 		net_copy_ip(&net_server_ip, &bp->bp_siaddr);
1591203fcceSJoe Hershberger 	memcpy(net_server_ethaddr,
1601203fcceSJoe Hershberger 	       ((struct ethernet_hdr *)net_rx_packet)->et_src, 6);
161ec87b1b3SStefan Brüns 	if (
162ec87b1b3SStefan Brüns #if defined(CONFIG_CMD_DHCP)
163ec87b1b3SStefan Brüns 	    !(dhcp_option_overload & OVERLOAD_FILE) &&
164ec87b1b3SStefan Brüns #endif
165449312c1SAlexander Graf 	    (strlen(bp->bp_file) > 0) &&
166449312c1SAlexander Graf 	    !net_boot_file_name_explicit) {
1671411157dSJoe Hershberger 		copy_filename(net_boot_file_name, bp->bp_file,
1681411157dSJoe Hershberger 			      sizeof(net_boot_file_name));
169ec87b1b3SStefan Brüns 	}
1703861aa5cSwdenk 
1711411157dSJoe Hershberger 	debug("net_boot_file_name: %s\n", net_boot_file_name);
1723861aa5cSwdenk 
1733861aa5cSwdenk 	/* Propagate to environment:
1743861aa5cSwdenk 	 * don't delete exising entry when BOOTP / DHCP reply does
1753861aa5cSwdenk 	 * not contain a new value
1763861aa5cSwdenk 	 */
1771411157dSJoe Hershberger 	if (*net_boot_file_name)
178382bee57SSimon Glass 		env_set("bootfile", net_boot_file_name);
179ecec4e9cSWu, Josh #endif
180049a95a7SJoe Hershberger 	net_copy_ip(&net_ip, &bp->bp_yiaddr);
1813861aa5cSwdenk }
1823861aa5cSwdenk 
truncate_sz(const char * name,int maxlen,int curlen)1833861aa5cSwdenk static int truncate_sz(const char *name, int maxlen, int curlen)
1843861aa5cSwdenk {
1853861aa5cSwdenk 	if (curlen >= maxlen) {
1863090b7e3SJoe Hershberger 		printf("*** WARNING: %s is too long (%d - max: %d)"
1873090b7e3SJoe Hershberger 			" - truncated\n", name, curlen, maxlen);
1883861aa5cSwdenk 		curlen = maxlen - 1;
1893861aa5cSwdenk 	}
1903090b7e3SJoe Hershberger 	return curlen;
1913861aa5cSwdenk }
1923861aa5cSwdenk 
193643d1ab2SJon Loeliger #if !defined(CONFIG_CMD_DHCP)
1943861aa5cSwdenk 
bootp_process_vendor_field(u8 * ext)1957044c6bbSJoe Hershberger static void bootp_process_vendor_field(u8 *ext)
1963861aa5cSwdenk {
1973861aa5cSwdenk 	int size = *(ext + 1);
1983861aa5cSwdenk 
1990ebf04c6SRobin Getz 	debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
200232c150aSwdenk 	      *(ext + 1));
2013861aa5cSwdenk 
2021411157dSJoe Hershberger 	net_boot_file_expected_size_in_blocks = 0;
2033861aa5cSwdenk 
2043861aa5cSwdenk 	switch (*ext) {
2053861aa5cSwdenk 		/* Fixed length fields */
2063861aa5cSwdenk 	case 1:			/* Subnet mask */
207049a95a7SJoe Hershberger 		if (net_netmask.s_addr == 0)
208049a95a7SJoe Hershberger 			net_copy_ip(&net_netmask, (struct in_addr *)(ext + 2));
2093861aa5cSwdenk 		break;
2103861aa5cSwdenk 	case 2:			/* Time offset - Not yet supported */
2113861aa5cSwdenk 		break;
2123861aa5cSwdenk 		/* Variable length fields */
2133861aa5cSwdenk 	case 3:			/* Gateways list */
214049a95a7SJoe Hershberger 		if (net_gateway.s_addr == 0)
215049a95a7SJoe Hershberger 			net_copy_ip(&net_gateway, (struct in_addr *)(ext + 2));
2163861aa5cSwdenk 		break;
2173861aa5cSwdenk 	case 4:			/* Time server - Not yet supported */
2183861aa5cSwdenk 		break;
2193861aa5cSwdenk 	case 5:			/* IEN-116 name server - Not yet supported */
2203861aa5cSwdenk 		break;
2213861aa5cSwdenk 	case 6:
222049a95a7SJoe Hershberger 		if (net_dns_server.s_addr == 0)
223049a95a7SJoe Hershberger 			net_copy_ip(&net_dns_server,
224049a95a7SJoe Hershberger 				    (struct in_addr *)(ext + 2));
2251fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_DNS2)
226049a95a7SJoe Hershberger 		if ((net_dns_server2.s_addr == 0) && (size > 4))
227049a95a7SJoe Hershberger 			net_copy_ip(&net_dns_server2,
228049a95a7SJoe Hershberger 				    (struct in_addr *)(ext + 2 + 4));
229fe389a82Sstroese #endif
2303861aa5cSwdenk 		break;
2313861aa5cSwdenk 	case 7:			/* Log server - Not yet supported */
2323861aa5cSwdenk 		break;
2333861aa5cSwdenk 	case 8:			/* Cookie/Quote server - Not yet supported */
2343861aa5cSwdenk 		break;
2353861aa5cSwdenk 	case 9:			/* LPR server - Not yet supported */
2363861aa5cSwdenk 		break;
2373861aa5cSwdenk 	case 10:		/* Impress server - Not yet supported */
2383861aa5cSwdenk 		break;
2393861aa5cSwdenk 	case 11:		/* RPL server - Not yet supported */
2403861aa5cSwdenk 		break;
2413861aa5cSwdenk 	case 12:		/* Host name */
242586cbe51SJoe Hershberger 		if (net_hostname[0] == 0) {
2433090b7e3SJoe Hershberger 			size = truncate_sz("Host Name",
244586cbe51SJoe Hershberger 				sizeof(net_hostname), size);
245586cbe51SJoe Hershberger 			memcpy(&net_hostname, ext + 2, size);
246586cbe51SJoe Hershberger 			net_hostname[size] = 0;
2473861aa5cSwdenk 		}
2483861aa5cSwdenk 		break;
2493861aa5cSwdenk 	case 13:		/* Boot file size */
2503861aa5cSwdenk 		if (size == 2)
2511411157dSJoe Hershberger 			net_boot_file_expected_size_in_blocks =
2521411157dSJoe Hershberger 				ntohs(*(ushort *)(ext + 2));
2533861aa5cSwdenk 		else if (size == 4)
2541411157dSJoe Hershberger 			net_boot_file_expected_size_in_blocks =
2551411157dSJoe Hershberger 				ntohl(*(ulong *)(ext + 2));
2563861aa5cSwdenk 		break;
2573861aa5cSwdenk 	case 14:		/* Merit dump file - Not yet supported */
2583861aa5cSwdenk 		break;
2593861aa5cSwdenk 	case 15:		/* Domain name - Not yet supported */
2603861aa5cSwdenk 		break;
2613861aa5cSwdenk 	case 16:		/* Swap server - Not yet supported */
2623861aa5cSwdenk 		break;
2633861aa5cSwdenk 	case 17:		/* Root path */
264586cbe51SJoe Hershberger 		if (net_root_path[0] == 0) {
2653090b7e3SJoe Hershberger 			size = truncate_sz("Root Path",
266586cbe51SJoe Hershberger 				sizeof(net_root_path), size);
267586cbe51SJoe Hershberger 			memcpy(&net_root_path, ext + 2, size);
268586cbe51SJoe Hershberger 			net_root_path[size] = 0;
2693861aa5cSwdenk 		}
2703861aa5cSwdenk 		break;
2713861aa5cSwdenk 	case 18:		/* Extension path - Not yet supported */
2723861aa5cSwdenk 		/*
27347cd00faSwdenk 		 * This can be used to send the information of the
2743861aa5cSwdenk 		 * vendor area in another file that the client can
2753861aa5cSwdenk 		 * access via TFTP.
2763861aa5cSwdenk 		 */
2773861aa5cSwdenk 		break;
2783861aa5cSwdenk 		/* IP host layer fields */
2793861aa5cSwdenk 	case 40:		/* NIS Domain name */
280586cbe51SJoe Hershberger 		if (net_nis_domain[0] == 0) {
2813090b7e3SJoe Hershberger 			size = truncate_sz("NIS Domain Name",
282586cbe51SJoe Hershberger 				sizeof(net_nis_domain), size);
283586cbe51SJoe Hershberger 			memcpy(&net_nis_domain, ext + 2, size);
284586cbe51SJoe Hershberger 			net_nis_domain[size] = 0;
2853861aa5cSwdenk 		}
2863861aa5cSwdenk 		break;
28709e3a67dSLuuk Paulussen #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
28809e3a67dSLuuk Paulussen 	case 42:	/* NTP server IP */
289049a95a7SJoe Hershberger 		net_copy_ip(&net_ntp_server, (struct in_addr *)(ext + 2));
29009e3a67dSLuuk Paulussen 		break;
29109e3a67dSLuuk Paulussen #endif
2923861aa5cSwdenk 		/* Application layer fields */
2933861aa5cSwdenk 	case 43:		/* Vendor specific info - Not yet supported */
2943861aa5cSwdenk 		/*
29547cd00faSwdenk 		 * Binary information to exchange specific
2963861aa5cSwdenk 		 * product information.
2973861aa5cSwdenk 		 */
2983861aa5cSwdenk 		break;
2993861aa5cSwdenk 		/* Reserved (custom) fields (128..254) */
3003861aa5cSwdenk 	}
3013861aa5cSwdenk }
3023861aa5cSwdenk 
bootp_process_vendor(u8 * ext,int size)3037044c6bbSJoe Hershberger static void bootp_process_vendor(u8 *ext, int size)
3043861aa5cSwdenk {
3053861aa5cSwdenk 	u8 *end = ext + size;
3063861aa5cSwdenk 
3070ebf04c6SRobin Getz 	debug("[BOOTP] Checking extension (%d bytes)...\n", size);
3083861aa5cSwdenk 
3093861aa5cSwdenk 	while ((ext < end) && (*ext != 0xff)) {
3103861aa5cSwdenk 		if (*ext == 0) {
3113861aa5cSwdenk 			ext++;
3123861aa5cSwdenk 		} else {
3133861aa5cSwdenk 			u8 *opt = ext;
314232c150aSwdenk 
3153861aa5cSwdenk 			ext += ext[1] + 2;
3163861aa5cSwdenk 			if (ext <= end)
3177044c6bbSJoe Hershberger 				bootp_process_vendor_field(opt);
3183861aa5cSwdenk 		}
3193861aa5cSwdenk 	}
3203861aa5cSwdenk 
3210ebf04c6SRobin Getz 	debug("[BOOTP] Received fields:\n");
322049a95a7SJoe Hershberger 	if (net_netmask.s_addr)
323049a95a7SJoe Hershberger 		debug("net_netmask : %pI4\n", &net_netmask);
3243861aa5cSwdenk 
325049a95a7SJoe Hershberger 	if (net_gateway.s_addr)
326049a95a7SJoe Hershberger 		debug("net_gateway	: %pI4", &net_gateway);
3273861aa5cSwdenk 
3281411157dSJoe Hershberger 	if (net_boot_file_expected_size_in_blocks)
3291411157dSJoe Hershberger 		debug("net_boot_file_expected_size_in_blocks : %d\n",
3301411157dSJoe Hershberger 		      net_boot_file_expected_size_in_blocks);
3313861aa5cSwdenk 
332586cbe51SJoe Hershberger 	if (net_hostname[0])
333586cbe51SJoe Hershberger 		debug("net_hostname  : %s\n", net_hostname);
3343861aa5cSwdenk 
335586cbe51SJoe Hershberger 	if (net_root_path[0])
336586cbe51SJoe Hershberger 		debug("net_root_path  : %s\n", net_root_path);
3373861aa5cSwdenk 
338586cbe51SJoe Hershberger 	if (net_nis_domain[0])
339586cbe51SJoe Hershberger 		debug("net_nis_domain : %s\n", net_nis_domain);
3403861aa5cSwdenk 
34109e3a67dSLuuk Paulussen #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
3424b4dc521SChris Packham 	if (net_ntp_server.s_addr)
343049a95a7SJoe Hershberger 		debug("net_ntp_server : %pI4\n", &net_ntp_server);
34409e3a67dSLuuk Paulussen #endif
3453861aa5cSwdenk }
34609349866SSimon Glass 
3473861aa5cSwdenk /*
3483861aa5cSwdenk  *	Handle a BOOTP received packet.
3493861aa5cSwdenk  */
bootp_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)350049a95a7SJoe Hershberger static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
351049a95a7SJoe Hershberger 			  unsigned src, unsigned len)
3523861aa5cSwdenk {
3537044c6bbSJoe Hershberger 	struct bootp_hdr *bp;
3543861aa5cSwdenk 
355b64f190bSWolfgang Denk 	debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
3567044c6bbSJoe Hershberger 	      src, dest, len, sizeof(struct bootp_hdr));
3573861aa5cSwdenk 
3587044c6bbSJoe Hershberger 	bp = (struct bootp_hdr *)pkt;
3593861aa5cSwdenk 
3603090b7e3SJoe Hershberger 	/* Filter out pkts we don't want */
361867d6ae2SStefan Brüns 	if (check_reply_packet(pkt, dest, src, len))
3623861aa5cSwdenk 		return;
3633861aa5cSwdenk 
3643861aa5cSwdenk 	/*
3653861aa5cSwdenk 	 *	Got a good BOOTP reply.	 Copy the data into our variables.
3663861aa5cSwdenk 	 */
3672d8d190cSUri Mashiach #if defined(CONFIG_LED_STATUS) && defined(CONFIG_LED_STATUS_BOOT_ENABLE)
3682d8d190cSUri Mashiach 	status_led_set(CONFIG_LED_STATUS_BOOT, CONFIG_LED_STATUS_OFF);
3693861aa5cSwdenk #endif
3703861aa5cSwdenk 
3717044c6bbSJoe Hershberger 	store_net_params(bp);		/* Store net parameters from reply */
3723861aa5cSwdenk 
3733861aa5cSwdenk 	/* Retrieve extended information (we must parse the vendor area) */
3745917e7d1SSergey Temerkhanov 	if (net_read_u32((u32 *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
3757044c6bbSJoe Hershberger 		bootp_process_vendor((uchar *)&bp->bp_vend[4], len);
3763861aa5cSwdenk 
377bc0571fcSJoe Hershberger 	net_set_timeout_handler(0, (thand_f *)0);
378573f14feSSimon Glass 	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
3793861aa5cSwdenk 
3803861aa5cSwdenk 	debug("Got good BOOTP\n");
3813861aa5cSwdenk 
382e4a3d57dSSimon Glass 	net_auto_load();
3833861aa5cSwdenk }
384610f2e9cSJon Loeliger #endif
3853861aa5cSwdenk 
3863861aa5cSwdenk /*
3873861aa5cSwdenk  *	Timeout on BOOTP/DHCP request.
3883861aa5cSwdenk  */
bootp_timeout_handler(void)3897044c6bbSJoe Hershberger static void bootp_timeout_handler(void)
3903861aa5cSwdenk {
391f59be6e8SStephen Warren 	ulong time_taken = get_timer(bootp_start);
392f59be6e8SStephen Warren 
39350768f5bSAlexandre Messier 	if (time_taken >= time_taken_max) {
3942c00e099SJoe Hershberger #ifdef CONFIG_BOOTP_MAY_FAIL
3952099b9f2SJoe Hershberger 		char *ethrotate;
3962099b9f2SJoe Hershberger 
3972099b9f2SJoe Hershberger 		ethrotate = env_get("ethrotate");
3982099b9f2SJoe Hershberger 		if ((ethrotate && strcmp(ethrotate, "no") == 0) ||
3992099b9f2SJoe Hershberger 		    net_restart_wrap) {
400f59be6e8SStephen Warren 			puts("\nRetry time exceeded\n");
401b977aa80Sbenoit.thebaudeau@advans 			net_set_state(NETLOOP_FAIL);
4022099b9f2SJoe Hershberger 		} else
4032099b9f2SJoe Hershberger #endif
4042099b9f2SJoe Hershberger 		{
405f59be6e8SStephen Warren 			puts("\nRetry time exceeded; starting again\n");
406bc0571fcSJoe Hershberger 			net_start_again();
4072099b9f2SJoe Hershberger 		}
4083861aa5cSwdenk 	} else {
409f59be6e8SStephen Warren 		bootp_timeout *= 2;
41092ac8accSThierry Reding 		if (bootp_timeout > 2000)
41192ac8accSThierry Reding 			bootp_timeout = 2000;
412bc0571fcSJoe Hershberger 		net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
4137044c6bbSJoe Hershberger 		bootp_request();
4143861aa5cSwdenk 	}
4153861aa5cSwdenk }
4163861aa5cSwdenk 
4179ace17c8SIlya Yanok #define put_vci(e, str)						\
4189ace17c8SIlya Yanok 	do {							\
4199ace17c8SIlya Yanok 		size_t vci_strlen = strlen(str);		\
4209ace17c8SIlya Yanok 		*e++ = 60;	/* Vendor Class Identifier */	\
4219ace17c8SIlya Yanok 		*e++ = vci_strlen;				\
4229ace17c8SIlya Yanok 		memcpy(e, str, vci_strlen);			\
4239ace17c8SIlya Yanok 		e += vci_strlen;				\
4249ace17c8SIlya Yanok 	} while (0)
4259ace17c8SIlya Yanok 
add_vci(u8 * e)4264570a993SAlexander Graf static u8 *add_vci(u8 *e)
4274570a993SAlexander Graf {
42820898ea9SAlexander Graf 	char *vci = NULL;
42900caae6dSSimon Glass 	char *env_vci = env_get("bootp_vci");
43020898ea9SAlexander Graf 
4314570a993SAlexander Graf #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
43220898ea9SAlexander Graf 	vci = CONFIG_SPL_NET_VCI_STRING;
4334570a993SAlexander Graf #elif defined(CONFIG_BOOTP_VCI_STRING)
43420898ea9SAlexander Graf 	vci = CONFIG_BOOTP_VCI_STRING;
4354570a993SAlexander Graf #endif
4364570a993SAlexander Graf 
43720898ea9SAlexander Graf 	if (env_vci)
43820898ea9SAlexander Graf 		vci = env_vci;
43920898ea9SAlexander Graf 
44020898ea9SAlexander Graf 	if (vci)
44120898ea9SAlexander Graf 		put_vci(e, vci);
44220898ea9SAlexander Graf 
4434570a993SAlexander Graf 	return e;
4444570a993SAlexander Graf }
4454570a993SAlexander Graf 
4463861aa5cSwdenk /*
4473861aa5cSwdenk  *	Initialize BOOTP extension fields in the request.
4483861aa5cSwdenk  */
449643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
dhcp_extended(u8 * e,int message_type,struct in_addr server_ip,struct in_addr requested_ip)450049a95a7SJoe Hershberger static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
451049a95a7SJoe Hershberger 			struct in_addr requested_ip)
4523861aa5cSwdenk {
4533861aa5cSwdenk 	u8 *start = e;
4543861aa5cSwdenk 	u8 *cnt;
455bc6fc28bSAlexander Graf #ifdef CONFIG_LIB_UUID
456d2b5d5c4SJason Hobbs 	char *uuid;
457d2b5d5c4SJason Hobbs #endif
458bc6fc28bSAlexander Graf 	int clientarch = -1;
459232c150aSwdenk 
4601fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_VENDOREX)
4613861aa5cSwdenk 	u8 *x;
4623861aa5cSwdenk #endif
4631fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_SEND_HOSTNAME)
46477ddac94SWolfgang Denk 	char *hostname;
465fe389a82Sstroese #endif
4663861aa5cSwdenk 
4673861aa5cSwdenk 	*e++ = 99;		/* RFC1048 Magic Cookie */
4683861aa5cSwdenk 	*e++ = 130;
4693861aa5cSwdenk 	*e++ = 83;
4703861aa5cSwdenk 	*e++ = 99;
4713861aa5cSwdenk 
4723861aa5cSwdenk 	*e++ = 53;		/* DHCP Message Type */
4733861aa5cSwdenk 	*e++ = 1;
4743861aa5cSwdenk 	*e++ = message_type;
4753861aa5cSwdenk 
4763861aa5cSwdenk 	*e++ = 57;		/* Maximum DHCP Message Size */
4773861aa5cSwdenk 	*e++ = 2;
478f8315731SJoe Hershberger 	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
479f8315731SJoe Hershberger 	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
4803861aa5cSwdenk 
481049a95a7SJoe Hershberger 	if (server_ip.s_addr) {
482049a95a7SJoe Hershberger 		int tmp = ntohl(server_ip.s_addr);
4833861aa5cSwdenk 
4843861aa5cSwdenk 		*e++ = 54;	/* ServerID */
4853861aa5cSwdenk 		*e++ = 4;
4863861aa5cSwdenk 		*e++ = tmp >> 24;
4873861aa5cSwdenk 		*e++ = tmp >> 16;
4883861aa5cSwdenk 		*e++ = tmp >> 8;
4893861aa5cSwdenk 		*e++ = tmp & 0xff;
4903861aa5cSwdenk 	}
4913861aa5cSwdenk 
492049a95a7SJoe Hershberger 	if (requested_ip.s_addr) {
493049a95a7SJoe Hershberger 		int tmp = ntohl(requested_ip.s_addr);
4943861aa5cSwdenk 
4953861aa5cSwdenk 		*e++ = 50;	/* Requested IP */
4963861aa5cSwdenk 		*e++ = 4;
4973861aa5cSwdenk 		*e++ = tmp >> 24;
4983861aa5cSwdenk 		*e++ = tmp >> 16;
4993861aa5cSwdenk 		*e++ = tmp >> 8;
5003861aa5cSwdenk 		*e++ = tmp & 0xff;
5013861aa5cSwdenk 	}
5021fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_SEND_HOSTNAME)
50300caae6dSSimon Glass 	hostname = env_get("hostname");
5043090b7e3SJoe Hershberger 	if (hostname) {
505fe389a82Sstroese 		int hostnamelen = strlen(hostname);
506232c150aSwdenk 
507fe389a82Sstroese 		*e++ = 12;	/* Hostname */
508fe389a82Sstroese 		*e++ = hostnamelen;
509fe389a82Sstroese 		memcpy(e, hostname, hostnamelen);
510fe389a82Sstroese 		e += hostnamelen;
511fe389a82Sstroese 	}
512fe389a82Sstroese #endif
513fe389a82Sstroese 
514bc6fc28bSAlexander Graf #ifdef CONFIG_BOOTP_PXE_CLIENTARCH
515d2b5d5c4SJason Hobbs 	clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
516bc6fc28bSAlexander Graf #endif
517bc6fc28bSAlexander Graf 
51800caae6dSSimon Glass 	if (env_get("bootp_arch"))
519bfebc8c9SSimon Glass 		clientarch = env_get_ulong("bootp_arch", 16, clientarch);
520bc6fc28bSAlexander Graf 
521bc6fc28bSAlexander Graf 	if (clientarch > 0) {
522d2b5d5c4SJason Hobbs 		*e++ = 93;	/* Client System Architecture */
523d2b5d5c4SJason Hobbs 		*e++ = 2;
524d2b5d5c4SJason Hobbs 		*e++ = (clientarch >> 8) & 0xff;
525d2b5d5c4SJason Hobbs 		*e++ = clientarch & 0xff;
526bc6fc28bSAlexander Graf 	}
527d2b5d5c4SJason Hobbs 
528d2b5d5c4SJason Hobbs 	*e++ = 94;	/* Client Network Interface Identifier */
529d2b5d5c4SJason Hobbs 	*e++ = 3;
530d2b5d5c4SJason Hobbs 	*e++ = 1;	/* type field for UNDI */
531d2b5d5c4SJason Hobbs 	*e++ = 0;	/* major revision */
532d2b5d5c4SJason Hobbs 	*e++ = 0;	/* minor revision */
533d2b5d5c4SJason Hobbs 
534bc6fc28bSAlexander Graf #ifdef CONFIG_LIB_UUID
53500caae6dSSimon Glass 	uuid = env_get("pxeuuid");
536d2b5d5c4SJason Hobbs 
537d2b5d5c4SJason Hobbs 	if (uuid) {
538d2b5d5c4SJason Hobbs 		if (uuid_str_valid(uuid)) {
539d2b5d5c4SJason Hobbs 			*e++ = 97;	/* Client Machine Identifier */
540d2b5d5c4SJason Hobbs 			*e++ = 17;
541d2b5d5c4SJason Hobbs 			*e++ = 0;	/* type 0 - UUID */
542d2b5d5c4SJason Hobbs 
543d718ded0SPrzemyslaw Marczak 			uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD);
544d2b5d5c4SJason Hobbs 			e += 16;
545d2b5d5c4SJason Hobbs 		} else {
546d2b5d5c4SJason Hobbs 			printf("Invalid pxeuuid: %s\n", uuid);
547d2b5d5c4SJason Hobbs 		}
548d2b5d5c4SJason Hobbs 	}
5499ace17c8SIlya Yanok #endif
550d2b5d5c4SJason Hobbs 
5514570a993SAlexander Graf 	e = add_vci(e);
552d2b5d5c4SJason Hobbs 
5531fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_VENDOREX)
5543090b7e3SJoe Hershberger 	x = dhcp_vendorex_prep(e);
5553090b7e3SJoe Hershberger 	if (x)
5563861aa5cSwdenk 		return x - start;
5573861aa5cSwdenk #endif
5583861aa5cSwdenk 
5593861aa5cSwdenk 	*e++ = 55;		/* Parameter Request List */
5603861aa5cSwdenk 	 cnt = e++;		/* Pointer to count of requested items */
5613861aa5cSwdenk 	*cnt = 0;
5621fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_SUBNETMASK)
5633861aa5cSwdenk 	*e++  = 1;		/* Subnet Mask */
5643861aa5cSwdenk 	*cnt += 1;
5653861aa5cSwdenk #endif
5661fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_TIMEOFFSET)
567ea287debSwdenk 	*e++  = 2;
568ea287debSwdenk 	*cnt += 1;
569ea287debSwdenk #endif
5701fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_GATEWAY)
5713861aa5cSwdenk 	*e++  = 3;		/* Router Option */
5723861aa5cSwdenk 	*cnt += 1;
5733861aa5cSwdenk #endif
5741fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_DNS)
5753861aa5cSwdenk 	*e++  = 6;		/* DNS Server(s) */
5763861aa5cSwdenk 	*cnt += 1;
5773861aa5cSwdenk #endif
5781fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_HOSTNAME)
5793861aa5cSwdenk 	*e++  = 12;		/* Hostname */
5803861aa5cSwdenk 	*cnt += 1;
5813861aa5cSwdenk #endif
5821fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_BOOTFILESIZE)
5833861aa5cSwdenk 	*e++  = 13;		/* Boot File Size */
5843861aa5cSwdenk 	*cnt += 1;
5853861aa5cSwdenk #endif
5861fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_BOOTPATH)
5873861aa5cSwdenk 	*e++  = 17;		/* Boot path */
5883861aa5cSwdenk 	*cnt += 1;
5893861aa5cSwdenk #endif
5901fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_NISDOMAIN)
5913861aa5cSwdenk 	*e++  = 40;		/* NIS Domain name request */
5923861aa5cSwdenk 	*cnt += 1;
5933861aa5cSwdenk #endif
5941fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_NTPSERVER)
595ea287debSwdenk 	*e++  = 42;
596ea287debSwdenk 	*cnt += 1;
597ea287debSwdenk #endif
598258ccd68SJason Liu 	/* no options, so back up to avoid sending an empty request list */
599258ccd68SJason Liu 	if (*cnt == 0)
600258ccd68SJason Liu 		e -= 2;
601258ccd68SJason Liu 
6023861aa5cSwdenk 	*e++  = 255;		/* End of the list */
6033861aa5cSwdenk 
6043861aa5cSwdenk 	/* Pad to minimal length */
6053861aa5cSwdenk #ifdef	CONFIG_DHCP_MIN_EXT_LEN
60621076f61SSimon Glass 	while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
6073861aa5cSwdenk 		*e++ = 0;
6083861aa5cSwdenk #endif
6093861aa5cSwdenk 
6103861aa5cSwdenk 	return e - start;
6113861aa5cSwdenk }
6123861aa5cSwdenk 
613610f2e9cSJon Loeliger #else
6143861aa5cSwdenk /*
6151fe80d79SJon Loeliger  * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
6163861aa5cSwdenk  */
bootp_extended(u8 * e)617049a95a7SJoe Hershberger static int bootp_extended(u8 *e)
6183861aa5cSwdenk {
6193861aa5cSwdenk 	u8 *start = e;
6203861aa5cSwdenk 
6213861aa5cSwdenk 	*e++ = 99;		/* RFC1048 Magic Cookie */
6223861aa5cSwdenk 	*e++ = 130;
6233861aa5cSwdenk 	*e++ = 83;
6243861aa5cSwdenk 	*e++ = 99;
6253861aa5cSwdenk 
626643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
6273861aa5cSwdenk 	*e++ = 53;		/* DHCP Message Type */
6283861aa5cSwdenk 	*e++ = 1;
6293861aa5cSwdenk 	*e++ = DHCP_DISCOVER;
6303861aa5cSwdenk 
6313861aa5cSwdenk 	*e++ = 57;		/* Maximum DHCP Message Size */
6323861aa5cSwdenk 	*e++ = 2;
633f8315731SJoe Hershberger 	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
634f8315731SJoe Hershberger 	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
635610f2e9cSJon Loeliger #endif
6363861aa5cSwdenk 
6374570a993SAlexander Graf 	add_vci(e);
6389ace17c8SIlya Yanok 
6391fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_SUBNETMASK)
6403861aa5cSwdenk 	*e++ = 1;		/* Subnet mask request */
6413861aa5cSwdenk 	*e++ = 4;
6423861aa5cSwdenk 	e   += 4;
6433861aa5cSwdenk #endif
6443861aa5cSwdenk 
6451fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_GATEWAY)
6463861aa5cSwdenk 	*e++ = 3;		/* Default gateway request */
6473861aa5cSwdenk 	*e++ = 4;
6483861aa5cSwdenk 	e   += 4;
6493861aa5cSwdenk #endif
6503861aa5cSwdenk 
6511fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_DNS)
6523861aa5cSwdenk 	*e++ = 6;		/* Domain Name Server */
6533861aa5cSwdenk 	*e++ = 4;
6543861aa5cSwdenk 	e   += 4;
6553861aa5cSwdenk #endif
6563861aa5cSwdenk 
6571fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_HOSTNAME)
6583861aa5cSwdenk 	*e++ = 12;		/* Host name request */
6593861aa5cSwdenk 	*e++ = 32;
6603861aa5cSwdenk 	e   += 32;
6613861aa5cSwdenk #endif
6623861aa5cSwdenk 
6631fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_BOOTFILESIZE)
6643861aa5cSwdenk 	*e++ = 13;		/* Boot file size */
6653861aa5cSwdenk 	*e++ = 2;
6663861aa5cSwdenk 	e   += 2;
6673861aa5cSwdenk #endif
6683861aa5cSwdenk 
6691fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_BOOTPATH)
6703861aa5cSwdenk 	*e++ = 17;		/* Boot path */
6713861aa5cSwdenk 	*e++ = 32;
6723861aa5cSwdenk 	e   += 32;
6733861aa5cSwdenk #endif
6743861aa5cSwdenk 
6751fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_NISDOMAIN)
6763861aa5cSwdenk 	*e++ = 40;		/* NIS Domain name request */
6773861aa5cSwdenk 	*e++ = 32;
6783861aa5cSwdenk 	e   += 32;
6793861aa5cSwdenk #endif
68009e3a67dSLuuk Paulussen #if defined(CONFIG_BOOTP_NTPSERVER)
68109e3a67dSLuuk Paulussen 	*e++ = 42;
68209e3a67dSLuuk Paulussen 	*e++ = 4;
68309e3a67dSLuuk Paulussen 	e   += 4;
68409e3a67dSLuuk Paulussen #endif
6853861aa5cSwdenk 
6863861aa5cSwdenk 	*e++ = 255;		/* End of the list */
6873861aa5cSwdenk 
688166c409bSAndre Renaud 	/*
689166c409bSAndre Renaud 	 * If nothing in list, remove it altogether. Some DHCP servers get
690166c409bSAndre Renaud 	 * upset by this minor faux pas and do not respond at all.
691166c409bSAndre Renaud 	 */
692166c409bSAndre Renaud 	if (e == start + 3) {
693166c409bSAndre Renaud 		printf("*** Warning: no DHCP options requested\n");
694166c409bSAndre Renaud 		e -= 3;
695166c409bSAndre Renaud 	}
696166c409bSAndre Renaud 
6973861aa5cSwdenk 	return e - start;
6983861aa5cSwdenk }
699610f2e9cSJon Loeliger #endif
7003861aa5cSwdenk 
bootp_reset(void)7017044c6bbSJoe Hershberger void bootp_reset(void)
702f59be6e8SStephen Warren {
70392ac8accSThierry Reding 	bootp_num_ids = 0;
7047044c6bbSJoe Hershberger 	bootp_try = 0;
705f59be6e8SStephen Warren 	bootp_start = get_timer(0);
70692ac8accSThierry Reding 	bootp_timeout = 250;
707f59be6e8SStephen Warren }
708f59be6e8SStephen Warren 
bootp_request(void)7097044c6bbSJoe Hershberger void bootp_request(void)
7103861aa5cSwdenk {
711db288a96SJoe Hershberger 	uchar *pkt, *iphdr;
7127044c6bbSJoe Hershberger 	struct bootp_hdr *bp;
713ae446f56SJoe Hershberger 	int extlen, pktlen, iplen;
714ae446f56SJoe Hershberger 	int eth_hdr_size;
715eafc8db0SJoe Hershberger #ifdef CONFIG_BOOTP_RANDOM_DELAY
7168e8d73b4SPavel Machek 	ulong rand_ms;
717eafc8db0SJoe Hershberger #endif
7185917e7d1SSergey Temerkhanov 	u32 bootp_id;
719049a95a7SJoe Hershberger 	struct in_addr zero_ip;
720049a95a7SJoe Hershberger 	struct in_addr bcast_ip;
72150768f5bSAlexandre Messier 	char *ep;  /* Environment pointer */
7223861aa5cSwdenk 
723573f14feSSimon Glass 	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
724643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
7253861aa5cSwdenk 	dhcp_state = INIT;
7263861aa5cSwdenk #endif
7273861aa5cSwdenk 
72800caae6dSSimon Glass 	ep = env_get("bootpretryperiod");
72950768f5bSAlexandre Messier 	if (ep != NULL)
73050768f5bSAlexandre Messier 		time_taken_max = simple_strtoul(ep, NULL, 10);
73150768f5bSAlexandre Messier 	else
73250768f5bSAlexandre Messier 		time_taken_max = TIMEOUT_MS;
73350768f5bSAlexandre Messier 
7343861aa5cSwdenk #ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
7357044c6bbSJoe Hershberger 	if (bootp_try == 0)
736eafc8db0SJoe Hershberger 		srand_mac();
7373861aa5cSwdenk 
7387044c6bbSJoe Hershberger 	if (bootp_try <= 2)	/* Start with max 1024 * 1ms */
7397044c6bbSJoe Hershberger 		rand_ms = rand() >> (22 - bootp_try);
740eafc8db0SJoe Hershberger 	else		/* After 3rd BOOTP request max 8192 * 1ms */
741eafc8db0SJoe Hershberger 		rand_ms = rand() >> 19;
7423861aa5cSwdenk 
743eafc8db0SJoe Hershberger 	printf("Random delay: %ld ms...\n", rand_ms);
7448e8d73b4SPavel Machek 	mdelay(rand_ms);
7453090b7e3SJoe Hershberger 
7463861aa5cSwdenk #endif	/* CONFIG_BOOTP_RANDOM_DELAY */
7473861aa5cSwdenk 
7487044c6bbSJoe Hershberger 	printf("BOOTP broadcast %d\n", ++bootp_try);
7491203fcceSJoe Hershberger 	pkt = net_tx_packet;
7503861aa5cSwdenk 	memset((void *)pkt, 0, PKTSIZE);
7513861aa5cSwdenk 
7521203fcceSJoe Hershberger 	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
753ae446f56SJoe Hershberger 	pkt += eth_hdr_size;
7543861aa5cSwdenk 
7553861aa5cSwdenk 	/*
7563090b7e3SJoe Hershberger 	 * Next line results in incorrect packet size being transmitted,
7573090b7e3SJoe Hershberger 	 * resulting in errors in some DHCP servers, reporting missing bytes.
7583090b7e3SJoe Hershberger 	 * Size must be set in packet header after extension length has been
7593090b7e3SJoe Hershberger 	 * determined.
7603861aa5cSwdenk 	 * C. Hallinan, DS4.COM, Inc.
7613861aa5cSwdenk 	 */
7624b11c916SJoe Hershberger 	/* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
7637044c6bbSJoe Hershberger 		sizeof (struct bootp_hdr)); */
7644b11c916SJoe Hershberger 	iphdr = pkt;	/* We need this later for net_set_udp_header() */
765594c26f8SJoe Hershberger 	pkt += IP_UDP_HDR_SIZE;
7663861aa5cSwdenk 
7677044c6bbSJoe Hershberger 	bp = (struct bootp_hdr *)pkt;
7683861aa5cSwdenk 	bp->bp_op = OP_BOOTREQUEST;
7693861aa5cSwdenk 	bp->bp_htype = HWT_ETHER;
7703861aa5cSwdenk 	bp->bp_hlen = HWL_ETHER;
7713861aa5cSwdenk 	bp->bp_hops = 0;
772454d9d3eSStefan Brüns 	/*
773454d9d3eSStefan Brüns 	 * according to RFC1542, should be 0 on first request, secs since
774454d9d3eSStefan Brüns 	 * first request otherwise
775454d9d3eSStefan Brüns 	 */
776454d9d3eSStefan Brüns 	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
777049a95a7SJoe Hershberger 	zero_ip.s_addr = 0;
778049a95a7SJoe Hershberger 	net_write_ip(&bp->bp_ciaddr, zero_ip);
779049a95a7SJoe Hershberger 	net_write_ip(&bp->bp_yiaddr, zero_ip);
780049a95a7SJoe Hershberger 	net_write_ip(&bp->bp_siaddr, zero_ip);
781049a95a7SJoe Hershberger 	net_write_ip(&bp->bp_giaddr, zero_ip);
7820adb5b76SJoe Hershberger 	memcpy(bp->bp_chaddr, net_ethaddr, 6);
7831411157dSJoe Hershberger 	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
7843861aa5cSwdenk 
7853861aa5cSwdenk 	/* Request additional information from the BOOTP/DHCP server */
786643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
787049a95a7SJoe Hershberger 	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_DISCOVER, zero_ip,
788049a95a7SJoe Hershberger 			       zero_ip);
7893861aa5cSwdenk #else
790049a95a7SJoe Hershberger 	extlen = bootp_extended((u8 *)bp->bp_vend);
791610f2e9cSJon Loeliger #endif
7923861aa5cSwdenk 
7933861aa5cSwdenk 	/*
7943861aa5cSwdenk 	 *	Bootp ID is the lower 4 bytes of our ethernet address
79549f3bdbbSBartlomiej Sieka 	 *	plus the current time in ms.
7963861aa5cSwdenk 	 */
7975917e7d1SSergey Temerkhanov 	bootp_id = ((u32)net_ethaddr[2] << 24)
7985917e7d1SSergey Temerkhanov 		| ((u32)net_ethaddr[3] << 16)
7995917e7d1SSergey Temerkhanov 		| ((u32)net_ethaddr[4] << 8)
8005917e7d1SSergey Temerkhanov 		| (u32)net_ethaddr[5];
8017044c6bbSJoe Hershberger 	bootp_id += get_timer(0);
8027044c6bbSJoe Hershberger 	bootp_id = htonl(bootp_id);
8037044c6bbSJoe Hershberger 	bootp_add_id(bootp_id);
8045917e7d1SSergey Temerkhanov 	net_copy_u32(&bp->bp_id, &bootp_id);
8053861aa5cSwdenk 
8063861aa5cSwdenk 	/*
8073861aa5cSwdenk 	 * Calculate proper packet lengths taking into account the
8083861aa5cSwdenk 	 * variable size of the options field
8093861aa5cSwdenk 	 */
810ae446f56SJoe Hershberger 	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
811ae446f56SJoe Hershberger 	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
812049a95a7SJoe Hershberger 	bcast_ip.s_addr = 0xFFFFFFFFL;
813049a95a7SJoe Hershberger 	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
814bc0571fcSJoe Hershberger 	net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
8153861aa5cSwdenk 
816643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
8173861aa5cSwdenk 	dhcp_state = SELECTING;
818049a95a7SJoe Hershberger 	net_set_udp_handler(dhcp_handler);
8193861aa5cSwdenk #else
820049a95a7SJoe Hershberger 	net_set_udp_handler(bootp_handler);
821610f2e9cSJon Loeliger #endif
8221203fcceSJoe Hershberger 	net_send_packet(net_tx_packet, pktlen);
8233861aa5cSwdenk }
8243861aa5cSwdenk 
825643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
dhcp_process_options(uchar * popt,uchar * end)826774c3e05SStefan Brüns static void dhcp_process_options(uchar *popt, uchar *end)
8273861aa5cSwdenk {
8283861aa5cSwdenk 	int oplen, size;
829d8d8724bSWolfgang Denk #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
830d8d8724bSWolfgang Denk 	int *to_ptr;
831d8d8724bSWolfgang Denk #endif
8323861aa5cSwdenk 
8333861aa5cSwdenk 	while (popt < end && *popt != 0xff) {
8343861aa5cSwdenk 		oplen = *(popt + 1);
8353861aa5cSwdenk 		switch (*popt) {
836c56eb573SStefan Brüns 		case 0:
837c56eb573SStefan Brüns 			oplen = -1; /* Pad omits len byte */
838c56eb573SStefan Brüns 			break;
8393861aa5cSwdenk 		case 1:
840049a95a7SJoe Hershberger 			net_copy_ip(&net_netmask, (popt + 2));
8413861aa5cSwdenk 			break;
8421fe80d79SJon Loeliger #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
843ea287debSwdenk 		case 2:		/* Time offset	*/
844bc0571fcSJoe Hershberger 			to_ptr = &net_ntp_time_offset;
8455917e7d1SSergey Temerkhanov 			net_copy_u32((u32 *)to_ptr, (u32 *)(popt + 2));
846bc0571fcSJoe Hershberger 			net_ntp_time_offset = ntohl(net_ntp_time_offset);
847ea287debSwdenk 			break;
848ea287debSwdenk #endif
8493861aa5cSwdenk 		case 3:
850049a95a7SJoe Hershberger 			net_copy_ip(&net_gateway, (popt + 2));
8513861aa5cSwdenk 			break;
8523861aa5cSwdenk 		case 6:
853049a95a7SJoe Hershberger 			net_copy_ip(&net_dns_server, (popt + 2));
8541fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_DNS2)
8553090b7e3SJoe Hershberger 			if (*(popt + 1) > 4)
856049a95a7SJoe Hershberger 				net_copy_ip(&net_dns_server2, (popt + 2 + 4));
857fe389a82Sstroese #endif
8583861aa5cSwdenk 			break;
8593861aa5cSwdenk 		case 12:
8603090b7e3SJoe Hershberger 			size = truncate_sz("Host Name",
861586cbe51SJoe Hershberger 				sizeof(net_hostname), oplen);
862586cbe51SJoe Hershberger 			memcpy(&net_hostname, popt + 2, size);
863586cbe51SJoe Hershberger 			net_hostname[size] = 0;
8643861aa5cSwdenk 			break;
8653861aa5cSwdenk 		case 15:	/* Ignore Domain Name Option */
8663861aa5cSwdenk 			break;
8673861aa5cSwdenk 		case 17:
8683090b7e3SJoe Hershberger 			size = truncate_sz("Root Path",
869586cbe51SJoe Hershberger 				sizeof(net_root_path), oplen);
870586cbe51SJoe Hershberger 			memcpy(&net_root_path, popt + 2, size);
871586cbe51SJoe Hershberger 			net_root_path[size] = 0;
8723861aa5cSwdenk 			break;
873ee0f60dfSBrian Rzycki 		case 28:	/* Ignore Broadcast Address Option */
874ee0f60dfSBrian Rzycki 			break;
8751fe80d79SJon Loeliger #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
876ea287debSwdenk 		case 42:	/* NTP server IP */
877049a95a7SJoe Hershberger 			net_copy_ip(&net_ntp_server, (popt + 2));
878ea287debSwdenk 			break;
879ea287debSwdenk #endif
8803861aa5cSwdenk 		case 51:
8815917e7d1SSergey Temerkhanov 			net_copy_u32(&dhcp_leasetime, (u32 *)(popt + 2));
8823861aa5cSwdenk 			break;
883ec87b1b3SStefan Brüns 		case 52:
884ec87b1b3SStefan Brüns 			dhcp_option_overload = popt[2];
885ec87b1b3SStefan Brüns 			break;
8863861aa5cSwdenk 		case 53:	/* Ignore Message Type Option */
8873861aa5cSwdenk 			break;
8883861aa5cSwdenk 		case 54:
889049a95a7SJoe Hershberger 			net_copy_ip(&dhcp_server_ip, (popt + 2));
8903861aa5cSwdenk 			break;
8913861aa5cSwdenk 		case 58:	/* Ignore Renewal Time Option */
8923861aa5cSwdenk 			break;
8933861aa5cSwdenk 		case 59:	/* Ignore Rebinding Time Option */
8943861aa5cSwdenk 			break;
8953b2e4fd9SWolfgang Denk 		case 66:	/* Ignore TFTP server name */
8963b2e4fd9SWolfgang Denk 			break;
897ec87b1b3SStefan Brüns 		case 67:	/* Bootfile option */
898449312c1SAlexander Graf 			if (!net_boot_file_name_explicit) {
899ec87b1b3SStefan Brüns 				size = truncate_sz("Bootfile",
900449312c1SAlexander Graf 						   sizeof(net_boot_file_name),
901449312c1SAlexander Graf 						   oplen);
902ec87b1b3SStefan Brüns 				memcpy(&net_boot_file_name, popt + 2, size);
903ec87b1b3SStefan Brüns 				net_boot_file_name[size] = 0;
904449312c1SAlexander Graf 			}
9053b2e4fd9SWolfgang Denk 			break;
9063861aa5cSwdenk 		default:
9071fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_VENDOREX)
9083861aa5cSwdenk 			if (dhcp_vendorex_proc(popt))
9093861aa5cSwdenk 				break;
9103861aa5cSwdenk #endif
9113090b7e3SJoe Hershberger 			printf("*** Unhandled DHCP Option in OFFER/ACK:"
9123090b7e3SJoe Hershberger 			       " %d\n", *popt);
9133861aa5cSwdenk 			break;
9143861aa5cSwdenk 		}
9153861aa5cSwdenk 		popt += oplen + 2;	/* Process next option */
9163861aa5cSwdenk 	}
9173861aa5cSwdenk }
9183861aa5cSwdenk 
dhcp_packet_process_options(struct bootp_hdr * bp)919774c3e05SStefan Brüns static void dhcp_packet_process_options(struct bootp_hdr *bp)
920774c3e05SStefan Brüns {
921774c3e05SStefan Brüns 	uchar *popt = (uchar *)&bp->bp_vend[4];
922774c3e05SStefan Brüns 	uchar *end = popt + BOOTP_HDR_SIZE;
923774c3e05SStefan Brüns 
924774c3e05SStefan Brüns 	if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
925774c3e05SStefan Brüns 		return;
926774c3e05SStefan Brüns 
927774c3e05SStefan Brüns 	dhcp_option_overload = 0;
928774c3e05SStefan Brüns 
929774c3e05SStefan Brüns 	/*
930774c3e05SStefan Brüns 	 * The 'options' field MUST be interpreted first, 'file' next,
931774c3e05SStefan Brüns 	 * 'sname' last.
932774c3e05SStefan Brüns 	 */
933774c3e05SStefan Brüns 	dhcp_process_options(popt, end);
934774c3e05SStefan Brüns 
935774c3e05SStefan Brüns 	if (dhcp_option_overload & OVERLOAD_FILE) {
936774c3e05SStefan Brüns 		popt = (uchar *)bp->bp_file;
937774c3e05SStefan Brüns 		end = popt + sizeof(bp->bp_file);
938774c3e05SStefan Brüns 		dhcp_process_options(popt, end);
939774c3e05SStefan Brüns 	}
940774c3e05SStefan Brüns 
941774c3e05SStefan Brüns 	if (dhcp_option_overload & OVERLOAD_SNAME) {
942774c3e05SStefan Brüns 		popt = (uchar *)bp->bp_sname;
943774c3e05SStefan Brüns 		end = popt + sizeof(bp->bp_sname);
944774c3e05SStefan Brüns 		dhcp_process_options(popt, end);
945774c3e05SStefan Brüns 	}
946774c3e05SStefan Brüns }
947774c3e05SStefan Brüns 
dhcp_message_type(unsigned char * popt)9487044c6bbSJoe Hershberger static int dhcp_message_type(unsigned char *popt)
9493861aa5cSwdenk {
9505917e7d1SSergey Temerkhanov 	if (net_read_u32((u32 *)popt) != htonl(BOOTP_VENDOR_MAGIC))
9513861aa5cSwdenk 		return -1;
9523861aa5cSwdenk 
9533861aa5cSwdenk 	popt += 4;
9543861aa5cSwdenk 	while (*popt != 0xff) {
9553861aa5cSwdenk 		if (*popt == 53)	/* DHCP Message Type */
9563861aa5cSwdenk 			return *(popt + 2);
957c56eb573SStefan Brüns 		if (*popt == 0)	{
958c56eb573SStefan Brüns 			/* Pad */
959c56eb573SStefan Brüns 			popt += 1;
960c56eb573SStefan Brüns 		} else {
961c56eb573SStefan Brüns 			/* Scan through all options */
962c56eb573SStefan Brüns 			popt += *(popt + 1) + 2;
963c56eb573SStefan Brüns 		}
9643861aa5cSwdenk 	}
9653861aa5cSwdenk 	return -1;
9663861aa5cSwdenk }
9673861aa5cSwdenk 
dhcp_send_request_packet(struct bootp_hdr * bp_offer)9687044c6bbSJoe Hershberger static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
9693861aa5cSwdenk {
970db288a96SJoe Hershberger 	uchar *pkt, *iphdr;
9717044c6bbSJoe Hershberger 	struct bootp_hdr *bp;
9723861aa5cSwdenk 	int pktlen, iplen, extlen;
973ae446f56SJoe Hershberger 	int eth_hdr_size;
974049a95a7SJoe Hershberger 	struct in_addr offered_ip;
975049a95a7SJoe Hershberger 	struct in_addr zero_ip;
976049a95a7SJoe Hershberger 	struct in_addr bcast_ip;
9773861aa5cSwdenk 
9787044c6bbSJoe Hershberger 	debug("dhcp_send_request_packet: Sending DHCPREQUEST\n");
9791203fcceSJoe Hershberger 	pkt = net_tx_packet;
9803861aa5cSwdenk 	memset((void *)pkt, 0, PKTSIZE);
9813861aa5cSwdenk 
9821203fcceSJoe Hershberger 	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
983ae446f56SJoe Hershberger 	pkt += eth_hdr_size;
9843861aa5cSwdenk 
9853861aa5cSwdenk 	iphdr = pkt;	/* We'll need this later to set proper pkt size */
986594c26f8SJoe Hershberger 	pkt += IP_UDP_HDR_SIZE;
9873861aa5cSwdenk 
9887044c6bbSJoe Hershberger 	bp = (struct bootp_hdr *)pkt;
9893861aa5cSwdenk 	bp->bp_op = OP_BOOTREQUEST;
9903861aa5cSwdenk 	bp->bp_htype = HWT_ETHER;
9913861aa5cSwdenk 	bp->bp_hlen = HWL_ETHER;
9923861aa5cSwdenk 	bp->bp_hops = 0;
993454d9d3eSStefan Brüns 	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
9943090b7e3SJoe Hershberger 	/* Do not set the client IP, your IP, or server IP yet, since it
9953090b7e3SJoe Hershberger 	 * hasn't been ACK'ed by the server yet */
996e5c794e4SJustin Flammia 
997d82718feSWolfgang Denk 	/*
998d82718feSWolfgang Denk 	 * RFC3046 requires Relay Agents to discard packets with
999d82718feSWolfgang Denk 	 * nonzero and offered giaddr
1000d82718feSWolfgang Denk 	 */
1001049a95a7SJoe Hershberger 	zero_ip.s_addr = 0;
1002049a95a7SJoe Hershberger 	net_write_ip(&bp->bp_giaddr, zero_ip);
1003d82718feSWolfgang Denk 
10040adb5b76SJoe Hershberger 	memcpy(bp->bp_chaddr, net_ethaddr, 6);
1005b2b7fbc3SAlexandre Messier 	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
10063861aa5cSwdenk 
10073861aa5cSwdenk 	/*
10083861aa5cSwdenk 	 * ID is the id of the OFFER packet
10093861aa5cSwdenk 	 */
10103861aa5cSwdenk 
10115917e7d1SSergey Temerkhanov 	net_copy_u32(&bp->bp_id, &bp_offer->bp_id);
10123861aa5cSwdenk 
10133861aa5cSwdenk 	/*
10143861aa5cSwdenk 	 * Copy options from OFFER packet if present
10153861aa5cSwdenk 	 */
1016e5c794e4SJustin Flammia 
1017e5c794e4SJustin Flammia 	/* Copy offered IP into the parameters request list */
1018049a95a7SJoe Hershberger 	net_copy_ip(&offered_ip, &bp_offer->bp_yiaddr);
1019049a95a7SJoe Hershberger 	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_REQUEST,
1020049a95a7SJoe Hershberger 		dhcp_server_ip, offered_ip);
10213861aa5cSwdenk 
1022ae446f56SJoe Hershberger 	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
1023ae446f56SJoe Hershberger 	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
1024049a95a7SJoe Hershberger 	bcast_ip.s_addr = 0xFFFFFFFFL;
1025049a95a7SJoe Hershberger 	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
10263861aa5cSwdenk 
1027d9a2f416SAras Vaichas #ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
1028d9a2f416SAras Vaichas 	udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
1029d9a2f416SAras Vaichas #endif	/* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
1030f9623229SJoe Hershberger 	debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
10311203fcceSJoe Hershberger 	net_send_packet(net_tx_packet, pktlen);
10323861aa5cSwdenk }
10333861aa5cSwdenk 
10343861aa5cSwdenk /*
10353861aa5cSwdenk  *	Handle DHCP received packets.
10363861aa5cSwdenk  */
dhcp_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)1037049a95a7SJoe Hershberger static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
1038049a95a7SJoe Hershberger 			 unsigned src, unsigned len)
10393861aa5cSwdenk {
10407044c6bbSJoe Hershberger 	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
10413861aa5cSwdenk 
10423861aa5cSwdenk 	debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
10433861aa5cSwdenk 	      src, dest, len, dhcp_state);
10443861aa5cSwdenk 
10453090b7e3SJoe Hershberger 	/* Filter out pkts we don't want */
1046867d6ae2SStefan Brüns 	if (check_reply_packet(pkt, dest, src, len))
10473861aa5cSwdenk 		return;
10483861aa5cSwdenk 
10493090b7e3SJoe Hershberger 	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
10503090b7e3SJoe Hershberger 	      "%d\n", src, dest, len, dhcp_state);
10513861aa5cSwdenk 
105244c42dd4SPeng Fan 	if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
105344c42dd4SPeng Fan 		return;
105444c42dd4SPeng Fan 
10553861aa5cSwdenk 	switch (dhcp_state) {
10563861aa5cSwdenk 	case SELECTING:
10573861aa5cSwdenk 		/*
10583861aa5cSwdenk 		 * Wait an appropriate time for any potential DHCPOFFER packets
10593090b7e3SJoe Hershberger 		 * to arrive.  Then select one, and generate DHCPREQUEST
10603090b7e3SJoe Hershberger 		 * response.  If filename is in format we recognize, assume it
10613090b7e3SJoe Hershberger 		 * is a valid OFFER from a server we want.
10623861aa5cSwdenk 		 */
10633861aa5cSwdenk 		debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
10646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_BOOTFILE_PREFIX
10653861aa5cSwdenk 		if (strncmp(bp->bp_file,
10666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			    CONFIG_SYS_BOOTFILE_PREFIX,
10676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
10686d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
1069774c3e05SStefan Brüns 			dhcp_packet_process_options(bp);
10700efe1bcfSAlexander Graf 			efi_net_set_dhcp_ack(pkt, len);
10713861aa5cSwdenk 
10723861aa5cSwdenk 			debug("TRANSITIONING TO REQUESTING STATE\n");
10733861aa5cSwdenk 			dhcp_state = REQUESTING;
1074759a51b4Sstroese 
1075bc0571fcSJoe Hershberger 			net_set_timeout_handler(5000, bootp_timeout_handler);
10767044c6bbSJoe Hershberger 			dhcp_send_request_packet(bp);
10776d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_BOOTFILE_PREFIX
10783861aa5cSwdenk 		}
10796d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
10803861aa5cSwdenk 
10813861aa5cSwdenk 		return;
10823861aa5cSwdenk 		break;
10833861aa5cSwdenk 	case REQUESTING:
10843861aa5cSwdenk 		debug("DHCP State: REQUESTING\n");
10853861aa5cSwdenk 
10867044c6bbSJoe Hershberger 		if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
1087774c3e05SStefan Brüns 			dhcp_packet_process_options(bp);
10883090b7e3SJoe Hershberger 			/* Store net params from reply */
10897044c6bbSJoe Hershberger 			store_net_params(bp);
10903861aa5cSwdenk 			dhcp_state = BOUND;
109192ac8accSThierry Reding 			printf("DHCP client bound to address %pI4 (%lu ms)\n",
1092049a95a7SJoe Hershberger 			       &net_ip, get_timer(bootp_start));
10934f28c9b1SStefan Brüns 			net_set_timeout_handler(0, (thand_f *)0);
1094573f14feSSimon Glass 			bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
1095573f14feSSimon Glass 					    "bootp_stop");
10963861aa5cSwdenk 
1097e4a3d57dSSimon Glass 			net_auto_load();
10983861aa5cSwdenk 			return;
10993861aa5cSwdenk 		}
11003861aa5cSwdenk 		break;
110151dfe138SRemy Bohmer 	case BOUND:
110251dfe138SRemy Bohmer 		/* DHCP client bound to address */
110351dfe138SRemy Bohmer 		break;
11043861aa5cSwdenk 	default:
11054b9206edSwdenk 		puts("DHCP: INVALID STATE\n");
11063861aa5cSwdenk 		break;
11073861aa5cSwdenk 	}
11083861aa5cSwdenk }
11093861aa5cSwdenk 
dhcp_request(void)11107044c6bbSJoe Hershberger void dhcp_request(void)
11113861aa5cSwdenk {
11127044c6bbSJoe Hershberger 	bootp_request();
11133861aa5cSwdenk }
1114992742a5SWolfgang Denk #endif	/* CONFIG_CMD_DHCP */
1115