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