BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Dynamic Host Configuration Protocol client |
||
4 | * |
||
5 | * @defgroup dhcp4 DHCPv4 |
||
6 | * @ingroup ip4 |
||
7 | * DHCP (IPv4) related functions |
||
8 | * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform |
||
9 | * with RFC 2131 and RFC 2132. |
||
10 | * |
||
11 | * @todo: |
||
12 | * - Support for interfaces other than Ethernet (SLIP, PPP, ...) |
||
13 | * |
||
14 | * Options: |
||
15 | * @ref DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) |
||
16 | * @ref DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) |
||
17 | * |
||
18 | * dhcp_start() starts a DHCP client instance which |
||
19 | * configures the interface by obtaining an IP address lease and maintaining it. |
||
20 | * |
||
21 | * Use dhcp_release() to end the lease and use dhcp_stop() |
||
22 | * to remove the DHCP client. |
||
23 | * |
||
24 | * @see LWIP_HOOK_DHCP_APPEND_OPTIONS |
||
25 | * @see LWIP_HOOK_DHCP_PARSE_OPTION |
||
26 | * |
||
27 | * @see netifapi_dhcp4 |
||
28 | */ |
||
29 | |||
30 | /* |
||
31 | * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net> |
||
32 | * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. |
||
33 | * All rights reserved. |
||
34 | * |
||
35 | * Redistribution and use in source and binary forms, with or without modification, |
||
36 | * are permitted provided that the following conditions are met: |
||
37 | * |
||
38 | * 1. Redistributions of source code must retain the above copyright notice, |
||
39 | * this list of conditions and the following disclaimer. |
||
40 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
41 | * this list of conditions and the following disclaimer in the documentation |
||
42 | * and/or other materials provided with the distribution. |
||
43 | * 3. The name of the author may not be used to endorse or promote products |
||
44 | * derived from this software without specific prior written permission. |
||
45 | * |
||
46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
47 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
48 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
49 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
50 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
51 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
52 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
53 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
54 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
55 | * OF SUCH DAMAGE. |
||
56 | * |
||
57 | * This file is part of the lwIP TCP/IP stack. |
||
58 | * The Swedish Institute of Computer Science and Adam Dunkels |
||
59 | * are specifically granted permission to redistribute this |
||
60 | * source code. |
||
61 | * |
||
62 | * Author: Leon Woestenberg <leon.woestenberg@gmx.net> |
||
63 | * |
||
64 | */ |
||
65 | |||
66 | #include "lwip/opt.h" |
||
67 | |||
68 | #if LWIP_IPV4 && LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ |
||
69 | |||
70 | #include "lwip/stats.h" |
||
71 | #include "lwip/mem.h" |
||
72 | #include "lwip/udp.h" |
||
73 | #include "lwip/ip_addr.h" |
||
74 | #include "lwip/netif.h" |
||
75 | #include "lwip/def.h" |
||
76 | #include "lwip/dhcp.h" |
||
77 | #include "lwip/autoip.h" |
||
78 | #include "lwip/dns.h" |
||
79 | #include "lwip/etharp.h" |
||
80 | #include "lwip/prot/dhcp.h" |
||
81 | #include "lwip/prot/iana.h" |
||
82 | |||
83 | #include <string.h> |
||
84 | |||
85 | #ifdef LWIP_HOOK_FILENAME |
||
86 | #include LWIP_HOOK_FILENAME |
||
87 | #endif |
||
88 | #ifndef LWIP_HOOK_DHCP_APPEND_OPTIONS |
||
89 | #define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) |
||
90 | #endif |
||
91 | #ifndef LWIP_HOOK_DHCP_PARSE_OPTION |
||
92 | #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0) |
||
93 | #endif |
||
94 | |||
95 | /** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using |
||
96 | * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) |
||
97 | */ |
||
98 | #ifndef DHCP_CREATE_RAND_XID |
||
99 | #define DHCP_CREATE_RAND_XID 1 |
||
100 | #endif |
||
101 | |||
102 | /** Default for DHCP_GLOBAL_XID is 0xABCD0000 |
||
103 | * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. |
||
104 | * \#define DHCP_GLOBAL_XID_HEADER "stdlib.h" |
||
105 | * \#define DHCP_GLOBAL_XID rand() |
||
106 | */ |
||
107 | #ifdef DHCP_GLOBAL_XID_HEADER |
||
108 | #include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ |
||
109 | #endif |
||
110 | |||
111 | /** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU |
||
112 | * MTU is checked to be big enough in dhcp_start */ |
||
113 | #define DHCP_MAX_MSG_LEN(netif) (netif->mtu) |
||
114 | #define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 |
||
115 | /** Minimum length for reply before packet is parsed */ |
||
116 | #define DHCP_MIN_REPLY_LEN 44 |
||
117 | |||
118 | #define REBOOT_TRIES 2 |
||
119 | |||
120 | #if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS |
||
121 | #if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS |
||
122 | #define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS |
||
123 | #else |
||
124 | #define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS |
||
125 | #endif |
||
126 | #else |
||
127 | #define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 |
||
128 | #endif |
||
129 | |||
130 | /** Option handling: options are parsed in dhcp_parse_reply |
||
131 | * and saved in an array where other functions can load them from. |
||
132 | * This might be moved into the struct dhcp (not necessarily since |
||
133 | * lwIP is single-threaded and the array is only used while in recv |
||
134 | * callback). */ |
||
135 | enum dhcp_option_idx { |
||
136 | DHCP_OPTION_IDX_OVERLOAD = 0, |
||
137 | DHCP_OPTION_IDX_MSG_TYPE, |
||
138 | DHCP_OPTION_IDX_SERVER_ID, |
||
139 | DHCP_OPTION_IDX_LEASE_TIME, |
||
140 | DHCP_OPTION_IDX_T1, |
||
141 | DHCP_OPTION_IDX_T2, |
||
142 | DHCP_OPTION_IDX_SUBNET_MASK, |
||
143 | DHCP_OPTION_IDX_ROUTER, |
||
144 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS |
||
145 | DHCP_OPTION_IDX_DNS_SERVER, |
||
146 | DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, |
||
147 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ |
||
148 | #if LWIP_DHCP_GET_NTP_SRV |
||
149 | DHCP_OPTION_IDX_NTP_SERVER, |
||
150 | DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, |
||
151 | #endif /* LWIP_DHCP_GET_NTP_SRV */ |
||
152 | DHCP_OPTION_IDX_MAX |
||
153 | }; |
||
154 | |||
155 | /** Holds the decoded option values, only valid while in dhcp_recv. |
||
156 | @todo: move this into struct dhcp? */ |
||
157 | u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; |
||
158 | /** Holds a flag which option was received and is contained in dhcp_rx_options_val, |
||
159 | only valid while in dhcp_recv. |
||
160 | @todo: move this into struct dhcp? */ |
||
161 | u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; |
||
162 | |||
163 | static u8_t dhcp_discover_request_options[] = { |
||
164 | DHCP_OPTION_SUBNET_MASK, |
||
165 | DHCP_OPTION_ROUTER, |
||
166 | DHCP_OPTION_BROADCAST |
||
167 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS |
||
168 | , DHCP_OPTION_DNS_SERVER |
||
169 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ |
||
170 | #if LWIP_DHCP_GET_NTP_SRV |
||
171 | , DHCP_OPTION_NTP |
||
172 | #endif /* LWIP_DHCP_GET_NTP_SRV */ |
||
173 | }; |
||
174 | |||
175 | #ifdef DHCP_GLOBAL_XID |
||
176 | static u32_t xid; |
||
177 | static u8_t xid_initialised; |
||
178 | #endif /* DHCP_GLOBAL_XID */ |
||
179 | |||
180 | #define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) |
||
181 | #define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) |
||
182 | #define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) |
||
183 | #define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) |
||
184 | #define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) |
||
185 | #define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) |
||
186 | |||
187 | static struct udp_pcb *dhcp_pcb; |
||
188 | static u8_t dhcp_pcb_refcount; |
||
189 | |||
190 | /* DHCP client state machine functions */ |
||
191 | static err_t dhcp_discover(struct netif *netif); |
||
192 | static err_t dhcp_select(struct netif *netif); |
||
193 | static void dhcp_bind(struct netif *netif); |
||
194 | #if DHCP_DOES_ARP_CHECK |
||
195 | static err_t dhcp_decline(struct netif *netif); |
||
196 | #endif /* DHCP_DOES_ARP_CHECK */ |
||
197 | static err_t dhcp_rebind(struct netif *netif); |
||
198 | static err_t dhcp_reboot(struct netif *netif); |
||
199 | static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); |
||
200 | |||
201 | /* receive, unfold, parse and free incoming messages */ |
||
202 | static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); |
||
203 | |||
204 | /* set the DHCP timers */ |
||
205 | static void dhcp_timeout(struct netif *netif); |
||
206 | static void dhcp_t1_timeout(struct netif *netif); |
||
207 | static void dhcp_t2_timeout(struct netif *netif); |
||
208 | |||
209 | /* build outgoing messages */ |
||
210 | /* create a DHCP message, fill in common headers */ |
||
211 | static struct pbuf *dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len); |
||
212 | /* add a DHCP option (type, then length in bytes) */ |
||
213 | static u16_t dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len); |
||
214 | /* add option values */ |
||
215 | static u16_t dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value); |
||
216 | static u16_t dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value); |
||
217 | static u16_t dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value); |
||
218 | #if LWIP_NETIF_HOSTNAME |
||
219 | static u16_t dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif); |
||
220 | #endif /* LWIP_NETIF_HOSTNAME */ |
||
221 | /* always add the DHCP options trailer to end and pad */ |
||
222 | static void dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out); |
||
223 | |||
224 | /** Ensure DHCP PCB is allocated and bound */ |
||
225 | static err_t |
||
226 | dhcp_inc_pcb_refcount(void) |
||
227 | { |
||
228 | if (dhcp_pcb_refcount == 0) { |
||
229 | LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL); |
||
230 | |||
231 | /* allocate UDP PCB */ |
||
232 | dhcp_pcb = udp_new(); |
||
233 | |||
234 | if (dhcp_pcb == NULL) { |
||
235 | return ERR_MEM; |
||
236 | } |
||
237 | |||
238 | ip_set_option(dhcp_pcb, SOF_BROADCAST); |
||
239 | |||
240 | /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ |
||
241 | udp_bind(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT); |
||
242 | udp_connect(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER); |
||
243 | udp_recv(dhcp_pcb, dhcp_recv, NULL); |
||
244 | } |
||
245 | |||
246 | dhcp_pcb_refcount++; |
||
247 | |||
248 | return ERR_OK; |
||
249 | } |
||
250 | |||
251 | /** Free DHCP PCB if the last netif stops using it */ |
||
252 | static void |
||
253 | dhcp_dec_pcb_refcount(void) |
||
254 | { |
||
255 | LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0)); |
||
256 | dhcp_pcb_refcount--; |
||
257 | |||
258 | if (dhcp_pcb_refcount == 0) { |
||
259 | udp_remove(dhcp_pcb); |
||
260 | dhcp_pcb = NULL; |
||
261 | } |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Back-off the DHCP client (because of a received NAK response). |
||
266 | * |
||
267 | * Back-off the DHCP client because of a received NAK. Receiving a |
||
268 | * NAK means the client asked for something non-sensible, for |
||
269 | * example when it tries to renew a lease obtained on another network. |
||
270 | * |
||
271 | * We clear any existing set IP address and restart DHCP negotiation |
||
272 | * afresh (as per RFC2131 3.2.3). |
||
273 | * |
||
274 | * @param netif the netif under DHCP control |
||
275 | */ |
||
276 | static void |
||
277 | dhcp_handle_nak(struct netif *netif) |
||
278 | { |
||
279 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
280 | |||
281 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", |
||
282 | (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); |
||
283 | /* Change to a defined state - set this before assigning the address |
||
284 | to ensure the callback can use dhcp_supplied_address() */ |
||
285 | dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); |
||
286 | /* remove IP address from interface (must no longer be used, as per RFC2131) */ |
||
287 | netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); |
||
288 | /* We can immediately restart discovery */ |
||
289 | dhcp_discover(netif); |
||
290 | } |
||
291 | |||
292 | #if DHCP_DOES_ARP_CHECK |
||
293 | /** |
||
294 | * Checks if the offered IP address is already in use. |
||
295 | * |
||
296 | * It does so by sending an ARP request for the offered address and |
||
297 | * entering CHECKING state. If no ARP reply is received within a small |
||
298 | * interval, the address is assumed to be free for use by us. |
||
299 | * |
||
300 | * @param netif the netif under DHCP control |
||
301 | */ |
||
302 | static void |
||
303 | dhcp_check(struct netif *netif) |
||
304 | { |
||
305 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
306 | err_t result; |
||
307 | u16_t msecs; |
||
308 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], |
||
309 | (s16_t)netif->name[1])); |
||
310 | dhcp_set_state(dhcp, DHCP_STATE_CHECKING); |
||
311 | /* create an ARP query for the offered IP address, expecting that no host |
||
312 | responds, as the IP address should not be in use. */ |
||
313 | result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); |
||
314 | if (result != ERR_OK) { |
||
315 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); |
||
316 | } |
||
317 | if (dhcp->tries < 255) { |
||
318 | dhcp->tries++; |
||
319 | } |
||
320 | msecs = 500; |
||
321 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
322 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); |
||
323 | } |
||
324 | #endif /* DHCP_DOES_ARP_CHECK */ |
||
325 | |||
326 | /** |
||
327 | * Remember the configuration offered by a DHCP server. |
||
328 | * |
||
329 | * @param netif the netif under DHCP control |
||
330 | */ |
||
331 | static void |
||
332 | dhcp_handle_offer(struct netif *netif, struct dhcp_msg *msg_in) |
||
333 | { |
||
334 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
335 | |||
336 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", |
||
337 | (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); |
||
338 | /* obtain the server address */ |
||
339 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { |
||
340 | ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); |
||
341 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", |
||
342 | ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); |
||
343 | /* remember offered address */ |
||
344 | ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr); |
||
345 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", |
||
346 | ip4_addr_get_u32(&dhcp->offered_ip_addr))); |
||
347 | |||
348 | dhcp_select(netif); |
||
349 | } else { |
||
350 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
351 | ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void *)netif)); |
||
352 | } |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Select a DHCP server offer out of all offers. |
||
357 | * |
||
358 | * Simply select the first offer received. |
||
359 | * |
||
360 | * @param netif the netif under DHCP control |
||
361 | * @return lwIP specific error (see error.h) |
||
362 | */ |
||
363 | static err_t |
||
364 | dhcp_select(struct netif *netif) |
||
365 | { |
||
366 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
367 | err_t result; |
||
368 | u16_t msecs; |
||
369 | u8_t i; |
||
370 | struct pbuf *p_out; |
||
371 | u16_t options_out_len; |
||
372 | |||
373 | LWIP_ERROR("dhcp_select: netif != NULL", (netif != NULL), return ERR_ARG;); |
||
374 | LWIP_ERROR("dhcp_select: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); |
||
375 | |||
376 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); |
||
377 | dhcp_set_state(dhcp, DHCP_STATE_REQUESTING); |
||
378 | |||
379 | /* create and initialize the DHCP message header */ |
||
380 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); |
||
381 | if (p_out != NULL) { |
||
382 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
383 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
384 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); |
||
385 | |||
386 | /* MUST request the offered IP address */ |
||
387 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); |
||
388 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); |
||
389 | |||
390 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); |
||
391 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); |
||
392 | |||
393 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); |
||
394 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { |
||
395 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); |
||
396 | } |
||
397 | |||
398 | #if LWIP_NETIF_HOSTNAME |
||
399 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); |
||
400 | #endif /* LWIP_NETIF_HOSTNAME */ |
||
401 | |||
402 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REQUESTING, msg_out, DHCP_REQUEST, &options_out_len); |
||
403 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
404 | |||
405 | /* send broadcast to any DHCP server */ |
||
406 | result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); |
||
407 | pbuf_free(p_out); |
||
408 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); |
||
409 | } else { |
||
410 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); |
||
411 | result = ERR_MEM; |
||
412 | } |
||
413 | if (dhcp->tries < 255) { |
||
414 | dhcp->tries++; |
||
415 | } |
||
416 | msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); |
||
417 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
418 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); |
||
419 | return result; |
||
420 | } |
||
421 | |||
422 | /** |
||
423 | * The DHCP timer that checks for lease renewal/rebind timeouts. |
||
424 | * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS). |
||
425 | */ |
||
426 | void |
||
427 | dhcp_coarse_tmr(void) |
||
428 | { |
||
429 | struct netif *netif; |
||
430 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); |
||
431 | /* iterate through all network interfaces */ |
||
432 | NETIF_FOREACH(netif) { |
||
433 | /* only act on DHCP configured interfaces */ |
||
434 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
435 | if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { |
||
436 | /* compare lease time to expire timeout */ |
||
437 | if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) { |
||
438 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n")); |
||
439 | /* this clients' lease time has expired */ |
||
440 | dhcp_release_and_stop(netif); |
||
441 | dhcp_start(netif); |
||
442 | /* timer is active (non zero), and triggers (zeroes) now? */ |
||
443 | } else if (dhcp->t2_rebind_time && (dhcp->t2_rebind_time-- == 1)) { |
||
444 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); |
||
445 | /* this clients' rebind timeout triggered */ |
||
446 | dhcp_t2_timeout(netif); |
||
447 | /* timer is active (non zero), and triggers (zeroes) now */ |
||
448 | } else if (dhcp->t1_renew_time && (dhcp->t1_renew_time-- == 1)) { |
||
449 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); |
||
450 | /* this clients' renewal timeout triggered */ |
||
451 | dhcp_t1_timeout(netif); |
||
452 | } |
||
453 | } |
||
454 | } |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * DHCP transaction timeout handling (this function must be called every 500ms, |
||
459 | * see @ref DHCP_FINE_TIMER_MSECS). |
||
460 | * |
||
461 | * A DHCP server is expected to respond within a short period of time. |
||
462 | * This timer checks whether an outstanding DHCP request is timed out. |
||
463 | */ |
||
464 | void |
||
465 | dhcp_fine_tmr(void) |
||
466 | { |
||
467 | struct netif *netif; |
||
468 | /* loop through netif's */ |
||
469 | NETIF_FOREACH(netif) { |
||
470 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
471 | /* only act on DHCP configured interfaces */ |
||
472 | if (dhcp != NULL) { |
||
473 | /* timer is active (non zero), and is about to trigger now */ |
||
474 | if (dhcp->request_timeout > 1) { |
||
475 | dhcp->request_timeout--; |
||
476 | } else if (dhcp->request_timeout == 1) { |
||
477 | dhcp->request_timeout--; |
||
478 | /* { netif->dhcp->request_timeout == 0 } */ |
||
479 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); |
||
480 | /* this client's request timeout triggered */ |
||
481 | dhcp_timeout(netif); |
||
482 | } |
||
483 | } |
||
484 | } |
||
485 | } |
||
486 | |||
487 | /** |
||
488 | * A DHCP negotiation transaction, or ARP request, has timed out. |
||
489 | * |
||
490 | * The timer that was started with the DHCP or ARP request has |
||
491 | * timed out, indicating no response was received in time. |
||
492 | * |
||
493 | * @param netif the netif under DHCP control |
||
494 | */ |
||
495 | static void |
||
496 | dhcp_timeout(struct netif *netif) |
||
497 | { |
||
498 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
499 | |||
500 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); |
||
501 | /* back-off period has passed, or server selection timed out */ |
||
502 | if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) { |
||
503 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); |
||
504 | dhcp_discover(netif); |
||
505 | /* receiving the requested lease timed out */ |
||
506 | } else if (dhcp->state == DHCP_STATE_REQUESTING) { |
||
507 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); |
||
508 | if (dhcp->tries <= 5) { |
||
509 | dhcp_select(netif); |
||
510 | } else { |
||
511 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); |
||
512 | dhcp_release_and_stop(netif); |
||
513 | dhcp_start(netif); |
||
514 | } |
||
515 | #if DHCP_DOES_ARP_CHECK |
||
516 | /* received no ARP reply for the offered address (which is good) */ |
||
517 | } else if (dhcp->state == DHCP_STATE_CHECKING) { |
||
518 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); |
||
519 | if (dhcp->tries <= 1) { |
||
520 | dhcp_check(netif); |
||
521 | /* no ARP replies on the offered address, |
||
522 | looks like the IP address is indeed free */ |
||
523 | } else { |
||
524 | /* bind the interface to the offered address */ |
||
525 | dhcp_bind(netif); |
||
526 | } |
||
527 | #endif /* DHCP_DOES_ARP_CHECK */ |
||
528 | } else if (dhcp->state == DHCP_STATE_REBOOTING) { |
||
529 | if (dhcp->tries < REBOOT_TRIES) { |
||
530 | dhcp_reboot(netif); |
||
531 | } else { |
||
532 | dhcp_discover(netif); |
||
533 | } |
||
534 | } |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * The renewal period has timed out. |
||
539 | * |
||
540 | * @param netif the netif under DHCP control |
||
541 | */ |
||
542 | static void |
||
543 | dhcp_t1_timeout(struct netif *netif) |
||
544 | { |
||
545 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
546 | |||
547 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); |
||
548 | if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || |
||
549 | (dhcp->state == DHCP_STATE_RENEWING)) { |
||
550 | /* just retry to renew - note that the rebind timer (t2) will |
||
551 | * eventually time-out if renew tries fail. */ |
||
552 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, |
||
553 | ("dhcp_t1_timeout(): must renew\n")); |
||
554 | /* This slightly different to RFC2131: DHCPREQUEST will be sent from state |
||
555 | DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ |
||
556 | dhcp_renew(netif); |
||
557 | /* Calculate next timeout */ |
||
558 | if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { |
||
559 | dhcp->t1_renew_time = (u16_t)((dhcp->t2_timeout - dhcp->lease_used) / 2); |
||
560 | } |
||
561 | } |
||
562 | } |
||
563 | |||
564 | /** |
||
565 | * The rebind period has timed out. |
||
566 | * |
||
567 | * @param netif the netif under DHCP control |
||
568 | */ |
||
569 | static void |
||
570 | dhcp_t2_timeout(struct netif *netif) |
||
571 | { |
||
572 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
573 | |||
574 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); |
||
575 | if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || |
||
576 | (dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) { |
||
577 | /* just retry to rebind */ |
||
578 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, |
||
579 | ("dhcp_t2_timeout(): must rebind\n")); |
||
580 | /* This slightly different to RFC2131: DHCPREQUEST will be sent from state |
||
581 | DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */ |
||
582 | dhcp_rebind(netif); |
||
583 | /* Calculate next timeout */ |
||
584 | if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) { |
||
585 | dhcp->t2_rebind_time = (u16_t)((dhcp->t0_timeout - dhcp->lease_used) / 2); |
||
586 | } |
||
587 | } |
||
588 | } |
||
589 | |||
590 | /** |
||
591 | * Handle a DHCP ACK packet |
||
592 | * |
||
593 | * @param netif the netif under DHCP control |
||
594 | */ |
||
595 | static void |
||
596 | dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in) |
||
597 | { |
||
598 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
599 | |||
600 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV |
||
601 | u8_t n; |
||
602 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */ |
||
603 | #if LWIP_DHCP_GET_NTP_SRV |
||
604 | ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; |
||
605 | #endif |
||
606 | |||
607 | /* clear options we might not get from the ACK */ |
||
608 | ip4_addr_set_zero(&dhcp->offered_sn_mask); |
||
609 | ip4_addr_set_zero(&dhcp->offered_gw_addr); |
||
610 | #if LWIP_DHCP_BOOTP_FILE |
||
611 | ip4_addr_set_zero(&dhcp->offered_si_addr); |
||
612 | #endif /* LWIP_DHCP_BOOTP_FILE */ |
||
613 | |||
614 | /* lease time given? */ |
||
615 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { |
||
616 | /* remember offered lease time */ |
||
617 | dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); |
||
618 | } |
||
619 | /* renewal period given? */ |
||
620 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { |
||
621 | /* remember given renewal period */ |
||
622 | dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); |
||
623 | } else { |
||
624 | /* calculate safe periods for renewal */ |
||
625 | dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; |
||
626 | } |
||
627 | |||
628 | /* renewal period given? */ |
||
629 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { |
||
630 | /* remember given rebind period */ |
||
631 | dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); |
||
632 | } else { |
||
633 | /* calculate safe periods for rebinding (offered_t0_lease * 0.875 -> 87.5%)*/ |
||
634 | dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U; |
||
635 | } |
||
636 | |||
637 | /* (y)our internet address */ |
||
638 | ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr); |
||
639 | |||
640 | #if LWIP_DHCP_BOOTP_FILE |
||
641 | /* copy boot server address, |
||
642 | boot file name copied in dhcp_parse_reply if not overloaded */ |
||
643 | ip4_addr_copy(dhcp->offered_si_addr, msg_in->siaddr); |
||
644 | #endif /* LWIP_DHCP_BOOTP_FILE */ |
||
645 | |||
646 | /* subnet mask given? */ |
||
647 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { |
||
648 | /* remember given subnet mask */ |
||
649 | ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); |
||
650 | dhcp->subnet_mask_given = 1; |
||
651 | } else { |
||
652 | dhcp->subnet_mask_given = 0; |
||
653 | } |
||
654 | |||
655 | /* gateway router */ |
||
656 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { |
||
657 | ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); |
||
658 | } |
||
659 | |||
660 | #if LWIP_DHCP_GET_NTP_SRV |
||
661 | /* NTP servers */ |
||
662 | for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) { |
||
663 | ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n))); |
||
664 | } |
||
665 | dhcp_set_ntp_servers(n, ntp_server_addrs); |
||
666 | #endif /* LWIP_DHCP_GET_NTP_SRV */ |
||
667 | |||
668 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS |
||
669 | /* DNS servers */ |
||
670 | for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { |
||
671 | ip_addr_t dns_addr; |
||
672 | ip_addr_set_ip4_u32_val(dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); |
||
673 | dns_setserver(n, &dns_addr); |
||
674 | } |
||
675 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ |
||
676 | } |
||
677 | |||
678 | /** |
||
679 | * @ingroup dhcp4 |
||
680 | * Set a statically allocated struct dhcp to work with. |
||
681 | * Using this prevents dhcp_start to allocate it using mem_malloc. |
||
682 | * |
||
683 | * @param netif the netif for which to set the struct dhcp |
||
684 | * @param dhcp (uninitialised) dhcp struct allocated by the application |
||
685 | */ |
||
686 | void |
||
687 | dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) |
||
688 | { |
||
689 | LWIP_ASSERT("netif != NULL", netif != NULL); |
||
690 | LWIP_ASSERT("dhcp != NULL", dhcp != NULL); |
||
691 | LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL); |
||
692 | |||
693 | /* clear data structure */ |
||
694 | memset(dhcp, 0, sizeof(struct dhcp)); |
||
695 | /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ |
||
696 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); |
||
697 | } |
||
698 | |||
699 | /** |
||
700 | * @ingroup dhcp4 |
||
701 | * Removes a struct dhcp from a netif. |
||
702 | * |
||
703 | * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the |
||
704 | * struct dhcp since the memory is passed back to the heap. |
||
705 | * |
||
706 | * @param netif the netif from which to remove the struct dhcp |
||
707 | */ |
||
708 | void dhcp_cleanup(struct netif *netif) |
||
709 | { |
||
710 | LWIP_ASSERT("netif != NULL", netif != NULL); |
||
711 | |||
712 | if (netif_dhcp_data(netif) != NULL) { |
||
713 | mem_free(netif_dhcp_data(netif)); |
||
714 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL); |
||
715 | } |
||
716 | } |
||
717 | |||
718 | /** |
||
719 | * @ingroup dhcp4 |
||
720 | * Start DHCP negotiation for a network interface. |
||
721 | * |
||
722 | * If no DHCP client instance was attached to this interface, |
||
723 | * a new client is created first. If a DHCP client instance |
||
724 | * was already present, it restarts negotiation. |
||
725 | * |
||
726 | * @param netif The lwIP network interface |
||
727 | * @return lwIP error code |
||
728 | * - ERR_OK - No error |
||
729 | * - ERR_MEM - Out of memory |
||
730 | */ |
||
731 | err_t |
||
732 | dhcp_start(struct netif *netif) |
||
733 | { |
||
734 | struct dhcp *dhcp; |
||
735 | err_t result; |
||
736 | |||
737 | LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); |
||
738 | LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); |
||
739 | dhcp = netif_dhcp_data(netif); |
||
740 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); |
||
741 | |||
742 | /* check MTU of the netif */ |
||
743 | if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { |
||
744 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); |
||
745 | return ERR_MEM; |
||
746 | } |
||
747 | |||
748 | /* no DHCP client attached yet? */ |
||
749 | if (dhcp == NULL) { |
||
750 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new DHCP client\n")); |
||
751 | dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); |
||
752 | if (dhcp == NULL) { |
||
753 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); |
||
754 | return ERR_MEM; |
||
755 | } |
||
756 | |||
757 | /* store this dhcp client in the netif */ |
||
758 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); |
||
759 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); |
||
760 | /* already has DHCP client attached */ |
||
761 | } else { |
||
762 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); |
||
763 | |||
764 | if (dhcp->pcb_allocated != 0) { |
||
765 | dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ |
||
766 | } |
||
767 | /* dhcp is cleared below, no need to reset flag*/ |
||
768 | } |
||
769 | |||
770 | /* clear data structure */ |
||
771 | memset(dhcp, 0, sizeof(struct dhcp)); |
||
772 | /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ |
||
773 | |||
774 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); |
||
775 | |||
776 | if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ |
||
777 | return ERR_MEM; |
||
778 | } |
||
779 | dhcp->pcb_allocated = 1; |
||
780 | |||
781 | #if LWIP_DHCP_CHECK_LINK_UP |
||
782 | if (!netif_is_link_up(netif)) { |
||
783 | /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */ |
||
784 | dhcp_set_state(dhcp, DHCP_STATE_INIT); |
||
785 | return ERR_OK; |
||
786 | } |
||
787 | #endif /* LWIP_DHCP_CHECK_LINK_UP */ |
||
788 | |||
789 | |||
790 | /* (re)start the DHCP negotiation */ |
||
791 | result = dhcp_discover(netif); |
||
792 | if (result != ERR_OK) { |
||
793 | /* free resources allocated above */ |
||
794 | dhcp_release_and_stop(netif); |
||
795 | return ERR_MEM; |
||
796 | } |
||
797 | return result; |
||
798 | } |
||
799 | |||
800 | /** |
||
801 | * @ingroup dhcp4 |
||
802 | * Inform a DHCP server of our manual configuration. |
||
803 | * |
||
804 | * This informs DHCP servers of our fixed IP address configuration |
||
805 | * by sending an INFORM message. It does not involve DHCP address |
||
806 | * configuration, it is just here to be nice to the network. |
||
807 | * |
||
808 | * @param netif The lwIP network interface |
||
809 | */ |
||
810 | void |
||
811 | dhcp_inform(struct netif *netif) |
||
812 | { |
||
813 | struct dhcp dhcp; |
||
814 | struct pbuf *p_out; |
||
815 | u16_t options_out_len; |
||
816 | |||
817 | LWIP_ERROR("netif != NULL", (netif != NULL), return;); |
||
818 | |||
819 | if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ |
||
820 | return; |
||
821 | } |
||
822 | |||
823 | memset(&dhcp, 0, sizeof(struct dhcp)); |
||
824 | dhcp_set_state(&dhcp, DHCP_STATE_INFORMING); |
||
825 | |||
826 | /* create and initialize the DHCP message header */ |
||
827 | p_out = dhcp_create_msg(netif, &dhcp, DHCP_INFORM, &options_out_len); |
||
828 | if (p_out != NULL) { |
||
829 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
830 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
831 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); |
||
832 | |||
833 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, &dhcp, DHCP_STATE_INFORMING, msg_out, DHCP_INFORM, &options_out_len); |
||
834 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
835 | |||
836 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); |
||
837 | |||
838 | udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); |
||
839 | |||
840 | pbuf_free(p_out); |
||
841 | } else { |
||
842 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); |
||
843 | } |
||
844 | |||
845 | dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */ |
||
846 | } |
||
847 | |||
848 | /** Handle a possible change in the network configuration. |
||
849 | * |
||
850 | * This enters the REBOOTING state to verify that the currently bound |
||
851 | * address is still valid. |
||
852 | */ |
||
853 | void |
||
854 | dhcp_network_changed(struct netif *netif) |
||
855 | { |
||
856 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
857 | |||
858 | if (!dhcp) { |
||
859 | return; |
||
860 | } |
||
861 | switch (dhcp->state) { |
||
862 | case DHCP_STATE_REBINDING: |
||
863 | case DHCP_STATE_RENEWING: |
||
864 | case DHCP_STATE_BOUND: |
||
865 | case DHCP_STATE_REBOOTING: |
||
866 | dhcp->tries = 0; |
||
867 | dhcp_reboot(netif); |
||
868 | break; |
||
869 | case DHCP_STATE_OFF: |
||
870 | /* stay off */ |
||
871 | break; |
||
872 | default: |
||
873 | LWIP_ASSERT("invalid dhcp->state", dhcp->state <= DHCP_STATE_BACKING_OFF); |
||
874 | /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the |
||
875 | state changes, SELECTING: continue with current 'rid' as we stay in the |
||
876 | same state */ |
||
877 | #if LWIP_DHCP_AUTOIP_COOP |
||
878 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { |
||
879 | autoip_stop(netif); |
||
880 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; |
||
881 | } |
||
882 | #endif /* LWIP_DHCP_AUTOIP_COOP */ |
||
883 | /* ensure we start with short timeouts, even if already discovering */ |
||
884 | dhcp->tries = 0; |
||
885 | dhcp_discover(netif); |
||
886 | break; |
||
887 | } |
||
888 | } |
||
889 | |||
890 | #if DHCP_DOES_ARP_CHECK |
||
891 | /** |
||
892 | * Match an ARP reply with the offered IP address: |
||
893 | * check whether the offered IP address is not in use using ARP |
||
894 | * |
||
895 | * @param netif the network interface on which the reply was received |
||
896 | * @param addr The IP address we received a reply from |
||
897 | */ |
||
898 | void |
||
899 | dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) |
||
900 | { |
||
901 | struct dhcp *dhcp; |
||
902 | |||
903 | LWIP_ERROR("netif != NULL", (netif != NULL), return;); |
||
904 | dhcp = netif_dhcp_data(netif); |
||
905 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); |
||
906 | /* is a DHCP client doing an ARP check? */ |
||
907 | if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) { |
||
908 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", |
||
909 | ip4_addr_get_u32(addr))); |
||
910 | /* did a host respond with the address we |
||
911 | were offered by the DHCP server? */ |
||
912 | if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) { |
||
913 | /* we will not accept the offered address */ |
||
914 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, |
||
915 | ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); |
||
916 | dhcp_decline(netif); |
||
917 | } |
||
918 | } |
||
919 | } |
||
920 | |||
921 | /** |
||
922 | * Decline an offered lease. |
||
923 | * |
||
924 | * Tell the DHCP server we do not accept the offered address. |
||
925 | * One reason to decline the lease is when we find out the address |
||
926 | * is already in use by another host (through ARP). |
||
927 | * |
||
928 | * @param netif the netif under DHCP control |
||
929 | */ |
||
930 | static err_t |
||
931 | dhcp_decline(struct netif *netif) |
||
932 | { |
||
933 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
934 | err_t result; |
||
935 | u16_t msecs; |
||
936 | struct pbuf *p_out; |
||
937 | u16_t options_out_len; |
||
938 | |||
939 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); |
||
940 | dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); |
||
941 | /* create and initialize the DHCP message header */ |
||
942 | p_out = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len); |
||
943 | if (p_out != NULL) { |
||
944 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
945 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); |
||
946 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); |
||
947 | |||
948 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_BACKING_OFF, msg_out, DHCP_DECLINE, &options_out_len); |
||
949 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
950 | |||
951 | /* per section 4.4.4, broadcast DECLINE messages */ |
||
952 | result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); |
||
953 | pbuf_free(p_out); |
||
954 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); |
||
955 | } else { |
||
956 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
957 | ("dhcp_decline: could not allocate DHCP request\n")); |
||
958 | result = ERR_MEM; |
||
959 | } |
||
960 | if (dhcp->tries < 255) { |
||
961 | dhcp->tries++; |
||
962 | } |
||
963 | msecs = 10 * 1000; |
||
964 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
965 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); |
||
966 | return result; |
||
967 | } |
||
968 | #endif /* DHCP_DOES_ARP_CHECK */ |
||
969 | |||
970 | |||
971 | /** |
||
972 | * Start the DHCP process, discover a DHCP server. |
||
973 | * |
||
974 | * @param netif the netif under DHCP control |
||
975 | */ |
||
976 | static err_t |
||
977 | dhcp_discover(struct netif *netif) |
||
978 | { |
||
979 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
980 | err_t result = ERR_OK; |
||
981 | u16_t msecs; |
||
982 | u8_t i; |
||
983 | struct pbuf *p_out; |
||
984 | u16_t options_out_len; |
||
985 | |||
986 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); |
||
987 | |||
988 | ip4_addr_set_any(&dhcp->offered_ip_addr); |
||
989 | dhcp_set_state(dhcp, DHCP_STATE_SELECTING); |
||
990 | /* create and initialize the DHCP message header */ |
||
991 | p_out = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER, &options_out_len); |
||
992 | if (p_out != NULL) { |
||
993 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
994 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); |
||
995 | |||
996 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
997 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); |
||
998 | |||
999 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); |
||
1000 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { |
||
1001 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); |
||
1002 | } |
||
1003 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_SELECTING, msg_out, DHCP_DISCOVER, &options_out_len); |
||
1004 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
1005 | |||
1006 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n")); |
||
1007 | udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY); |
||
1008 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); |
||
1009 | pbuf_free(p_out); |
||
1010 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); |
||
1011 | } else { |
||
1012 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); |
||
1013 | } |
||
1014 | if (dhcp->tries < 255) { |
||
1015 | dhcp->tries++; |
||
1016 | } |
||
1017 | #if LWIP_DHCP_AUTOIP_COOP |
||
1018 | if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { |
||
1019 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; |
||
1020 | autoip_start(netif); |
||
1021 | } |
||
1022 | #endif /* LWIP_DHCP_AUTOIP_COOP */ |
||
1023 | msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000); |
||
1024 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
1025 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); |
||
1026 | return result; |
||
1027 | } |
||
1028 | |||
1029 | |||
1030 | /** |
||
1031 | * Bind the interface to the offered IP address. |
||
1032 | * |
||
1033 | * @param netif network interface to bind to the offered address |
||
1034 | */ |
||
1035 | static void |
||
1036 | dhcp_bind(struct netif *netif) |
||
1037 | { |
||
1038 | u32_t timeout; |
||
1039 | struct dhcp *dhcp; |
||
1040 | ip4_addr_t sn_mask, gw_addr; |
||
1041 | LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); |
||
1042 | dhcp = netif_dhcp_data(netif); |
||
1043 | LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); |
||
1044 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); |
||
1045 | |||
1046 | /* reset time used of lease */ |
||
1047 | dhcp->lease_used = 0; |
||
1048 | |||
1049 | if (dhcp->offered_t0_lease != 0xffffffffUL) { |
||
1050 | /* set renewal period timer */ |
||
1051 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); |
||
1052 | timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
||
1053 | if (timeout > 0xffff) { |
||
1054 | timeout = 0xffff; |
||
1055 | } |
||
1056 | dhcp->t0_timeout = (u16_t)timeout; |
||
1057 | if (dhcp->t0_timeout == 0) { |
||
1058 | dhcp->t0_timeout = 1; |
||
1059 | } |
||
1060 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000)); |
||
1061 | } |
||
1062 | |||
1063 | /* temporary DHCP lease? */ |
||
1064 | if (dhcp->offered_t1_renew != 0xffffffffUL) { |
||
1065 | /* set renewal period timer */ |
||
1066 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); |
||
1067 | timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
||
1068 | if (timeout > 0xffff) { |
||
1069 | timeout = 0xffff; |
||
1070 | } |
||
1071 | dhcp->t1_timeout = (u16_t)timeout; |
||
1072 | if (dhcp->t1_timeout == 0) { |
||
1073 | dhcp->t1_timeout = 1; |
||
1074 | } |
||
1075 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew * 1000)); |
||
1076 | dhcp->t1_renew_time = dhcp->t1_timeout; |
||
1077 | } |
||
1078 | /* set renewal period timer */ |
||
1079 | if (dhcp->offered_t2_rebind != 0xffffffffUL) { |
||
1080 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); |
||
1081 | timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
||
1082 | if (timeout > 0xffff) { |
||
1083 | timeout = 0xffff; |
||
1084 | } |
||
1085 | dhcp->t2_timeout = (u16_t)timeout; |
||
1086 | if (dhcp->t2_timeout == 0) { |
||
1087 | dhcp->t2_timeout = 1; |
||
1088 | } |
||
1089 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind * 1000)); |
||
1090 | dhcp->t2_rebind_time = dhcp->t2_timeout; |
||
1091 | } |
||
1092 | |||
1093 | /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ |
||
1094 | if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { |
||
1095 | dhcp->t1_timeout = 0; |
||
1096 | } |
||
1097 | |||
1098 | if (dhcp->subnet_mask_given) { |
||
1099 | /* copy offered network mask */ |
||
1100 | ip4_addr_copy(sn_mask, dhcp->offered_sn_mask); |
||
1101 | } else { |
||
1102 | /* subnet mask not given, choose a safe subnet mask given the network class */ |
||
1103 | u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); |
||
1104 | if (first_octet <= 127) { |
||
1105 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); |
||
1106 | } else if (first_octet >= 192) { |
||
1107 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); |
||
1108 | } else { |
||
1109 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); |
||
1110 | } |
||
1111 | } |
||
1112 | |||
1113 | ip4_addr_copy(gw_addr, dhcp->offered_gw_addr); |
||
1114 | /* gateway address not given? */ |
||
1115 | if (ip4_addr_isany_val(gw_addr)) { |
||
1116 | /* copy network address */ |
||
1117 | ip4_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); |
||
1118 | /* use first host address on network as gateway */ |
||
1119 | ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL)); |
||
1120 | } |
||
1121 | |||
1122 | #if LWIP_DHCP_AUTOIP_COOP |
||
1123 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { |
||
1124 | autoip_stop(netif); |
||
1125 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; |
||
1126 | } |
||
1127 | #endif /* LWIP_DHCP_AUTOIP_COOP */ |
||
1128 | |||
1129 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n", |
||
1130 | ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr))); |
||
1131 | /* netif is now bound to DHCP leased address - set this before assigning the address |
||
1132 | to ensure the callback can use dhcp_supplied_address() */ |
||
1133 | dhcp_set_state(dhcp, DHCP_STATE_BOUND); |
||
1134 | |||
1135 | netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr); |
||
1136 | /* interface is used by routing now that an address is set */ |
||
1137 | } |
||
1138 | |||
1139 | /** |
||
1140 | * @ingroup dhcp4 |
||
1141 | * Renew an existing DHCP lease at the involved DHCP server. |
||
1142 | * |
||
1143 | * @param netif network interface which must renew its lease |
||
1144 | */ |
||
1145 | err_t |
||
1146 | dhcp_renew(struct netif *netif) |
||
1147 | { |
||
1148 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1149 | err_t result; |
||
1150 | u16_t msecs; |
||
1151 | u8_t i; |
||
1152 | struct pbuf *p_out; |
||
1153 | u16_t options_out_len; |
||
1154 | |||
1155 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); |
||
1156 | dhcp_set_state(dhcp, DHCP_STATE_RENEWING); |
||
1157 | |||
1158 | /* create and initialize the DHCP message header */ |
||
1159 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); |
||
1160 | if (p_out != NULL) { |
||
1161 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
1162 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
1163 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); |
||
1164 | |||
1165 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); |
||
1166 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { |
||
1167 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); |
||
1168 | } |
||
1169 | |||
1170 | #if LWIP_NETIF_HOSTNAME |
||
1171 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); |
||
1172 | #endif /* LWIP_NETIF_HOSTNAME */ |
||
1173 | |||
1174 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_RENEWING, msg_out, DHCP_REQUEST, &options_out_len); |
||
1175 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
1176 | |||
1177 | result = udp_sendto_if(dhcp_pcb, p_out, &dhcp->server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); |
||
1178 | pbuf_free(p_out); |
||
1179 | |||
1180 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); |
||
1181 | } else { |
||
1182 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); |
||
1183 | result = ERR_MEM; |
||
1184 | } |
||
1185 | if (dhcp->tries < 255) { |
||
1186 | dhcp->tries++; |
||
1187 | } |
||
1188 | /* back-off on retries, but to a maximum of 20 seconds */ |
||
1189 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000); |
||
1190 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
1191 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); |
||
1192 | return result; |
||
1193 | } |
||
1194 | |||
1195 | /** |
||
1196 | * Rebind with a DHCP server for an existing DHCP lease. |
||
1197 | * |
||
1198 | * @param netif network interface which must rebind with a DHCP server |
||
1199 | */ |
||
1200 | static err_t |
||
1201 | dhcp_rebind(struct netif *netif) |
||
1202 | { |
||
1203 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1204 | err_t result; |
||
1205 | u16_t msecs; |
||
1206 | u8_t i; |
||
1207 | struct pbuf *p_out; |
||
1208 | u16_t options_out_len; |
||
1209 | |||
1210 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); |
||
1211 | dhcp_set_state(dhcp, DHCP_STATE_REBINDING); |
||
1212 | |||
1213 | /* create and initialize the DHCP message header */ |
||
1214 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); |
||
1215 | if (p_out != NULL) { |
||
1216 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
1217 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
1218 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif)); |
||
1219 | |||
1220 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); |
||
1221 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { |
||
1222 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); |
||
1223 | } |
||
1224 | |||
1225 | #if LWIP_NETIF_HOSTNAME |
||
1226 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif); |
||
1227 | #endif /* LWIP_NETIF_HOSTNAME */ |
||
1228 | |||
1229 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBINDING, msg_out, DHCP_DISCOVER, &options_out_len); |
||
1230 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
1231 | |||
1232 | /* broadcast to server */ |
||
1233 | result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); |
||
1234 | pbuf_free(p_out); |
||
1235 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); |
||
1236 | } else { |
||
1237 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); |
||
1238 | result = ERR_MEM; |
||
1239 | } |
||
1240 | if (dhcp->tries < 255) { |
||
1241 | dhcp->tries++; |
||
1242 | } |
||
1243 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); |
||
1244 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
1245 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); |
||
1246 | return result; |
||
1247 | } |
||
1248 | |||
1249 | /** |
||
1250 | * Enter REBOOTING state to verify an existing lease |
||
1251 | * |
||
1252 | * @param netif network interface which must reboot |
||
1253 | */ |
||
1254 | static err_t |
||
1255 | dhcp_reboot(struct netif *netif) |
||
1256 | { |
||
1257 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1258 | err_t result; |
||
1259 | u16_t msecs; |
||
1260 | u8_t i; |
||
1261 | struct pbuf *p_out; |
||
1262 | u16_t options_out_len; |
||
1263 | |||
1264 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); |
||
1265 | dhcp_set_state(dhcp, DHCP_STATE_REBOOTING); |
||
1266 | |||
1267 | /* create and initialize the DHCP message header */ |
||
1268 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len); |
||
1269 | if (p_out != NULL) { |
||
1270 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
1271 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
||
1272 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN_MIN_REQUIRED); |
||
1273 | |||
1274 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4); |
||
1275 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); |
||
1276 | |||
1277 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); |
||
1278 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { |
||
1279 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]); |
||
1280 | } |
||
1281 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBOOTING, msg_out, DHCP_REQUEST, &options_out_len); |
||
1282 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
1283 | |||
1284 | /* broadcast to server */ |
||
1285 | result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif); |
||
1286 | pbuf_free(p_out); |
||
1287 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); |
||
1288 | } else { |
||
1289 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); |
||
1290 | result = ERR_MEM; |
||
1291 | } |
||
1292 | if (dhcp->tries < 255) { |
||
1293 | dhcp->tries++; |
||
1294 | } |
||
1295 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000); |
||
1296 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS); |
||
1297 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); |
||
1298 | return result; |
||
1299 | } |
||
1300 | |||
1301 | /** |
||
1302 | * @ingroup dhcp4 |
||
1303 | * Release a DHCP lease and stop DHCP statemachine (and AUTOIP if LWIP_DHCP_AUTOIP_COOP). |
||
1304 | * |
||
1305 | * @param netif network interface |
||
1306 | */ |
||
1307 | void |
||
1308 | dhcp_release_and_stop(struct netif *netif) |
||
1309 | { |
||
1310 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1311 | ip_addr_t server_ip_addr; |
||
1312 | |||
1313 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release_and_stop()\n")); |
||
1314 | if (dhcp == NULL) { |
||
1315 | return; |
||
1316 | } |
||
1317 | |||
1318 | /* already off? -> nothing to do */ |
||
1319 | if (dhcp->state == DHCP_STATE_OFF) { |
||
1320 | return; |
||
1321 | } |
||
1322 | |||
1323 | ip_addr_copy(server_ip_addr, dhcp->server_ip_addr); |
||
1324 | |||
1325 | /* clean old DHCP offer */ |
||
1326 | ip_addr_set_zero_ip4(&dhcp->server_ip_addr); |
||
1327 | ip4_addr_set_zero(&dhcp->offered_ip_addr); |
||
1328 | ip4_addr_set_zero(&dhcp->offered_sn_mask); |
||
1329 | ip4_addr_set_zero(&dhcp->offered_gw_addr); |
||
1330 | #if LWIP_DHCP_BOOTP_FILE |
||
1331 | ip4_addr_set_zero(&dhcp->offered_si_addr); |
||
1332 | #endif /* LWIP_DHCP_BOOTP_FILE */ |
||
1333 | dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; |
||
1334 | dhcp->t1_renew_time = dhcp->t2_rebind_time = dhcp->lease_used = dhcp->t0_timeout = 0; |
||
1335 | |||
1336 | /* send release message when current IP was assigned via DHCP */ |
||
1337 | if (dhcp_supplied_address(netif)) { |
||
1338 | /* create and initialize the DHCP message header */ |
||
1339 | struct pbuf *p_out; |
||
1340 | u16_t options_out_len; |
||
1341 | p_out = dhcp_create_msg(netif, dhcp, DHCP_RELEASE, &options_out_len); |
||
1342 | if (p_out != NULL) { |
||
1343 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload; |
||
1344 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4); |
||
1345 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr)))); |
||
1346 | |||
1347 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, dhcp->state, msg_out, DHCP_RELEASE, &options_out_len); |
||
1348 | dhcp_option_trailer(options_out_len, msg_out->options, p_out); |
||
1349 | |||
1350 | udp_sendto_if(dhcp_pcb, p_out, &server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif); |
||
1351 | pbuf_free(p_out); |
||
1352 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n")); |
||
1353 | } else { |
||
1354 | /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */ |
||
1355 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); |
||
1356 | } |
||
1357 | } |
||
1358 | |||
1359 | /* remove IP address from interface (prevents routing from selecting this interface) */ |
||
1360 | netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); |
||
1361 | |||
1362 | #if LWIP_DHCP_AUTOIP_COOP |
||
1363 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { |
||
1364 | autoip_stop(netif); |
||
1365 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; |
||
1366 | } |
||
1367 | #endif /* LWIP_DHCP_AUTOIP_COOP */ |
||
1368 | |||
1369 | dhcp_set_state(dhcp, DHCP_STATE_OFF); |
||
1370 | |||
1371 | if (dhcp->pcb_allocated != 0) { |
||
1372 | dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ |
||
1373 | dhcp->pcb_allocated = 0; |
||
1374 | } |
||
1375 | } |
||
1376 | |||
1377 | /** |
||
1378 | * @ingroup dhcp4 |
||
1379 | * This function calls dhcp_release_and_stop() internally. |
||
1380 | * @deprecated Use dhcp_release_and_stop() instead. |
||
1381 | */ |
||
1382 | err_t |
||
1383 | dhcp_release(struct netif *netif) |
||
1384 | { |
||
1385 | dhcp_release_and_stop(netif); |
||
1386 | return ERR_OK; |
||
1387 | } |
||
1388 | |||
1389 | /** |
||
1390 | * @ingroup dhcp4 |
||
1391 | * This function calls dhcp_release_and_stop() internally. |
||
1392 | * @deprecated Use dhcp_release_and_stop() instead. |
||
1393 | */ |
||
1394 | void |
||
1395 | dhcp_stop(struct netif *netif) |
||
1396 | { |
||
1397 | dhcp_release_and_stop(netif); |
||
1398 | } |
||
1399 | |||
1400 | /* |
||
1401 | * Set the DHCP state of a DHCP client. |
||
1402 | * |
||
1403 | * If the state changed, reset the number of tries. |
||
1404 | */ |
||
1405 | static void |
||
1406 | dhcp_set_state(struct dhcp *dhcp, u8_t new_state) |
||
1407 | { |
||
1408 | if (new_state != dhcp->state) { |
||
1409 | dhcp->state = new_state; |
||
1410 | dhcp->tries = 0; |
||
1411 | dhcp->request_timeout = 0; |
||
1412 | } |
||
1413 | } |
||
1414 | |||
1415 | /* |
||
1416 | * Concatenate an option type and length field to the outgoing |
||
1417 | * DHCP message. |
||
1418 | * |
||
1419 | */ |
||
1420 | static u16_t |
||
1421 | dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len) |
||
1422 | { |
||
1423 | LWIP_ASSERT("dhcp_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); |
||
1424 | options[options_out_len++] = option_type; |
||
1425 | options[options_out_len++] = option_len; |
||
1426 | return options_out_len; |
||
1427 | } |
||
1428 | /* |
||
1429 | * Concatenate a single byte to the outgoing DHCP message. |
||
1430 | * |
||
1431 | */ |
||
1432 | static u16_t |
||
1433 | dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value) |
||
1434 | { |
||
1435 | LWIP_ASSERT("dhcp_option_byte: options_out_len < DHCP_OPTIONS_LEN", options_out_len < DHCP_OPTIONS_LEN); |
||
1436 | options[options_out_len++] = value; |
||
1437 | return options_out_len; |
||
1438 | } |
||
1439 | |||
1440 | static u16_t |
||
1441 | dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value) |
||
1442 | { |
||
1443 | LWIP_ASSERT("dhcp_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN", options_out_len + 2U <= DHCP_OPTIONS_LEN); |
||
1444 | options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8); |
||
1445 | options[options_out_len++] = (u8_t) (value & 0x00ffU); |
||
1446 | return options_out_len; |
||
1447 | } |
||
1448 | |||
1449 | static u16_t |
||
1450 | dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value) |
||
1451 | { |
||
1452 | LWIP_ASSERT("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN", options_out_len + 4U <= DHCP_OPTIONS_LEN); |
||
1453 | options[options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); |
||
1454 | options[options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); |
||
1455 | options[options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); |
||
1456 | options[options_out_len++] = (u8_t)((value & 0x000000ffUL)); |
||
1457 | return options_out_len; |
||
1458 | } |
||
1459 | |||
1460 | #if LWIP_NETIF_HOSTNAME |
||
1461 | static u16_t |
||
1462 | dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif) |
||
1463 | { |
||
1464 | if (netif->hostname != NULL) { |
||
1465 | size_t namelen = strlen(netif->hostname); |
||
1466 | if (namelen > 0) { |
||
1467 | size_t len; |
||
1468 | const char *p = netif->hostname; |
||
1469 | /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME |
||
1470 | and 1 byte for trailer) */ |
||
1471 | size_t available = DHCP_OPTIONS_LEN - options_out_len - 3; |
||
1472 | LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); |
||
1473 | len = LWIP_MIN(namelen, available); |
||
1474 | LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF); |
||
1475 | options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_HOSTNAME, (u8_t)len); |
||
1476 | while (len--) { |
||
1477 | options_out_len = dhcp_option_byte(options_out_len, options, *p++); |
||
1478 | } |
||
1479 | } |
||
1480 | } |
||
1481 | return options_out_len; |
||
1482 | } |
||
1483 | #endif /* LWIP_NETIF_HOSTNAME */ |
||
1484 | |||
1485 | /** |
||
1486 | * Extract the DHCP message and the DHCP options. |
||
1487 | * |
||
1488 | * Extract the DHCP message and the DHCP options, each into a contiguous |
||
1489 | * piece of memory. As a DHCP message is variable sized by its options, |
||
1490 | * and also allows overriding some fields for options, the easy approach |
||
1491 | * is to first unfold the options into a contiguous piece of memory, and |
||
1492 | * use that further on. |
||
1493 | * |
||
1494 | */ |
||
1495 | static err_t |
||
1496 | dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp) |
||
1497 | { |
||
1498 | u8_t *options; |
||
1499 | u16_t offset; |
||
1500 | u16_t offset_max; |
||
1501 | u16_t options_idx; |
||
1502 | u16_t options_idx_max; |
||
1503 | struct pbuf *q; |
||
1504 | int parse_file_as_options = 0; |
||
1505 | int parse_sname_as_options = 0; |
||
1506 | struct dhcp_msg *msg_in; |
||
1507 | |||
1508 | LWIP_UNUSED_ARG(dhcp); |
||
1509 | |||
1510 | /* clear received options */ |
||
1511 | dhcp_clear_all_options(dhcp); |
||
1512 | /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ |
||
1513 | if (p->len < DHCP_SNAME_OFS) { |
||
1514 | return ERR_BUF; |
||
1515 | } |
||
1516 | msg_in = (struct dhcp_msg *)p->payload; |
||
1517 | #if LWIP_DHCP_BOOTP_FILE |
||
1518 | /* clear boot file name */ |
||
1519 | dhcp->boot_file_name[0] = 0; |
||
1520 | #endif /* LWIP_DHCP_BOOTP_FILE */ |
||
1521 | |||
1522 | /* parse options */ |
||
1523 | |||
1524 | /* start with options field */ |
||
1525 | options_idx = DHCP_OPTIONS_OFS; |
||
1526 | /* parse options to the end of the received packet */ |
||
1527 | options_idx_max = p->tot_len; |
||
1528 | again: |
||
1529 | q = p; |
||
1530 | while ((q != NULL) && (options_idx >= q->len)) { |
||
1531 | options_idx = (u16_t)(options_idx - q->len); |
||
1532 | options_idx_max = (u16_t)(options_idx_max - q->len); |
||
1533 | q = q->next; |
||
1534 | } |
||
1535 | if (q == NULL) { |
||
1536 | return ERR_BUF; |
||
1537 | } |
||
1538 | offset = options_idx; |
||
1539 | offset_max = options_idx_max; |
||
1540 | options = (u8_t *)q->payload; |
||
1541 | /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ |
||
1542 | while ((q != NULL) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) { |
||
1543 | u8_t op = options[offset]; |
||
1544 | u8_t len; |
||
1545 | u8_t decode_len = 0; |
||
1546 | int decode_idx = -1; |
||
1547 | u16_t val_offset = (u16_t)(offset + 2); |
||
1548 | if (val_offset < offset) { |
||
1549 | /* overflow */ |
||
1550 | return ERR_BUF; |
||
1551 | } |
||
1552 | /* len byte might be in the next pbuf */ |
||
1553 | if ((offset + 1) < q->len) { |
||
1554 | len = options[offset + 1]; |
||
1555 | } else { |
||
1556 | len = (q->next != NULL ? ((u8_t *)q->next->payload)[0] : 0); |
||
1557 | } |
||
1558 | /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ |
||
1559 | decode_len = len; |
||
1560 | switch (op) { |
||
1561 | /* case(DHCP_OPTION_END): handled above */ |
||
1562 | case (DHCP_OPTION_PAD): |
||
1563 | /* special option: no len encoded */ |
||
1564 | decode_len = len = 0; |
||
1565 | /* will be increased below */ |
||
1566 | offset--; |
||
1567 | break; |
||
1568 | case (DHCP_OPTION_SUBNET_MASK): |
||
1569 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); |
||
1570 | decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; |
||
1571 | break; |
||
1572 | case (DHCP_OPTION_ROUTER): |
||
1573 | decode_len = 4; /* only copy the first given router */ |
||
1574 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); |
||
1575 | decode_idx = DHCP_OPTION_IDX_ROUTER; |
||
1576 | break; |
||
1577 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS |
||
1578 | case (DHCP_OPTION_DNS_SERVER): |
||
1579 | /* special case: there might be more than one server */ |
||
1580 | LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); |
||
1581 | /* limit number of DNS servers */ |
||
1582 | decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); |
||
1583 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); |
||
1584 | decode_idx = DHCP_OPTION_IDX_DNS_SERVER; |
||
1585 | break; |
||
1586 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ |
||
1587 | case (DHCP_OPTION_LEASE_TIME): |
||
1588 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); |
||
1589 | decode_idx = DHCP_OPTION_IDX_LEASE_TIME; |
||
1590 | break; |
||
1591 | #if LWIP_DHCP_GET_NTP_SRV |
||
1592 | case (DHCP_OPTION_NTP): |
||
1593 | /* special case: there might be more than one server */ |
||
1594 | LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); |
||
1595 | /* limit number of NTP servers */ |
||
1596 | decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS); |
||
1597 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); |
||
1598 | decode_idx = DHCP_OPTION_IDX_NTP_SERVER; |
||
1599 | break; |
||
1600 | #endif /* LWIP_DHCP_GET_NTP_SRV*/ |
||
1601 | case (DHCP_OPTION_OVERLOAD): |
||
1602 | LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); |
||
1603 | /* decode overload only in options, not in file/sname: invalid packet */ |
||
1604 | LWIP_ERROR("overload in file/sname", options_idx == DHCP_OPTIONS_OFS, return ERR_VAL;); |
||
1605 | decode_idx = DHCP_OPTION_IDX_OVERLOAD; |
||
1606 | break; |
||
1607 | case (DHCP_OPTION_MESSAGE_TYPE): |
||
1608 | LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); |
||
1609 | decode_idx = DHCP_OPTION_IDX_MSG_TYPE; |
||
1610 | break; |
||
1611 | case (DHCP_OPTION_SERVER_ID): |
||
1612 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); |
||
1613 | decode_idx = DHCP_OPTION_IDX_SERVER_ID; |
||
1614 | break; |
||
1615 | case (DHCP_OPTION_T1): |
||
1616 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); |
||
1617 | decode_idx = DHCP_OPTION_IDX_T1; |
||
1618 | break; |
||
1619 | case (DHCP_OPTION_T2): |
||
1620 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); |
||
1621 | decode_idx = DHCP_OPTION_IDX_T2; |
||
1622 | break; |
||
1623 | default: |
||
1624 | decode_len = 0; |
||
1625 | LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); |
||
1626 | LWIP_HOOK_DHCP_PARSE_OPTION(ip_current_netif(), dhcp, dhcp->state, msg_in, |
||
1627 | dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) ? (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) : 0, |
||
1628 | op, len, q, val_offset); |
||
1629 | break; |
||
1630 | } |
||
1631 | if (offset + len + 2 > 0xFFFF) { |
||
1632 | /* overflow */ |
||
1633 | return ERR_BUF; |
||
1634 | } |
||
1635 | offset = (u16_t)(offset + len + 2); |
||
1636 | if (decode_len > 0) { |
||
1637 | u32_t value = 0; |
||
1638 | u16_t copy_len; |
||
1639 | decode_next: |
||
1640 | LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); |
||
1641 | if (!dhcp_option_given(dhcp, decode_idx)) { |
||
1642 | copy_len = LWIP_MIN(decode_len, 4); |
||
1643 | if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) { |
||
1644 | return ERR_BUF; |
||
1645 | } |
||
1646 | if (decode_len > 4) { |
||
1647 | /* decode more than one u32_t */ |
||
1648 | u16_t next_val_offset; |
||
1649 | LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); |
||
1650 | dhcp_got_option(dhcp, decode_idx); |
||
1651 | dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); |
||
1652 | decode_len = (u8_t)(decode_len - 4); |
||
1653 | next_val_offset = (u16_t)(val_offset + 4); |
||
1654 | if (next_val_offset < val_offset) { |
||
1655 | /* overflow */ |
||
1656 | return ERR_BUF; |
||
1657 | } |
||
1658 | val_offset = next_val_offset; |
||
1659 | decode_idx++; |
||
1660 | goto decode_next; |
||
1661 | } else if (decode_len == 4) { |
||
1662 | value = lwip_ntohl(value); |
||
1663 | } else { |
||
1664 | LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); |
||
1665 | value = ((u8_t *)&value)[0]; |
||
1666 | } |
||
1667 | dhcp_got_option(dhcp, decode_idx); |
||
1668 | dhcp_set_option_value(dhcp, decode_idx, value); |
||
1669 | } |
||
1670 | } |
||
1671 | if (offset >= q->len) { |
||
1672 | offset = (u16_t)(offset - q->len); |
||
1673 | offset_max = (u16_t)(offset_max - q->len); |
||
1674 | if ((offset < offset_max) && offset_max) { |
||
1675 | q = q->next; |
||
1676 | LWIP_ERROR("next pbuf was null", q != NULL, return ERR_VAL;); |
||
1677 | options = (u8_t *)q->payload; |
||
1678 | } else { |
||
1679 | /* We've run out of bytes, probably no end marker. Don't proceed. */ |
||
1680 | break; |
||
1681 | } |
||
1682 | } |
||
1683 | } |
||
1684 | /* is this an overloaded message? */ |
||
1685 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { |
||
1686 | u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); |
||
1687 | dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); |
||
1688 | if (overload == DHCP_OVERLOAD_FILE) { |
||
1689 | parse_file_as_options = 1; |
||
1690 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); |
||
1691 | } else if (overload == DHCP_OVERLOAD_SNAME) { |
||
1692 | parse_sname_as_options = 1; |
||
1693 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); |
||
1694 | } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { |
||
1695 | parse_sname_as_options = 1; |
||
1696 | parse_file_as_options = 1; |
||
1697 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); |
||
1698 | } else { |
||
1699 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); |
||
1700 | } |
||
1701 | #if LWIP_DHCP_BOOTP_FILE |
||
1702 | if (!parse_file_as_options) { |
||
1703 | /* only do this for ACK messages */ |
||
1704 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && |
||
1705 | (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) |
||
1706 | /* copy bootp file name, don't care for sname (server hostname) */ |
||
1707 | if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN - 1, DHCP_FILE_OFS) != (DHCP_FILE_LEN - 1)) { |
||
1708 | return ERR_BUF; |
||
1709 | } |
||
1710 | /* make sure the string is really NULL-terminated */ |
||
1711 | dhcp->boot_file_name[DHCP_FILE_LEN - 1] = 0; |
||
1712 | } |
||
1713 | #endif /* LWIP_DHCP_BOOTP_FILE */ |
||
1714 | } |
||
1715 | if (parse_file_as_options) { |
||
1716 | /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ |
||
1717 | parse_file_as_options = 0; |
||
1718 | options_idx = DHCP_FILE_OFS; |
||
1719 | options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; |
||
1720 | goto again; |
||
1721 | } else if (parse_sname_as_options) { |
||
1722 | parse_sname_as_options = 0; |
||
1723 | options_idx = DHCP_SNAME_OFS; |
||
1724 | options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; |
||
1725 | goto again; |
||
1726 | } |
||
1727 | return ERR_OK; |
||
1728 | } |
||
1729 | |||
1730 | /** |
||
1731 | * If an incoming DHCP message is in response to us, then trigger the state machine |
||
1732 | */ |
||
1733 | static void |
||
1734 | dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) |
||
1735 | { |
||
1736 | struct netif *netif = ip_current_input_netif(); |
||
1737 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1738 | struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; |
||
1739 | u8_t msg_type; |
||
1740 | u8_t i; |
||
1741 | struct dhcp_msg *msg_in; |
||
1742 | |||
1743 | LWIP_UNUSED_ARG(arg); |
||
1744 | |||
1745 | /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */ |
||
1746 | if ((dhcp == NULL) || (dhcp->pcb_allocated == 0)) { |
||
1747 | goto free_pbuf_and_return; |
||
1748 | } |
||
1749 | |||
1750 | LWIP_ASSERT("invalid server address type", IP_IS_V4(addr)); |
||
1751 | |||
1752 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void *)p, |
||
1753 | ip4_addr1_16(ip_2_ip4(addr)), ip4_addr2_16(ip_2_ip4(addr)), ip4_addr3_16(ip_2_ip4(addr)), ip4_addr4_16(ip_2_ip4(addr)), port)); |
||
1754 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); |
||
1755 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); |
||
1756 | /* prevent warnings about unused arguments */ |
||
1757 | LWIP_UNUSED_ARG(pcb); |
||
1758 | LWIP_UNUSED_ARG(addr); |
||
1759 | LWIP_UNUSED_ARG(port); |
||
1760 | |||
1761 | if (p->len < DHCP_MIN_REPLY_LEN) { |
||
1762 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); |
||
1763 | goto free_pbuf_and_return; |
||
1764 | } |
||
1765 | |||
1766 | if (reply_msg->op != DHCP_BOOTREPLY) { |
||
1767 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); |
||
1768 | goto free_pbuf_and_return; |
||
1769 | } |
||
1770 | /* iterate through hardware address and match against DHCP message */ |
||
1771 | for (i = 0; i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN && i < DHCP_CHADDR_LEN; i++) { |
||
1772 | if (netif->hwaddr[i] != reply_msg->chaddr[i]) { |
||
1773 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
1774 | ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", |
||
1775 | (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); |
||
1776 | goto free_pbuf_and_return; |
||
1777 | } |
||
1778 | } |
||
1779 | /* match transaction ID against what we expected */ |
||
1780 | if (lwip_ntohl(reply_msg->xid) != dhcp->xid) { |
||
1781 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
1782 | ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n", lwip_ntohl(reply_msg->xid), dhcp->xid)); |
||
1783 | goto free_pbuf_and_return; |
||
1784 | } |
||
1785 | /* option fields could be unfold? */ |
||
1786 | if (dhcp_parse_reply(p, dhcp) != ERR_OK) { |
||
1787 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
1788 | ("problem unfolding DHCP message - too short on memory?\n")); |
||
1789 | goto free_pbuf_and_return; |
||
1790 | } |
||
1791 | |||
1792 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); |
||
1793 | /* obtain pointer to DHCP message type */ |
||
1794 | if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { |
||
1795 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); |
||
1796 | goto free_pbuf_and_return; |
||
1797 | } |
||
1798 | |||
1799 | msg_in = (struct dhcp_msg *)p->payload; |
||
1800 | /* read DHCP message type */ |
||
1801 | msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); |
||
1802 | /* message type is DHCP ACK? */ |
||
1803 | if (msg_type == DHCP_ACK) { |
||
1804 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); |
||
1805 | /* in requesting state? */ |
||
1806 | if (dhcp->state == DHCP_STATE_REQUESTING) { |
||
1807 | dhcp_handle_ack(netif, msg_in); |
||
1808 | #if DHCP_DOES_ARP_CHECK |
||
1809 | if ((netif->flags & NETIF_FLAG_ETHARP) != 0) { |
||
1810 | /* check if the acknowledged lease address is already in use */ |
||
1811 | dhcp_check(netif); |
||
1812 | } else { |
||
1813 | /* bind interface to the acknowledged lease address */ |
||
1814 | dhcp_bind(netif); |
||
1815 | } |
||
1816 | #else |
||
1817 | /* bind interface to the acknowledged lease address */ |
||
1818 | dhcp_bind(netif); |
||
1819 | #endif |
||
1820 | } |
||
1821 | /* already bound to the given lease address? */ |
||
1822 | else if ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) || |
||
1823 | (dhcp->state == DHCP_STATE_RENEWING)) { |
||
1824 | dhcp_handle_ack(netif, msg_in); |
||
1825 | dhcp_bind(netif); |
||
1826 | } |
||
1827 | } |
||
1828 | /* received a DHCP_NAK in appropriate state? */ |
||
1829 | else if ((msg_type == DHCP_NAK) && |
||
1830 | ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REQUESTING) || |
||
1831 | (dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING ))) { |
||
1832 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); |
||
1833 | dhcp_handle_nak(netif); |
||
1834 | } |
||
1835 | /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */ |
||
1836 | else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_STATE_SELECTING)) { |
||
1837 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n")); |
||
1838 | dhcp->request_timeout = 0; |
||
1839 | /* remember offered lease */ |
||
1840 | dhcp_handle_offer(netif, msg_in); |
||
1841 | } |
||
1842 | |||
1843 | free_pbuf_and_return: |
||
1844 | pbuf_free(p); |
||
1845 | } |
||
1846 | |||
1847 | /** |
||
1848 | * Create a DHCP request, fill in common headers |
||
1849 | * |
||
1850 | * @param netif the netif under DHCP control |
||
1851 | * @param dhcp dhcp control struct |
||
1852 | * @param message_type message type of the request |
||
1853 | */ |
||
1854 | static struct pbuf * |
||
1855 | dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len) |
||
1856 | { |
||
1857 | u16_t i; |
||
1858 | struct pbuf *p_out; |
||
1859 | struct dhcp_msg *msg_out; |
||
1860 | u16_t options_out_len_loc; |
||
1861 | |||
1862 | #ifndef DHCP_GLOBAL_XID |
||
1863 | /** default global transaction identifier starting value (easy to match |
||
1864 | * with a packet analyser). We simply increment for each new request. |
||
1865 | * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one |
||
1866 | * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ |
||
1867 | #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) |
||
1868 | static u32_t xid; |
||
1869 | #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ |
||
1870 | static u32_t xid = 0xABCD0000; |
||
1871 | #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ |
||
1872 | #else |
||
1873 | if (!xid_initialised) { |
||
1874 | xid = DHCP_GLOBAL_XID; |
||
1875 | xid_initialised = !xid_initialised; |
||
1876 | } |
||
1877 | #endif |
||
1878 | LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return NULL;); |
||
1879 | LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return NULL;); |
||
1880 | p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); |
||
1881 | if (p_out == NULL) { |
||
1882 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
1883 | ("dhcp_create_msg(): could not allocate pbuf\n")); |
||
1884 | return NULL; |
||
1885 | } |
||
1886 | LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", |
||
1887 | (p_out->len >= sizeof(struct dhcp_msg))); |
||
1888 | |||
1889 | /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ |
||
1890 | if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) { |
||
1891 | /* reuse transaction identifier in retransmissions */ |
||
1892 | if (dhcp->tries == 0) { |
||
1893 | #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) |
||
1894 | xid = LWIP_RAND(); |
||
1895 | #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ |
||
1896 | xid++; |
||
1897 | #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ |
||
1898 | } |
||
1899 | dhcp->xid = xid; |
||
1900 | } |
||
1901 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, |
||
1902 | ("transaction id xid(%"X32_F")\n", xid)); |
||
1903 | |||
1904 | msg_out = (struct dhcp_msg *)p_out->payload; |
||
1905 | memset(msg_out, 0, sizeof(struct dhcp_msg)); |
||
1906 | |||
1907 | msg_out->op = DHCP_BOOTREQUEST; |
||
1908 | /* @todo: make link layer independent */ |
||
1909 | msg_out->htype = LWIP_IANA_HWTYPE_ETHERNET; |
||
1910 | msg_out->hlen = netif->hwaddr_len; |
||
1911 | msg_out->xid = lwip_htonl(dhcp->xid); |
||
1912 | /* we don't need the broadcast flag since we can receive unicast traffic |
||
1913 | before being fully configured! */ |
||
1914 | /* set ciaddr to netif->ip_addr based on message_type and state */ |
||
1915 | if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_RELEASE) || |
||
1916 | ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */ |
||
1917 | ((dhcp->state == DHCP_STATE_RENEWING) || dhcp->state == DHCP_STATE_REBINDING))) { |
||
1918 | ip4_addr_copy(msg_out->ciaddr, *netif_ip4_addr(netif)); |
||
1919 | } |
||
1920 | for (i = 0; i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) { |
||
1921 | /* copy netif hardware address (padded with zeroes through memset already) */ |
||
1922 | msg_out->chaddr[i] = netif->hwaddr[i]; |
||
1923 | } |
||
1924 | msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); |
||
1925 | /* Add option MESSAGE_TYPE */ |
||
1926 | options_out_len_loc = dhcp_option(0, msg_out->options, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
||
1927 | options_out_len_loc = dhcp_option_byte(options_out_len_loc, msg_out->options, message_type); |
||
1928 | if (options_out_len) { |
||
1929 | *options_out_len = options_out_len_loc; |
||
1930 | } |
||
1931 | return p_out; |
||
1932 | } |
||
1933 | |||
1934 | /** |
||
1935 | * Add a DHCP message trailer |
||
1936 | * |
||
1937 | * Adds the END option to the DHCP message, and if |
||
1938 | * necessary, up to three padding bytes. |
||
1939 | */ |
||
1940 | static void |
||
1941 | dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out) |
||
1942 | { |
||
1943 | options[options_out_len++] = DHCP_OPTION_END; |
||
1944 | /* packet is too small, or not 4 byte aligned? */ |
||
1945 | while (((options_out_len < DHCP_MIN_OPTIONS_LEN) || (options_out_len & 3)) && |
||
1946 | (options_out_len < DHCP_OPTIONS_LEN)) { |
||
1947 | /* add a fill/padding byte */ |
||
1948 | options[options_out_len++] = 0; |
||
1949 | } |
||
1950 | /* shrink the pbuf to the actual content length */ |
||
1951 | pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + options_out_len)); |
||
1952 | } |
||
1953 | |||
1954 | /** check if DHCP supplied netif->ip_addr |
||
1955 | * |
||
1956 | * @param netif the netif to check |
||
1957 | * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING), |
||
1958 | * 0 otherwise |
||
1959 | */ |
||
1960 | u8_t |
||
1961 | dhcp_supplied_address(const struct netif *netif) |
||
1962 | { |
||
1963 | if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) { |
||
1964 | struct dhcp *dhcp = netif_dhcp_data(netif); |
||
1965 | return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING) || |
||
1966 | (dhcp->state == DHCP_STATE_REBINDING); |
||
1967 | } |
||
1968 | return 0; |
||
1969 | } |
||
1970 | |||
1971 | #endif /* LWIP_IPV4 && LWIP_DHCP */ |