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