xref: /OK3568_Linux_fs/u-boot/net/bootp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *	Based on LiMon - BOOTP.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *	Copyright 1994, 1995, 2000 Neil Russell.
5*4882a593Smuzhiyun  *	(See License)
6*4882a593Smuzhiyun  *	Copyright 2000 Roland Borde
7*4882a593Smuzhiyun  *	Copyright 2000 Paolo Scaffardi
8*4882a593Smuzhiyun  *	Copyright 2000-2004 Wolfgang Denk, wd@denx.de
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <command.h>
13*4882a593Smuzhiyun #include <efi_loader.h>
14*4882a593Smuzhiyun #include <net.h>
15*4882a593Smuzhiyun #include <net/tftp.h>
16*4882a593Smuzhiyun #include "bootp.h"
17*4882a593Smuzhiyun #include "nfs.h"
18*4882a593Smuzhiyun #ifdef CONFIG_LED_STATUS
19*4882a593Smuzhiyun #include <status_led.h>
20*4882a593Smuzhiyun #endif
21*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_RANDOM_DELAY
22*4882a593Smuzhiyun #include "net_rand.h"
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * The timeout for the initial BOOTP/DHCP request used to be described by a
29*4882a593Smuzhiyun  * counter of fixed-length timeout periods. TIMEOUT_COUNT represents
30*4882a593Smuzhiyun  * that counter
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * Now that the timeout periods are variable (exponential backoff and retry)
33*4882a593Smuzhiyun  * we convert the timeout count to the absolute time it would have take to
34*4882a593Smuzhiyun  * execute that many retries, and keep sending retry packets until that time
35*4882a593Smuzhiyun  * is reached.
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun #ifndef CONFIG_NET_RETRY_COUNT
38*4882a593Smuzhiyun # define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
39*4882a593Smuzhiyun #else
40*4882a593Smuzhiyun # define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
41*4882a593Smuzhiyun #endif
42*4882a593Smuzhiyun #define TIMEOUT_MS	((3 + (TIMEOUT_COUNT * 5)) * 1000)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define PORT_BOOTPS	67		/* BOOTP server UDP port */
45*4882a593Smuzhiyun #define PORT_BOOTPC	68		/* BOOTP client UDP port */
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list */
48*4882a593Smuzhiyun #define CONFIG_DHCP_MIN_EXT_LEN 64
49*4882a593Smuzhiyun #endif
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #ifndef CONFIG_BOOTP_ID_CACHE_SIZE
52*4882a593Smuzhiyun #define CONFIG_BOOTP_ID_CACHE_SIZE 4
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun u32		bootp_ids[CONFIG_BOOTP_ID_CACHE_SIZE];
56*4882a593Smuzhiyun unsigned int	bootp_num_ids;
57*4882a593Smuzhiyun int		bootp_try;
58*4882a593Smuzhiyun ulong		bootp_start;
59*4882a593Smuzhiyun ulong		bootp_timeout;
60*4882a593Smuzhiyun char net_nis_domain[32] = {0,}; /* Our NIS domain */
61*4882a593Smuzhiyun char net_hostname[32] = {0,}; /* Our hostname */
62*4882a593Smuzhiyun char net_root_path[64] = {0,}; /* Our bootpath */
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static ulong time_taken_max;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
67*4882a593Smuzhiyun static dhcp_state_t dhcp_state = INIT;
68*4882a593Smuzhiyun static u32 dhcp_leasetime;
69*4882a593Smuzhiyun static struct in_addr dhcp_server_ip;
70*4882a593Smuzhiyun static u8 dhcp_option_overload;
71*4882a593Smuzhiyun #define OVERLOAD_FILE 1
72*4882a593Smuzhiyun #define OVERLOAD_SNAME 2
73*4882a593Smuzhiyun static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
74*4882a593Smuzhiyun 			unsigned src, unsigned len);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* For Debug */
77*4882a593Smuzhiyun #if 0
78*4882a593Smuzhiyun static char *dhcpmsg2str(int type)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	switch (type) {
81*4882a593Smuzhiyun 	case 1:	 return "DHCPDISCOVER"; break;
82*4882a593Smuzhiyun 	case 2:	 return "DHCPOFFER";	break;
83*4882a593Smuzhiyun 	case 3:	 return "DHCPREQUEST";	break;
84*4882a593Smuzhiyun 	case 4:	 return "DHCPDECLINE";	break;
85*4882a593Smuzhiyun 	case 5:	 return "DHCPACK";	break;
86*4882a593Smuzhiyun 	case 6:	 return "DHCPNACK";	break;
87*4882a593Smuzhiyun 	case 7:	 return "DHCPRELEASE";	break;
88*4882a593Smuzhiyun 	default: return "UNKNOWN/INVALID MSG TYPE"; break;
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun #endif
93*4882a593Smuzhiyun 
bootp_add_id(ulong id)94*4882a593Smuzhiyun static void bootp_add_id(ulong id)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	if (bootp_num_ids >= ARRAY_SIZE(bootp_ids)) {
97*4882a593Smuzhiyun 		size_t size = sizeof(bootp_ids) - sizeof(id);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		memmove(bootp_ids, &bootp_ids[1], size);
100*4882a593Smuzhiyun 		bootp_ids[bootp_num_ids - 1] = id;
101*4882a593Smuzhiyun 	} else {
102*4882a593Smuzhiyun 		bootp_ids[bootp_num_ids] = id;
103*4882a593Smuzhiyun 		bootp_num_ids++;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
bootp_match_id(ulong id)107*4882a593Smuzhiyun static bool bootp_match_id(ulong id)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	unsigned int i;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	for (i = 0; i < bootp_num_ids; i++)
112*4882a593Smuzhiyun 		if (bootp_ids[i] == id)
113*4882a593Smuzhiyun 			return true;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return false;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
check_reply_packet(uchar * pkt,unsigned dest,unsigned src,unsigned len)118*4882a593Smuzhiyun static int check_reply_packet(uchar *pkt, unsigned dest, unsigned src,
119*4882a593Smuzhiyun 			      unsigned len)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
122*4882a593Smuzhiyun 	int retval = 0;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
125*4882a593Smuzhiyun 		retval = -1;
126*4882a593Smuzhiyun 	else if (len < sizeof(struct bootp_hdr) - OPT_FIELD_SIZE)
127*4882a593Smuzhiyun 		retval = -2;
128*4882a593Smuzhiyun 	else if (bp->bp_op != OP_BOOTREPLY)
129*4882a593Smuzhiyun 		retval = -3;
130*4882a593Smuzhiyun 	else if (bp->bp_htype != HWT_ETHER)
131*4882a593Smuzhiyun 		retval = -4;
132*4882a593Smuzhiyun 	else if (bp->bp_hlen != HWL_ETHER)
133*4882a593Smuzhiyun 		retval = -5;
134*4882a593Smuzhiyun 	else if (!bootp_match_id(net_read_u32(&bp->bp_id)))
135*4882a593Smuzhiyun 		retval = -6;
136*4882a593Smuzhiyun 	else if (memcmp(bp->bp_chaddr, net_ethaddr, HWL_ETHER) != 0)
137*4882a593Smuzhiyun 		retval = -7;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	debug("Filtering pkt = %d\n", retval);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return retval;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun  * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
146*4882a593Smuzhiyun  */
store_net_params(struct bootp_hdr * bp)147*4882a593Smuzhiyun static void store_net_params(struct bootp_hdr *bp)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun #if !defined(CONFIG_BOOTP_SERVERIP)
150*4882a593Smuzhiyun 	struct in_addr tmp_ip;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	net_copy_ip(&tmp_ip, &bp->bp_siaddr);
153*4882a593Smuzhiyun 	if (tmp_ip.s_addr != 0)
154*4882a593Smuzhiyun 		net_copy_ip(&net_server_ip, &bp->bp_siaddr);
155*4882a593Smuzhiyun 	memcpy(net_server_ethaddr,
156*4882a593Smuzhiyun 	       ((struct ethernet_hdr *)net_rx_packet)->et_src, 6);
157*4882a593Smuzhiyun 	if (
158*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
159*4882a593Smuzhiyun 	    !(dhcp_option_overload & OVERLOAD_FILE) &&
160*4882a593Smuzhiyun #endif
161*4882a593Smuzhiyun 	    (strlen(bp->bp_file) > 0)) {
162*4882a593Smuzhiyun 		copy_filename(net_boot_file_name, bp->bp_file,
163*4882a593Smuzhiyun 			      sizeof(net_boot_file_name));
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	debug("net_boot_file_name: %s\n", net_boot_file_name);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	/* Propagate to environment:
169*4882a593Smuzhiyun 	 * don't delete exising entry when BOOTP / DHCP reply does
170*4882a593Smuzhiyun 	 * not contain a new value
171*4882a593Smuzhiyun 	 */
172*4882a593Smuzhiyun 	if (*net_boot_file_name)
173*4882a593Smuzhiyun 		env_set("bootfile", net_boot_file_name);
174*4882a593Smuzhiyun #endif
175*4882a593Smuzhiyun 	net_copy_ip(&net_ip, &bp->bp_yiaddr);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
truncate_sz(const char * name,int maxlen,int curlen)178*4882a593Smuzhiyun static int truncate_sz(const char *name, int maxlen, int curlen)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	if (curlen >= maxlen) {
181*4882a593Smuzhiyun 		printf("*** WARNING: %s is too long (%d - max: %d)"
182*4882a593Smuzhiyun 			" - truncated\n", name, curlen, maxlen);
183*4882a593Smuzhiyun 		curlen = maxlen - 1;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 	return curlen;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun #if !defined(CONFIG_CMD_DHCP)
189*4882a593Smuzhiyun 
bootp_process_vendor_field(u8 * ext)190*4882a593Smuzhiyun static void bootp_process_vendor_field(u8 *ext)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	int size = *(ext + 1);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
195*4882a593Smuzhiyun 	      *(ext + 1));
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	net_boot_file_expected_size_in_blocks = 0;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	switch (*ext) {
200*4882a593Smuzhiyun 		/* Fixed length fields */
201*4882a593Smuzhiyun 	case 1:			/* Subnet mask */
202*4882a593Smuzhiyun 		if (net_netmask.s_addr == 0)
203*4882a593Smuzhiyun 			net_copy_ip(&net_netmask, (struct in_addr *)(ext + 2));
204*4882a593Smuzhiyun 		break;
205*4882a593Smuzhiyun 	case 2:			/* Time offset - Not yet supported */
206*4882a593Smuzhiyun 		break;
207*4882a593Smuzhiyun 		/* Variable length fields */
208*4882a593Smuzhiyun 	case 3:			/* Gateways list */
209*4882a593Smuzhiyun 		if (net_gateway.s_addr == 0)
210*4882a593Smuzhiyun 			net_copy_ip(&net_gateway, (struct in_addr *)(ext + 2));
211*4882a593Smuzhiyun 		break;
212*4882a593Smuzhiyun 	case 4:			/* Time server - Not yet supported */
213*4882a593Smuzhiyun 		break;
214*4882a593Smuzhiyun 	case 5:			/* IEN-116 name server - Not yet supported */
215*4882a593Smuzhiyun 		break;
216*4882a593Smuzhiyun 	case 6:
217*4882a593Smuzhiyun 		if (net_dns_server.s_addr == 0)
218*4882a593Smuzhiyun 			net_copy_ip(&net_dns_server,
219*4882a593Smuzhiyun 				    (struct in_addr *)(ext + 2));
220*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_DNS2)
221*4882a593Smuzhiyun 		if ((net_dns_server2.s_addr == 0) && (size > 4))
222*4882a593Smuzhiyun 			net_copy_ip(&net_dns_server2,
223*4882a593Smuzhiyun 				    (struct in_addr *)(ext + 2 + 4));
224*4882a593Smuzhiyun #endif
225*4882a593Smuzhiyun 		break;
226*4882a593Smuzhiyun 	case 7:			/* Log server - Not yet supported */
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 	case 8:			/* Cookie/Quote server - Not yet supported */
229*4882a593Smuzhiyun 		break;
230*4882a593Smuzhiyun 	case 9:			/* LPR server - Not yet supported */
231*4882a593Smuzhiyun 		break;
232*4882a593Smuzhiyun 	case 10:		/* Impress server - Not yet supported */
233*4882a593Smuzhiyun 		break;
234*4882a593Smuzhiyun 	case 11:		/* RPL server - Not yet supported */
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 	case 12:		/* Host name */
237*4882a593Smuzhiyun 		if (net_hostname[0] == 0) {
238*4882a593Smuzhiyun 			size = truncate_sz("Host Name",
239*4882a593Smuzhiyun 				sizeof(net_hostname), size);
240*4882a593Smuzhiyun 			memcpy(&net_hostname, ext + 2, size);
241*4882a593Smuzhiyun 			net_hostname[size] = 0;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 		break;
244*4882a593Smuzhiyun 	case 13:		/* Boot file size */
245*4882a593Smuzhiyun 		if (size == 2)
246*4882a593Smuzhiyun 			net_boot_file_expected_size_in_blocks =
247*4882a593Smuzhiyun 				ntohs(*(ushort *)(ext + 2));
248*4882a593Smuzhiyun 		else if (size == 4)
249*4882a593Smuzhiyun 			net_boot_file_expected_size_in_blocks =
250*4882a593Smuzhiyun 				ntohl(*(ulong *)(ext + 2));
251*4882a593Smuzhiyun 		break;
252*4882a593Smuzhiyun 	case 14:		/* Merit dump file - Not yet supported */
253*4882a593Smuzhiyun 		break;
254*4882a593Smuzhiyun 	case 15:		/* Domain name - Not yet supported */
255*4882a593Smuzhiyun 		break;
256*4882a593Smuzhiyun 	case 16:		/* Swap server - Not yet supported */
257*4882a593Smuzhiyun 		break;
258*4882a593Smuzhiyun 	case 17:		/* Root path */
259*4882a593Smuzhiyun 		if (net_root_path[0] == 0) {
260*4882a593Smuzhiyun 			size = truncate_sz("Root Path",
261*4882a593Smuzhiyun 				sizeof(net_root_path), size);
262*4882a593Smuzhiyun 			memcpy(&net_root_path, ext + 2, size);
263*4882a593Smuzhiyun 			net_root_path[size] = 0;
264*4882a593Smuzhiyun 		}
265*4882a593Smuzhiyun 		break;
266*4882a593Smuzhiyun 	case 18:		/* Extension path - Not yet supported */
267*4882a593Smuzhiyun 		/*
268*4882a593Smuzhiyun 		 * This can be used to send the information of the
269*4882a593Smuzhiyun 		 * vendor area in another file that the client can
270*4882a593Smuzhiyun 		 * access via TFTP.
271*4882a593Smuzhiyun 		 */
272*4882a593Smuzhiyun 		break;
273*4882a593Smuzhiyun 		/* IP host layer fields */
274*4882a593Smuzhiyun 	case 40:		/* NIS Domain name */
275*4882a593Smuzhiyun 		if (net_nis_domain[0] == 0) {
276*4882a593Smuzhiyun 			size = truncate_sz("NIS Domain Name",
277*4882a593Smuzhiyun 				sizeof(net_nis_domain), size);
278*4882a593Smuzhiyun 			memcpy(&net_nis_domain, ext + 2, size);
279*4882a593Smuzhiyun 			net_nis_domain[size] = 0;
280*4882a593Smuzhiyun 		}
281*4882a593Smuzhiyun 		break;
282*4882a593Smuzhiyun #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
283*4882a593Smuzhiyun 	case 42:	/* NTP server IP */
284*4882a593Smuzhiyun 		net_copy_ip(&net_ntp_server, (struct in_addr *)(ext + 2));
285*4882a593Smuzhiyun 		break;
286*4882a593Smuzhiyun #endif
287*4882a593Smuzhiyun 		/* Application layer fields */
288*4882a593Smuzhiyun 	case 43:		/* Vendor specific info - Not yet supported */
289*4882a593Smuzhiyun 		/*
290*4882a593Smuzhiyun 		 * Binary information to exchange specific
291*4882a593Smuzhiyun 		 * product information.
292*4882a593Smuzhiyun 		 */
293*4882a593Smuzhiyun 		break;
294*4882a593Smuzhiyun 		/* Reserved (custom) fields (128..254) */
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
bootp_process_vendor(u8 * ext,int size)298*4882a593Smuzhiyun static void bootp_process_vendor(u8 *ext, int size)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	u8 *end = ext + size;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	debug("[BOOTP] Checking extension (%d bytes)...\n", size);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	while ((ext < end) && (*ext != 0xff)) {
305*4882a593Smuzhiyun 		if (*ext == 0) {
306*4882a593Smuzhiyun 			ext++;
307*4882a593Smuzhiyun 		} else {
308*4882a593Smuzhiyun 			u8 *opt = ext;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 			ext += ext[1] + 2;
311*4882a593Smuzhiyun 			if (ext <= end)
312*4882a593Smuzhiyun 				bootp_process_vendor_field(opt);
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	debug("[BOOTP] Received fields:\n");
317*4882a593Smuzhiyun 	if (net_netmask.s_addr)
318*4882a593Smuzhiyun 		debug("net_netmask : %pI4\n", &net_netmask);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (net_gateway.s_addr)
321*4882a593Smuzhiyun 		debug("net_gateway	: %pI4", &net_gateway);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (net_boot_file_expected_size_in_blocks)
324*4882a593Smuzhiyun 		debug("net_boot_file_expected_size_in_blocks : %d\n",
325*4882a593Smuzhiyun 		      net_boot_file_expected_size_in_blocks);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (net_hostname[0])
328*4882a593Smuzhiyun 		debug("net_hostname  : %s\n", net_hostname);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (net_root_path[0])
331*4882a593Smuzhiyun 		debug("net_root_path  : %s\n", net_root_path);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (net_nis_domain[0])
334*4882a593Smuzhiyun 		debug("net_nis_domain : %s\n", net_nis_domain);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
337*4882a593Smuzhiyun 	if (net_ntp_server)
338*4882a593Smuzhiyun 		debug("net_ntp_server : %pI4\n", &net_ntp_server);
339*4882a593Smuzhiyun #endif
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /*
343*4882a593Smuzhiyun  *	Handle a BOOTP received packet.
344*4882a593Smuzhiyun  */
bootp_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)345*4882a593Smuzhiyun static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
346*4882a593Smuzhiyun 			  unsigned src, unsigned len)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct bootp_hdr *bp;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
351*4882a593Smuzhiyun 	      src, dest, len, sizeof(struct bootp_hdr));
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	bp = (struct bootp_hdr *)pkt;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/* Filter out pkts we don't want */
356*4882a593Smuzhiyun 	if (check_reply_packet(pkt, dest, src, len))
357*4882a593Smuzhiyun 		return;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/*
360*4882a593Smuzhiyun 	 *	Got a good BOOTP reply.	 Copy the data into our variables.
361*4882a593Smuzhiyun 	 */
362*4882a593Smuzhiyun #if defined(CONFIG_LED_STATUS) && defined(CONFIG_LED_STATUS_BOOT_ENABLE)
363*4882a593Smuzhiyun 	status_led_set(CONFIG_LED_STATUS_BOOT, CONFIG_LED_STATUS_OFF);
364*4882a593Smuzhiyun #endif
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	store_net_params(bp);		/* Store net parameters from reply */
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* Retrieve extended information (we must parse the vendor area) */
369*4882a593Smuzhiyun 	if (net_read_u32((u32 *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
370*4882a593Smuzhiyun 		bootp_process_vendor((uchar *)&bp->bp_vend[4], len);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	net_set_timeout_handler(0, (thand_f *)0);
373*4882a593Smuzhiyun 	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	debug("Got good BOOTP\n");
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	net_auto_load();
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun #endif
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun /*
382*4882a593Smuzhiyun  *	Timeout on BOOTP/DHCP request.
383*4882a593Smuzhiyun  */
bootp_timeout_handler(void)384*4882a593Smuzhiyun static void bootp_timeout_handler(void)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	ulong time_taken = get_timer(bootp_start);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (time_taken >= time_taken_max) {
389*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_MAY_FAIL
390*4882a593Smuzhiyun 		puts("\nRetry time exceeded\n");
391*4882a593Smuzhiyun 		net_set_state(NETLOOP_FAIL);
392*4882a593Smuzhiyun #else
393*4882a593Smuzhiyun 		puts("\nRetry time exceeded; starting again\n");
394*4882a593Smuzhiyun 		net_start_again();
395*4882a593Smuzhiyun #endif
396*4882a593Smuzhiyun 	} else {
397*4882a593Smuzhiyun 		bootp_timeout *= 2;
398*4882a593Smuzhiyun 		if (bootp_timeout > 2000)
399*4882a593Smuzhiyun 			bootp_timeout = 2000;
400*4882a593Smuzhiyun 		net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
401*4882a593Smuzhiyun 		bootp_request();
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun #define put_vci(e, str)						\
406*4882a593Smuzhiyun 	do {							\
407*4882a593Smuzhiyun 		size_t vci_strlen = strlen(str);		\
408*4882a593Smuzhiyun 		*e++ = 60;	/* Vendor Class Identifier */	\
409*4882a593Smuzhiyun 		*e++ = vci_strlen;				\
410*4882a593Smuzhiyun 		memcpy(e, str, vci_strlen);			\
411*4882a593Smuzhiyun 		e += vci_strlen;				\
412*4882a593Smuzhiyun 	} while (0)
413*4882a593Smuzhiyun 
add_vci(u8 * e)414*4882a593Smuzhiyun static u8 *add_vci(u8 *e)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	char *vci = NULL;
417*4882a593Smuzhiyun 	char *env_vci = env_get("bootp_vci");
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
420*4882a593Smuzhiyun 	vci = CONFIG_SPL_NET_VCI_STRING;
421*4882a593Smuzhiyun #elif defined(CONFIG_BOOTP_VCI_STRING)
422*4882a593Smuzhiyun 	vci = CONFIG_BOOTP_VCI_STRING;
423*4882a593Smuzhiyun #endif
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (env_vci)
426*4882a593Smuzhiyun 		vci = env_vci;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (vci)
429*4882a593Smuzhiyun 		put_vci(e, vci);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	return e;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun /*
435*4882a593Smuzhiyun  *	Initialize BOOTP extension fields in the request.
436*4882a593Smuzhiyun  */
437*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
dhcp_extended(u8 * e,int message_type,struct in_addr server_ip,struct in_addr requested_ip)438*4882a593Smuzhiyun static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
439*4882a593Smuzhiyun 			struct in_addr requested_ip)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	u8 *start = e;
442*4882a593Smuzhiyun 	u8 *cnt;
443*4882a593Smuzhiyun #ifdef CONFIG_LIB_UUID
444*4882a593Smuzhiyun 	char *uuid;
445*4882a593Smuzhiyun #endif
446*4882a593Smuzhiyun 	int clientarch = -1;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_VENDOREX)
449*4882a593Smuzhiyun 	u8 *x;
450*4882a593Smuzhiyun #endif
451*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_SEND_HOSTNAME)
452*4882a593Smuzhiyun 	char *hostname;
453*4882a593Smuzhiyun #endif
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	*e++ = 99;		/* RFC1048 Magic Cookie */
456*4882a593Smuzhiyun 	*e++ = 130;
457*4882a593Smuzhiyun 	*e++ = 83;
458*4882a593Smuzhiyun 	*e++ = 99;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	*e++ = 53;		/* DHCP Message Type */
461*4882a593Smuzhiyun 	*e++ = 1;
462*4882a593Smuzhiyun 	*e++ = message_type;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	*e++ = 57;		/* Maximum DHCP Message Size */
465*4882a593Smuzhiyun 	*e++ = 2;
466*4882a593Smuzhiyun 	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
467*4882a593Smuzhiyun 	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (server_ip.s_addr) {
470*4882a593Smuzhiyun 		int tmp = ntohl(server_ip.s_addr);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		*e++ = 54;	/* ServerID */
473*4882a593Smuzhiyun 		*e++ = 4;
474*4882a593Smuzhiyun 		*e++ = tmp >> 24;
475*4882a593Smuzhiyun 		*e++ = tmp >> 16;
476*4882a593Smuzhiyun 		*e++ = tmp >> 8;
477*4882a593Smuzhiyun 		*e++ = tmp & 0xff;
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	if (requested_ip.s_addr) {
481*4882a593Smuzhiyun 		int tmp = ntohl(requested_ip.s_addr);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 		*e++ = 50;	/* Requested IP */
484*4882a593Smuzhiyun 		*e++ = 4;
485*4882a593Smuzhiyun 		*e++ = tmp >> 24;
486*4882a593Smuzhiyun 		*e++ = tmp >> 16;
487*4882a593Smuzhiyun 		*e++ = tmp >> 8;
488*4882a593Smuzhiyun 		*e++ = tmp & 0xff;
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_SEND_HOSTNAME)
491*4882a593Smuzhiyun 	hostname = env_get("hostname");
492*4882a593Smuzhiyun 	if (hostname) {
493*4882a593Smuzhiyun 		int hostnamelen = strlen(hostname);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 		*e++ = 12;	/* Hostname */
496*4882a593Smuzhiyun 		*e++ = hostnamelen;
497*4882a593Smuzhiyun 		memcpy(e, hostname, hostnamelen);
498*4882a593Smuzhiyun 		e += hostnamelen;
499*4882a593Smuzhiyun 	}
500*4882a593Smuzhiyun #endif
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_PXE_CLIENTARCH
503*4882a593Smuzhiyun 	clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
504*4882a593Smuzhiyun #endif
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	if (env_get("bootp_arch"))
507*4882a593Smuzhiyun 		clientarch = env_get_ulong("bootp_arch", 16, clientarch);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	if (clientarch > 0) {
510*4882a593Smuzhiyun 		*e++ = 93;	/* Client System Architecture */
511*4882a593Smuzhiyun 		*e++ = 2;
512*4882a593Smuzhiyun 		*e++ = (clientarch >> 8) & 0xff;
513*4882a593Smuzhiyun 		*e++ = clientarch & 0xff;
514*4882a593Smuzhiyun 	}
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	*e++ = 94;	/* Client Network Interface Identifier */
517*4882a593Smuzhiyun 	*e++ = 3;
518*4882a593Smuzhiyun 	*e++ = 1;	/* type field for UNDI */
519*4882a593Smuzhiyun 	*e++ = 0;	/* major revision */
520*4882a593Smuzhiyun 	*e++ = 0;	/* minor revision */
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun #ifdef CONFIG_LIB_UUID
523*4882a593Smuzhiyun 	uuid = env_get("pxeuuid");
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	if (uuid) {
526*4882a593Smuzhiyun 		if (uuid_str_valid(uuid)) {
527*4882a593Smuzhiyun 			*e++ = 97;	/* Client Machine Identifier */
528*4882a593Smuzhiyun 			*e++ = 17;
529*4882a593Smuzhiyun 			*e++ = 0;	/* type 0 - UUID */
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 			uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD);
532*4882a593Smuzhiyun 			e += 16;
533*4882a593Smuzhiyun 		} else {
534*4882a593Smuzhiyun 			printf("Invalid pxeuuid: %s\n", uuid);
535*4882a593Smuzhiyun 		}
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun #endif
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	e = add_vci(e);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_VENDOREX)
542*4882a593Smuzhiyun 	x = dhcp_vendorex_prep(e);
543*4882a593Smuzhiyun 	if (x)
544*4882a593Smuzhiyun 		return x - start;
545*4882a593Smuzhiyun #endif
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	*e++ = 55;		/* Parameter Request List */
548*4882a593Smuzhiyun 	 cnt = e++;		/* Pointer to count of requested items */
549*4882a593Smuzhiyun 	*cnt = 0;
550*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_SUBNETMASK)
551*4882a593Smuzhiyun 	*e++  = 1;		/* Subnet Mask */
552*4882a593Smuzhiyun 	*cnt += 1;
553*4882a593Smuzhiyun #endif
554*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_TIMEOFFSET)
555*4882a593Smuzhiyun 	*e++  = 2;
556*4882a593Smuzhiyun 	*cnt += 1;
557*4882a593Smuzhiyun #endif
558*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_GATEWAY)
559*4882a593Smuzhiyun 	*e++  = 3;		/* Router Option */
560*4882a593Smuzhiyun 	*cnt += 1;
561*4882a593Smuzhiyun #endif
562*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_DNS)
563*4882a593Smuzhiyun 	*e++  = 6;		/* DNS Server(s) */
564*4882a593Smuzhiyun 	*cnt += 1;
565*4882a593Smuzhiyun #endif
566*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_HOSTNAME)
567*4882a593Smuzhiyun 	*e++  = 12;		/* Hostname */
568*4882a593Smuzhiyun 	*cnt += 1;
569*4882a593Smuzhiyun #endif
570*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_BOOTFILESIZE)
571*4882a593Smuzhiyun 	*e++  = 13;		/* Boot File Size */
572*4882a593Smuzhiyun 	*cnt += 1;
573*4882a593Smuzhiyun #endif
574*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_BOOTPATH)
575*4882a593Smuzhiyun 	*e++  = 17;		/* Boot path */
576*4882a593Smuzhiyun 	*cnt += 1;
577*4882a593Smuzhiyun #endif
578*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_NISDOMAIN)
579*4882a593Smuzhiyun 	*e++  = 40;		/* NIS Domain name request */
580*4882a593Smuzhiyun 	*cnt += 1;
581*4882a593Smuzhiyun #endif
582*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_NTPSERVER)
583*4882a593Smuzhiyun 	*e++  = 42;
584*4882a593Smuzhiyun 	*cnt += 1;
585*4882a593Smuzhiyun #endif
586*4882a593Smuzhiyun 	/* no options, so back up to avoid sending an empty request list */
587*4882a593Smuzhiyun 	if (*cnt == 0)
588*4882a593Smuzhiyun 		e -= 2;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	*e++  = 255;		/* End of the list */
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	/* Pad to minimal length */
593*4882a593Smuzhiyun #ifdef	CONFIG_DHCP_MIN_EXT_LEN
594*4882a593Smuzhiyun 	while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
595*4882a593Smuzhiyun 		*e++ = 0;
596*4882a593Smuzhiyun #endif
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	return e - start;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun #else
602*4882a593Smuzhiyun /*
603*4882a593Smuzhiyun  * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
604*4882a593Smuzhiyun  */
bootp_extended(u8 * e)605*4882a593Smuzhiyun static int bootp_extended(u8 *e)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	u8 *start = e;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	*e++ = 99;		/* RFC1048 Magic Cookie */
610*4882a593Smuzhiyun 	*e++ = 130;
611*4882a593Smuzhiyun 	*e++ = 83;
612*4882a593Smuzhiyun 	*e++ = 99;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
615*4882a593Smuzhiyun 	*e++ = 53;		/* DHCP Message Type */
616*4882a593Smuzhiyun 	*e++ = 1;
617*4882a593Smuzhiyun 	*e++ = DHCP_DISCOVER;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	*e++ = 57;		/* Maximum DHCP Message Size */
620*4882a593Smuzhiyun 	*e++ = 2;
621*4882a593Smuzhiyun 	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
622*4882a593Smuzhiyun 	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
623*4882a593Smuzhiyun #endif
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	add_vci(e);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_SUBNETMASK)
628*4882a593Smuzhiyun 	*e++ = 1;		/* Subnet mask request */
629*4882a593Smuzhiyun 	*e++ = 4;
630*4882a593Smuzhiyun 	e   += 4;
631*4882a593Smuzhiyun #endif
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_GATEWAY)
634*4882a593Smuzhiyun 	*e++ = 3;		/* Default gateway request */
635*4882a593Smuzhiyun 	*e++ = 4;
636*4882a593Smuzhiyun 	e   += 4;
637*4882a593Smuzhiyun #endif
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_DNS)
640*4882a593Smuzhiyun 	*e++ = 6;		/* Domain Name Server */
641*4882a593Smuzhiyun 	*e++ = 4;
642*4882a593Smuzhiyun 	e   += 4;
643*4882a593Smuzhiyun #endif
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_HOSTNAME)
646*4882a593Smuzhiyun 	*e++ = 12;		/* Host name request */
647*4882a593Smuzhiyun 	*e++ = 32;
648*4882a593Smuzhiyun 	e   += 32;
649*4882a593Smuzhiyun #endif
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_BOOTFILESIZE)
652*4882a593Smuzhiyun 	*e++ = 13;		/* Boot file size */
653*4882a593Smuzhiyun 	*e++ = 2;
654*4882a593Smuzhiyun 	e   += 2;
655*4882a593Smuzhiyun #endif
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_BOOTPATH)
658*4882a593Smuzhiyun 	*e++ = 17;		/* Boot path */
659*4882a593Smuzhiyun 	*e++ = 32;
660*4882a593Smuzhiyun 	e   += 32;
661*4882a593Smuzhiyun #endif
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_NISDOMAIN)
664*4882a593Smuzhiyun 	*e++ = 40;		/* NIS Domain name request */
665*4882a593Smuzhiyun 	*e++ = 32;
666*4882a593Smuzhiyun 	e   += 32;
667*4882a593Smuzhiyun #endif
668*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_NTPSERVER)
669*4882a593Smuzhiyun 	*e++ = 42;
670*4882a593Smuzhiyun 	*e++ = 4;
671*4882a593Smuzhiyun 	e   += 4;
672*4882a593Smuzhiyun #endif
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	*e++ = 255;		/* End of the list */
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	/*
677*4882a593Smuzhiyun 	 * If nothing in list, remove it altogether. Some DHCP servers get
678*4882a593Smuzhiyun 	 * upset by this minor faux pas and do not respond at all.
679*4882a593Smuzhiyun 	 */
680*4882a593Smuzhiyun 	if (e == start + 3) {
681*4882a593Smuzhiyun 		printf("*** Warning: no DHCP options requested\n");
682*4882a593Smuzhiyun 		e -= 3;
683*4882a593Smuzhiyun 	}
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	return e - start;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun #endif
688*4882a593Smuzhiyun 
bootp_reset(void)689*4882a593Smuzhiyun void bootp_reset(void)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun 	bootp_num_ids = 0;
692*4882a593Smuzhiyun 	bootp_try = 0;
693*4882a593Smuzhiyun 	bootp_start = get_timer(0);
694*4882a593Smuzhiyun 	bootp_timeout = 250;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
bootp_request(void)697*4882a593Smuzhiyun void bootp_request(void)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	uchar *pkt, *iphdr;
700*4882a593Smuzhiyun 	struct bootp_hdr *bp;
701*4882a593Smuzhiyun 	int extlen, pktlen, iplen;
702*4882a593Smuzhiyun 	int eth_hdr_size;
703*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_RANDOM_DELAY
704*4882a593Smuzhiyun 	ulong rand_ms;
705*4882a593Smuzhiyun #endif
706*4882a593Smuzhiyun 	u32 bootp_id;
707*4882a593Smuzhiyun 	struct in_addr zero_ip;
708*4882a593Smuzhiyun 	struct in_addr bcast_ip;
709*4882a593Smuzhiyun 	char *ep;  /* Environment pointer */
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
712*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
713*4882a593Smuzhiyun 	dhcp_state = INIT;
714*4882a593Smuzhiyun #endif
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	ep = env_get("bootpretryperiod");
717*4882a593Smuzhiyun 	if (ep != NULL)
718*4882a593Smuzhiyun 		time_taken_max = simple_strtoul(ep, NULL, 10);
719*4882a593Smuzhiyun 	else
720*4882a593Smuzhiyun 		time_taken_max = TIMEOUT_MS;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
723*4882a593Smuzhiyun 	if (bootp_try == 0)
724*4882a593Smuzhiyun 		srand_mac();
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	if (bootp_try <= 2)	/* Start with max 1024 * 1ms */
727*4882a593Smuzhiyun 		rand_ms = rand() >> (22 - bootp_try);
728*4882a593Smuzhiyun 	else		/* After 3rd BOOTP request max 8192 * 1ms */
729*4882a593Smuzhiyun 		rand_ms = rand() >> 19;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	printf("Random delay: %ld ms...\n", rand_ms);
732*4882a593Smuzhiyun 	mdelay(rand_ms);
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun #endif	/* CONFIG_BOOTP_RANDOM_DELAY */
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	printf("BOOTP broadcast %d\n", ++bootp_try);
737*4882a593Smuzhiyun 	pkt = net_tx_packet;
738*4882a593Smuzhiyun 	memset((void *)pkt, 0, PKTSIZE);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
741*4882a593Smuzhiyun 	pkt += eth_hdr_size;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/*
744*4882a593Smuzhiyun 	 * Next line results in incorrect packet size being transmitted,
745*4882a593Smuzhiyun 	 * resulting in errors in some DHCP servers, reporting missing bytes.
746*4882a593Smuzhiyun 	 * Size must be set in packet header after extension length has been
747*4882a593Smuzhiyun 	 * determined.
748*4882a593Smuzhiyun 	 * C. Hallinan, DS4.COM, Inc.
749*4882a593Smuzhiyun 	 */
750*4882a593Smuzhiyun 	/* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
751*4882a593Smuzhiyun 		sizeof (struct bootp_hdr)); */
752*4882a593Smuzhiyun 	iphdr = pkt;	/* We need this later for net_set_udp_header() */
753*4882a593Smuzhiyun 	pkt += IP_UDP_HDR_SIZE;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	bp = (struct bootp_hdr *)pkt;
756*4882a593Smuzhiyun 	bp->bp_op = OP_BOOTREQUEST;
757*4882a593Smuzhiyun 	bp->bp_htype = HWT_ETHER;
758*4882a593Smuzhiyun 	bp->bp_hlen = HWL_ETHER;
759*4882a593Smuzhiyun 	bp->bp_hops = 0;
760*4882a593Smuzhiyun 	/*
761*4882a593Smuzhiyun 	 * according to RFC1542, should be 0 on first request, secs since
762*4882a593Smuzhiyun 	 * first request otherwise
763*4882a593Smuzhiyun 	 */
764*4882a593Smuzhiyun 	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
765*4882a593Smuzhiyun 	zero_ip.s_addr = 0;
766*4882a593Smuzhiyun 	net_write_ip(&bp->bp_ciaddr, zero_ip);
767*4882a593Smuzhiyun 	net_write_ip(&bp->bp_yiaddr, zero_ip);
768*4882a593Smuzhiyun 	net_write_ip(&bp->bp_siaddr, zero_ip);
769*4882a593Smuzhiyun 	net_write_ip(&bp->bp_giaddr, zero_ip);
770*4882a593Smuzhiyun 	memcpy(bp->bp_chaddr, net_ethaddr, 6);
771*4882a593Smuzhiyun 	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	/* Request additional information from the BOOTP/DHCP server */
774*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
775*4882a593Smuzhiyun 	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_DISCOVER, zero_ip,
776*4882a593Smuzhiyun 			       zero_ip);
777*4882a593Smuzhiyun #else
778*4882a593Smuzhiyun 	extlen = bootp_extended((u8 *)bp->bp_vend);
779*4882a593Smuzhiyun #endif
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/*
782*4882a593Smuzhiyun 	 *	Bootp ID is the lower 4 bytes of our ethernet address
783*4882a593Smuzhiyun 	 *	plus the current time in ms.
784*4882a593Smuzhiyun 	 */
785*4882a593Smuzhiyun 	bootp_id = ((u32)net_ethaddr[2] << 24)
786*4882a593Smuzhiyun 		| ((u32)net_ethaddr[3] << 16)
787*4882a593Smuzhiyun 		| ((u32)net_ethaddr[4] << 8)
788*4882a593Smuzhiyun 		| (u32)net_ethaddr[5];
789*4882a593Smuzhiyun 	bootp_id += get_timer(0);
790*4882a593Smuzhiyun 	bootp_id = htonl(bootp_id);
791*4882a593Smuzhiyun 	bootp_add_id(bootp_id);
792*4882a593Smuzhiyun 	net_copy_u32(&bp->bp_id, &bootp_id);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	/*
795*4882a593Smuzhiyun 	 * Calculate proper packet lengths taking into account the
796*4882a593Smuzhiyun 	 * variable size of the options field
797*4882a593Smuzhiyun 	 */
798*4882a593Smuzhiyun 	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
799*4882a593Smuzhiyun 	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
800*4882a593Smuzhiyun 	bcast_ip.s_addr = 0xFFFFFFFFL;
801*4882a593Smuzhiyun 	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
802*4882a593Smuzhiyun 	net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
805*4882a593Smuzhiyun 	dhcp_state = SELECTING;
806*4882a593Smuzhiyun 	net_set_udp_handler(dhcp_handler);
807*4882a593Smuzhiyun #else
808*4882a593Smuzhiyun 	net_set_udp_handler(bootp_handler);
809*4882a593Smuzhiyun #endif
810*4882a593Smuzhiyun 	net_send_packet(net_tx_packet, pktlen);
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun #if defined(CONFIG_CMD_DHCP)
dhcp_process_options(uchar * popt,uchar * end)814*4882a593Smuzhiyun static void dhcp_process_options(uchar *popt, uchar *end)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	int oplen, size;
817*4882a593Smuzhiyun #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
818*4882a593Smuzhiyun 	int *to_ptr;
819*4882a593Smuzhiyun #endif
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	while (popt < end && *popt != 0xff) {
822*4882a593Smuzhiyun 		oplen = *(popt + 1);
823*4882a593Smuzhiyun 		switch (*popt) {
824*4882a593Smuzhiyun 		case 0:
825*4882a593Smuzhiyun 			oplen = -1; /* Pad omits len byte */
826*4882a593Smuzhiyun 			break;
827*4882a593Smuzhiyun 		case 1:
828*4882a593Smuzhiyun 			net_copy_ip(&net_netmask, (popt + 2));
829*4882a593Smuzhiyun 			break;
830*4882a593Smuzhiyun #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
831*4882a593Smuzhiyun 		case 2:		/* Time offset	*/
832*4882a593Smuzhiyun 			to_ptr = &net_ntp_time_offset;
833*4882a593Smuzhiyun 			net_copy_u32((u32 *)to_ptr, (u32 *)(popt + 2));
834*4882a593Smuzhiyun 			net_ntp_time_offset = ntohl(net_ntp_time_offset);
835*4882a593Smuzhiyun 			break;
836*4882a593Smuzhiyun #endif
837*4882a593Smuzhiyun 		case 3:
838*4882a593Smuzhiyun 			net_copy_ip(&net_gateway, (popt + 2));
839*4882a593Smuzhiyun 			break;
840*4882a593Smuzhiyun 		case 6:
841*4882a593Smuzhiyun 			net_copy_ip(&net_dns_server, (popt + 2));
842*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_DNS2)
843*4882a593Smuzhiyun 			if (*(popt + 1) > 4)
844*4882a593Smuzhiyun 				net_copy_ip(&net_dns_server2, (popt + 2 + 4));
845*4882a593Smuzhiyun #endif
846*4882a593Smuzhiyun 			break;
847*4882a593Smuzhiyun 		case 12:
848*4882a593Smuzhiyun 			size = truncate_sz("Host Name",
849*4882a593Smuzhiyun 				sizeof(net_hostname), oplen);
850*4882a593Smuzhiyun 			memcpy(&net_hostname, popt + 2, size);
851*4882a593Smuzhiyun 			net_hostname[size] = 0;
852*4882a593Smuzhiyun 			break;
853*4882a593Smuzhiyun 		case 15:	/* Ignore Domain Name Option */
854*4882a593Smuzhiyun 			break;
855*4882a593Smuzhiyun 		case 17:
856*4882a593Smuzhiyun 			size = truncate_sz("Root Path",
857*4882a593Smuzhiyun 				sizeof(net_root_path), oplen);
858*4882a593Smuzhiyun 			memcpy(&net_root_path, popt + 2, size);
859*4882a593Smuzhiyun 			net_root_path[size] = 0;
860*4882a593Smuzhiyun 			break;
861*4882a593Smuzhiyun 		case 28:	/* Ignore Broadcast Address Option */
862*4882a593Smuzhiyun 			break;
863*4882a593Smuzhiyun #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
864*4882a593Smuzhiyun 		case 42:	/* NTP server IP */
865*4882a593Smuzhiyun 			net_copy_ip(&net_ntp_server, (popt + 2));
866*4882a593Smuzhiyun 			break;
867*4882a593Smuzhiyun #endif
868*4882a593Smuzhiyun 		case 51:
869*4882a593Smuzhiyun 			net_copy_u32(&dhcp_leasetime, (u32 *)(popt + 2));
870*4882a593Smuzhiyun 			break;
871*4882a593Smuzhiyun 		case 52:
872*4882a593Smuzhiyun 			dhcp_option_overload = popt[2];
873*4882a593Smuzhiyun 			break;
874*4882a593Smuzhiyun 		case 53:	/* Ignore Message Type Option */
875*4882a593Smuzhiyun 			break;
876*4882a593Smuzhiyun 		case 54:
877*4882a593Smuzhiyun 			net_copy_ip(&dhcp_server_ip, (popt + 2));
878*4882a593Smuzhiyun 			break;
879*4882a593Smuzhiyun 		case 58:	/* Ignore Renewal Time Option */
880*4882a593Smuzhiyun 			break;
881*4882a593Smuzhiyun 		case 59:	/* Ignore Rebinding Time Option */
882*4882a593Smuzhiyun 			break;
883*4882a593Smuzhiyun 		case 66:	/* Ignore TFTP server name */
884*4882a593Smuzhiyun 			break;
885*4882a593Smuzhiyun 		case 67:	/* Bootfile option */
886*4882a593Smuzhiyun 			size = truncate_sz("Bootfile",
887*4882a593Smuzhiyun 					   sizeof(net_boot_file_name), oplen);
888*4882a593Smuzhiyun 			memcpy(&net_boot_file_name, popt + 2, size);
889*4882a593Smuzhiyun 			net_boot_file_name[size] = 0;
890*4882a593Smuzhiyun 			break;
891*4882a593Smuzhiyun 		default:
892*4882a593Smuzhiyun #if defined(CONFIG_BOOTP_VENDOREX)
893*4882a593Smuzhiyun 			if (dhcp_vendorex_proc(popt))
894*4882a593Smuzhiyun 				break;
895*4882a593Smuzhiyun #endif
896*4882a593Smuzhiyun 			printf("*** Unhandled DHCP Option in OFFER/ACK:"
897*4882a593Smuzhiyun 			       " %d\n", *popt);
898*4882a593Smuzhiyun 			break;
899*4882a593Smuzhiyun 		}
900*4882a593Smuzhiyun 		popt += oplen + 2;	/* Process next option */
901*4882a593Smuzhiyun 	}
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun 
dhcp_packet_process_options(struct bootp_hdr * bp)904*4882a593Smuzhiyun static void dhcp_packet_process_options(struct bootp_hdr *bp)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	uchar *popt = (uchar *)&bp->bp_vend[4];
907*4882a593Smuzhiyun 	uchar *end = popt + BOOTP_HDR_SIZE;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
910*4882a593Smuzhiyun 		return;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	dhcp_option_overload = 0;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	/*
915*4882a593Smuzhiyun 	 * The 'options' field MUST be interpreted first, 'file' next,
916*4882a593Smuzhiyun 	 * 'sname' last.
917*4882a593Smuzhiyun 	 */
918*4882a593Smuzhiyun 	dhcp_process_options(popt, end);
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	if (dhcp_option_overload & OVERLOAD_FILE) {
921*4882a593Smuzhiyun 		popt = (uchar *)bp->bp_file;
922*4882a593Smuzhiyun 		end = popt + sizeof(bp->bp_file);
923*4882a593Smuzhiyun 		dhcp_process_options(popt, end);
924*4882a593Smuzhiyun 	}
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if (dhcp_option_overload & OVERLOAD_SNAME) {
927*4882a593Smuzhiyun 		popt = (uchar *)bp->bp_sname;
928*4882a593Smuzhiyun 		end = popt + sizeof(bp->bp_sname);
929*4882a593Smuzhiyun 		dhcp_process_options(popt, end);
930*4882a593Smuzhiyun 	}
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun 
dhcp_message_type(unsigned char * popt)933*4882a593Smuzhiyun static int dhcp_message_type(unsigned char *popt)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun 	if (net_read_u32((u32 *)popt) != htonl(BOOTP_VENDOR_MAGIC))
936*4882a593Smuzhiyun 		return -1;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	popt += 4;
939*4882a593Smuzhiyun 	while (*popt != 0xff) {
940*4882a593Smuzhiyun 		if (*popt == 53)	/* DHCP Message Type */
941*4882a593Smuzhiyun 			return *(popt + 2);
942*4882a593Smuzhiyun 		if (*popt == 0)	{
943*4882a593Smuzhiyun 			/* Pad */
944*4882a593Smuzhiyun 			popt += 1;
945*4882a593Smuzhiyun 		} else {
946*4882a593Smuzhiyun 			/* Scan through all options */
947*4882a593Smuzhiyun 			popt += *(popt + 1) + 2;
948*4882a593Smuzhiyun 		}
949*4882a593Smuzhiyun 	}
950*4882a593Smuzhiyun 	return -1;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun 
dhcp_send_request_packet(struct bootp_hdr * bp_offer)953*4882a593Smuzhiyun static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun 	uchar *pkt, *iphdr;
956*4882a593Smuzhiyun 	struct bootp_hdr *bp;
957*4882a593Smuzhiyun 	int pktlen, iplen, extlen;
958*4882a593Smuzhiyun 	int eth_hdr_size;
959*4882a593Smuzhiyun 	struct in_addr offered_ip;
960*4882a593Smuzhiyun 	struct in_addr zero_ip;
961*4882a593Smuzhiyun 	struct in_addr bcast_ip;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	debug("dhcp_send_request_packet: Sending DHCPREQUEST\n");
964*4882a593Smuzhiyun 	pkt = net_tx_packet;
965*4882a593Smuzhiyun 	memset((void *)pkt, 0, PKTSIZE);
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_IP);
968*4882a593Smuzhiyun 	pkt += eth_hdr_size;
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	iphdr = pkt;	/* We'll need this later to set proper pkt size */
971*4882a593Smuzhiyun 	pkt += IP_UDP_HDR_SIZE;
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	bp = (struct bootp_hdr *)pkt;
974*4882a593Smuzhiyun 	bp->bp_op = OP_BOOTREQUEST;
975*4882a593Smuzhiyun 	bp->bp_htype = HWT_ETHER;
976*4882a593Smuzhiyun 	bp->bp_hlen = HWL_ETHER;
977*4882a593Smuzhiyun 	bp->bp_hops = 0;
978*4882a593Smuzhiyun 	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
979*4882a593Smuzhiyun 	/* Do not set the client IP, your IP, or server IP yet, since it
980*4882a593Smuzhiyun 	 * hasn't been ACK'ed by the server yet */
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	/*
983*4882a593Smuzhiyun 	 * RFC3046 requires Relay Agents to discard packets with
984*4882a593Smuzhiyun 	 * nonzero and offered giaddr
985*4882a593Smuzhiyun 	 */
986*4882a593Smuzhiyun 	zero_ip.s_addr = 0;
987*4882a593Smuzhiyun 	net_write_ip(&bp->bp_giaddr, zero_ip);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	memcpy(bp->bp_chaddr, net_ethaddr, 6);
990*4882a593Smuzhiyun 	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	/*
993*4882a593Smuzhiyun 	 * ID is the id of the OFFER packet
994*4882a593Smuzhiyun 	 */
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	net_copy_u32(&bp->bp_id, &bp_offer->bp_id);
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	/*
999*4882a593Smuzhiyun 	 * Copy options from OFFER packet if present
1000*4882a593Smuzhiyun 	 */
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	/* Copy offered IP into the parameters request list */
1003*4882a593Smuzhiyun 	net_copy_ip(&offered_ip, &bp_offer->bp_yiaddr);
1004*4882a593Smuzhiyun 	extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_REQUEST,
1005*4882a593Smuzhiyun 		dhcp_server_ip, offered_ip);
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
1008*4882a593Smuzhiyun 	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
1009*4882a593Smuzhiyun 	bcast_ip.s_addr = 0xFFFFFFFFL;
1010*4882a593Smuzhiyun 	net_set_udp_header(iphdr, bcast_ip, PORT_BOOTPS, PORT_BOOTPC, iplen);
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun #ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
1013*4882a593Smuzhiyun 	udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
1014*4882a593Smuzhiyun #endif	/* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
1015*4882a593Smuzhiyun 	debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
1016*4882a593Smuzhiyun 	net_send_packet(net_tx_packet, pktlen);
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun /*
1020*4882a593Smuzhiyun  *	Handle DHCP received packets.
1021*4882a593Smuzhiyun  */
dhcp_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)1022*4882a593Smuzhiyun static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
1023*4882a593Smuzhiyun 			 unsigned src, unsigned len)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun 	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
1028*4882a593Smuzhiyun 	      src, dest, len, dhcp_state);
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	/* Filter out pkts we don't want */
1031*4882a593Smuzhiyun 	if (check_reply_packet(pkt, dest, src, len))
1032*4882a593Smuzhiyun 		return;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
1035*4882a593Smuzhiyun 	      "%d\n", src, dest, len, dhcp_state);
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
1038*4882a593Smuzhiyun 		return;
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	switch (dhcp_state) {
1041*4882a593Smuzhiyun 	case SELECTING:
1042*4882a593Smuzhiyun 		/*
1043*4882a593Smuzhiyun 		 * Wait an appropriate time for any potential DHCPOFFER packets
1044*4882a593Smuzhiyun 		 * to arrive.  Then select one, and generate DHCPREQUEST
1045*4882a593Smuzhiyun 		 * response.  If filename is in format we recognize, assume it
1046*4882a593Smuzhiyun 		 * is a valid OFFER from a server we want.
1047*4882a593Smuzhiyun 		 */
1048*4882a593Smuzhiyun 		debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
1049*4882a593Smuzhiyun #ifdef CONFIG_SYS_BOOTFILE_PREFIX
1050*4882a593Smuzhiyun 		if (strncmp(bp->bp_file,
1051*4882a593Smuzhiyun 			    CONFIG_SYS_BOOTFILE_PREFIX,
1052*4882a593Smuzhiyun 			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
1053*4882a593Smuzhiyun #endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
1054*4882a593Smuzhiyun 			dhcp_packet_process_options(bp);
1055*4882a593Smuzhiyun 			efi_net_set_dhcp_ack(pkt, len);
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 			debug("TRANSITIONING TO REQUESTING STATE\n");
1058*4882a593Smuzhiyun 			dhcp_state = REQUESTING;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 			net_set_timeout_handler(5000, bootp_timeout_handler);
1061*4882a593Smuzhiyun 			dhcp_send_request_packet(bp);
1062*4882a593Smuzhiyun #ifdef CONFIG_SYS_BOOTFILE_PREFIX
1063*4882a593Smuzhiyun 		}
1064*4882a593Smuzhiyun #endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 		return;
1067*4882a593Smuzhiyun 		break;
1068*4882a593Smuzhiyun 	case REQUESTING:
1069*4882a593Smuzhiyun 		debug("DHCP State: REQUESTING\n");
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 		if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
1072*4882a593Smuzhiyun 			dhcp_packet_process_options(bp);
1073*4882a593Smuzhiyun 			/* Store net params from reply */
1074*4882a593Smuzhiyun 			store_net_params(bp);
1075*4882a593Smuzhiyun 			dhcp_state = BOUND;
1076*4882a593Smuzhiyun 			printf("DHCP client bound to address %pI4 (%lu ms)\n",
1077*4882a593Smuzhiyun 			       &net_ip, get_timer(bootp_start));
1078*4882a593Smuzhiyun 			net_set_timeout_handler(0, (thand_f *)0);
1079*4882a593Smuzhiyun 			bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
1080*4882a593Smuzhiyun 					    "bootp_stop");
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 			net_auto_load();
1083*4882a593Smuzhiyun 			return;
1084*4882a593Smuzhiyun 		}
1085*4882a593Smuzhiyun 		break;
1086*4882a593Smuzhiyun 	case BOUND:
1087*4882a593Smuzhiyun 		/* DHCP client bound to address */
1088*4882a593Smuzhiyun 		break;
1089*4882a593Smuzhiyun 	default:
1090*4882a593Smuzhiyun 		puts("DHCP: INVALID STATE\n");
1091*4882a593Smuzhiyun 		break;
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun 
dhcp_request(void)1095*4882a593Smuzhiyun void dhcp_request(void)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun 	bootp_request();
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun #endif	/* CONFIG_CMD_DHCP */
1100