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 | dhcp->request_timeout = 0; /* stop timer */
|
---|
341 |
|
---|
342 | ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
|
---|
343 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
|
---|
344 | ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
|
---|
345 | /* remember offered address */
|
---|
346 | ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr);
|
---|
347 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n",
|
---|
348 | ip4_addr_get_u32(&dhcp->offered_ip_addr)));
|
---|
349 |
|
---|
350 | dhcp_select(netif);
|
---|
351 | } else {
|
---|
352 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
---|
353 | ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void *)netif));
|
---|
354 | }
|
---|
355 | }
|
---|
356 |
|
---|
357 | /**
|
---|
358 | * Select a DHCP server offer out of all offers.
|
---|
359 | *
|
---|
360 | * Simply select the first offer received.
|
---|
361 | *
|
---|
362 | * @param netif the netif under DHCP control
|
---|
363 | * @return lwIP specific error (see error.h)
|
---|
364 | */
|
---|
365 | static err_t
|
---|
366 | dhcp_select(struct netif *netif)
|
---|
367 | {
|
---|
368 | struct dhcp *dhcp;
|
---|
369 | err_t result;
|
---|
370 | u16_t msecs;
|
---|
371 | u8_t i;
|
---|
372 | struct pbuf *p_out;
|
---|
373 | u16_t options_out_len;
|
---|
374 |
|
---|
375 | LWIP_ERROR("dhcp_select: netif != NULL", (netif != NULL), return ERR_ARG;);
|
---|
376 | dhcp = netif_dhcp_data(netif);
|
---|
377 | LWIP_ERROR("dhcp_select: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
|
---|
378 |
|
---|
379 | 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));
|
---|
380 | dhcp_set_state(dhcp, DHCP_STATE_REQUESTING);
|
---|
381 |
|
---|
382 | /* create and initialize the DHCP message header */
|
---|
383 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
|
---|
384 | if (p_out != NULL) {
|
---|
385 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
386 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
387 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif));
|
---|
388 |
|
---|
389 | /* MUST request the offered IP address */
|
---|
390 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4);
|
---|
391 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
|
---|
392 |
|
---|
393 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4);
|
---|
394 | 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))));
|
---|
395 |
|
---|
396 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
|
---|
397 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
|
---|
398 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]);
|
---|
399 | }
|
---|
400 |
|
---|
401 | #if LWIP_NETIF_HOSTNAME
|
---|
402 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif);
|
---|
403 | #endif /* LWIP_NETIF_HOSTNAME */
|
---|
404 |
|
---|
405 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REQUESTING, msg_out, DHCP_REQUEST, &options_out_len);
|
---|
406 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
407 |
|
---|
408 | /* send broadcast to any DHCP server */
|
---|
409 | result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
|
---|
410 | pbuf_free(p_out);
|
---|
411 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
|
---|
412 | } else {
|
---|
413 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
|
---|
414 | result = ERR_MEM;
|
---|
415 | }
|
---|
416 | if (dhcp->tries < 255) {
|
---|
417 | dhcp->tries++;
|
---|
418 | }
|
---|
419 | msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000);
|
---|
420 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
421 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
422 | return result;
|
---|
423 | }
|
---|
424 |
|
---|
425 | /**
|
---|
426 | * The DHCP timer that checks for lease renewal/rebind timeouts.
|
---|
427 | * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS).
|
---|
428 | */
|
---|
429 | void
|
---|
430 | dhcp_coarse_tmr(void)
|
---|
431 | {
|
---|
432 | struct netif *netif;
|
---|
433 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
|
---|
434 | /* iterate through all network interfaces */
|
---|
435 | NETIF_FOREACH(netif) {
|
---|
436 | /* only act on DHCP configured interfaces */
|
---|
437 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
438 | if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) {
|
---|
439 | /* compare lease time to expire timeout */
|
---|
440 | if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) {
|
---|
441 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n"));
|
---|
442 | /* this clients' lease time has expired */
|
---|
443 | dhcp_release_and_stop(netif);
|
---|
444 | dhcp_start(netif);
|
---|
445 | /* timer is active (non zero), and triggers (zeroes) now? */
|
---|
446 | } else if (dhcp->t2_rebind_time && (dhcp->t2_rebind_time-- == 1)) {
|
---|
447 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
|
---|
448 | /* this clients' rebind timeout triggered */
|
---|
449 | dhcp_t2_timeout(netif);
|
---|
450 | /* timer is active (non zero), and triggers (zeroes) now */
|
---|
451 | } else if (dhcp->t1_renew_time && (dhcp->t1_renew_time-- == 1)) {
|
---|
452 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
|
---|
453 | /* this clients' renewal timeout triggered */
|
---|
454 | dhcp_t1_timeout(netif);
|
---|
455 | }
|
---|
456 | }
|
---|
457 | }
|
---|
458 | }
|
---|
459 |
|
---|
460 | /**
|
---|
461 | * DHCP transaction timeout handling (this function must be called every 500ms,
|
---|
462 | * see @ref DHCP_FINE_TIMER_MSECS).
|
---|
463 | *
|
---|
464 | * A DHCP server is expected to respond within a short period of time.
|
---|
465 | * This timer checks whether an outstanding DHCP request is timed out.
|
---|
466 | */
|
---|
467 | void
|
---|
468 | dhcp_fine_tmr(void)
|
---|
469 | {
|
---|
470 | struct netif *netif;
|
---|
471 | /* loop through netif's */
|
---|
472 | NETIF_FOREACH(netif) {
|
---|
473 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
474 | /* only act on DHCP configured interfaces */
|
---|
475 | if (dhcp != NULL) {
|
---|
476 | /* timer is active (non zero), and is about to trigger now */
|
---|
477 | if (dhcp->request_timeout > 1) {
|
---|
478 | dhcp->request_timeout--;
|
---|
479 | } else if (dhcp->request_timeout == 1) {
|
---|
480 | dhcp->request_timeout--;
|
---|
481 | /* { dhcp->request_timeout == 0 } */
|
---|
482 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
|
---|
483 | /* this client's request timeout triggered */
|
---|
484 | dhcp_timeout(netif);
|
---|
485 | }
|
---|
486 | }
|
---|
487 | }
|
---|
488 | }
|
---|
489 |
|
---|
490 | /**
|
---|
491 | * A DHCP negotiation transaction, or ARP request, has timed out.
|
---|
492 | *
|
---|
493 | * The timer that was started with the DHCP or ARP request has
|
---|
494 | * timed out, indicating no response was received in time.
|
---|
495 | *
|
---|
496 | * @param netif the netif under DHCP control
|
---|
497 | */
|
---|
498 | static void
|
---|
499 | dhcp_timeout(struct netif *netif)
|
---|
500 | {
|
---|
501 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
502 |
|
---|
503 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
|
---|
504 | /* back-off period has passed, or server selection timed out */
|
---|
505 | if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) {
|
---|
506 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
|
---|
507 | dhcp_discover(netif);
|
---|
508 | /* receiving the requested lease timed out */
|
---|
509 | } else if (dhcp->state == DHCP_STATE_REQUESTING) {
|
---|
510 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
|
---|
511 | if (dhcp->tries <= 5) {
|
---|
512 | dhcp_select(netif);
|
---|
513 | } else {
|
---|
514 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
|
---|
515 | dhcp_release_and_stop(netif);
|
---|
516 | dhcp_start(netif);
|
---|
517 | }
|
---|
518 | #if DHCP_DOES_ARP_CHECK
|
---|
519 | /* received no ARP reply for the offered address (which is good) */
|
---|
520 | } else if (dhcp->state == DHCP_STATE_CHECKING) {
|
---|
521 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
|
---|
522 | if (dhcp->tries <= 1) {
|
---|
523 | dhcp_check(netif);
|
---|
524 | /* no ARP replies on the offered address,
|
---|
525 | looks like the IP address is indeed free */
|
---|
526 | } else {
|
---|
527 | /* bind the interface to the offered address */
|
---|
528 | dhcp_bind(netif);
|
---|
529 | }
|
---|
530 | #endif /* DHCP_DOES_ARP_CHECK */
|
---|
531 | } else if (dhcp->state == DHCP_STATE_REBOOTING) {
|
---|
532 | if (dhcp->tries < REBOOT_TRIES) {
|
---|
533 | dhcp_reboot(netif);
|
---|
534 | } else {
|
---|
535 | dhcp_discover(netif);
|
---|
536 | }
|
---|
537 | }
|
---|
538 | }
|
---|
539 |
|
---|
540 | /**
|
---|
541 | * The renewal period has timed out.
|
---|
542 | *
|
---|
543 | * @param netif the netif under DHCP control
|
---|
544 | */
|
---|
545 | static void
|
---|
546 | dhcp_t1_timeout(struct netif *netif)
|
---|
547 | {
|
---|
548 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
549 |
|
---|
550 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
|
---|
551 | if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
|
---|
552 | (dhcp->state == DHCP_STATE_RENEWING)) {
|
---|
553 | /* just retry to renew - note that the rebind timer (t2) will
|
---|
554 | * eventually time-out if renew tries fail. */
|
---|
555 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
---|
556 | ("dhcp_t1_timeout(): must renew\n"));
|
---|
557 | /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
|
---|
558 | DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */
|
---|
559 | dhcp_renew(netif);
|
---|
560 | /* Calculate next timeout */
|
---|
561 | if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) {
|
---|
562 | dhcp->t1_renew_time = (u16_t)((dhcp->t2_timeout - dhcp->lease_used) / 2);
|
---|
563 | }
|
---|
564 | }
|
---|
565 | }
|
---|
566 |
|
---|
567 | /**
|
---|
568 | * The rebind period has timed out.
|
---|
569 | *
|
---|
570 | * @param netif the netif under DHCP control
|
---|
571 | */
|
---|
572 | static void
|
---|
573 | dhcp_t2_timeout(struct netif *netif)
|
---|
574 | {
|
---|
575 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
576 |
|
---|
577 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
|
---|
578 | if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
|
---|
579 | (dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) {
|
---|
580 | /* just retry to rebind */
|
---|
581 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
---|
582 | ("dhcp_t2_timeout(): must rebind\n"));
|
---|
583 | /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
|
---|
584 | DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */
|
---|
585 | dhcp_rebind(netif);
|
---|
586 | /* Calculate next timeout */
|
---|
587 | if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) {
|
---|
588 | dhcp->t2_rebind_time = (u16_t)((dhcp->t0_timeout - dhcp->lease_used) / 2);
|
---|
589 | }
|
---|
590 | }
|
---|
591 | }
|
---|
592 |
|
---|
593 | /**
|
---|
594 | * Handle a DHCP ACK packet
|
---|
595 | *
|
---|
596 | * @param netif the netif under DHCP control
|
---|
597 | */
|
---|
598 | static void
|
---|
599 | dhcp_handle_ack(struct netif *netif, struct dhcp_msg *msg_in)
|
---|
600 | {
|
---|
601 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
602 |
|
---|
603 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV
|
---|
604 | u8_t n;
|
---|
605 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */
|
---|
606 | #if LWIP_DHCP_GET_NTP_SRV
|
---|
607 | ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS];
|
---|
608 | #endif
|
---|
609 |
|
---|
610 | /* clear options we might not get from the ACK */
|
---|
611 | ip4_addr_set_zero(&dhcp->offered_sn_mask);
|
---|
612 | ip4_addr_set_zero(&dhcp->offered_gw_addr);
|
---|
613 | #if LWIP_DHCP_BOOTP_FILE
|
---|
614 | ip4_addr_set_zero(&dhcp->offered_si_addr);
|
---|
615 | #endif /* LWIP_DHCP_BOOTP_FILE */
|
---|
616 |
|
---|
617 | /* lease time given? */
|
---|
618 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {
|
---|
619 | /* remember offered lease time */
|
---|
620 | dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);
|
---|
621 | }
|
---|
622 | /* renewal period given? */
|
---|
623 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {
|
---|
624 | /* remember given renewal period */
|
---|
625 | dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);
|
---|
626 | } else {
|
---|
627 | /* calculate safe periods for renewal */
|
---|
628 | dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
|
---|
629 | }
|
---|
630 |
|
---|
631 | /* renewal period given? */
|
---|
632 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {
|
---|
633 | /* remember given rebind period */
|
---|
634 | dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);
|
---|
635 | } else {
|
---|
636 | /* calculate safe periods for rebinding (offered_t0_lease * 0.875 -> 87.5%)*/
|
---|
637 | dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U;
|
---|
638 | }
|
---|
639 |
|
---|
640 | /* (y)our internet address */
|
---|
641 | ip4_addr_copy(dhcp->offered_ip_addr, msg_in->yiaddr);
|
---|
642 |
|
---|
643 | #if LWIP_DHCP_BOOTP_FILE
|
---|
644 | /* copy boot server address,
|
---|
645 | boot file name copied in dhcp_parse_reply if not overloaded */
|
---|
646 | ip4_addr_copy(dhcp->offered_si_addr, msg_in->siaddr);
|
---|
647 | #endif /* LWIP_DHCP_BOOTP_FILE */
|
---|
648 |
|
---|
649 | /* subnet mask given? */
|
---|
650 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
|
---|
651 | /* remember given subnet mask */
|
---|
652 | ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
|
---|
653 | dhcp->subnet_mask_given = 1;
|
---|
654 | } else {
|
---|
655 | dhcp->subnet_mask_given = 0;
|
---|
656 | }
|
---|
657 |
|
---|
658 | /* gateway router */
|
---|
659 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
|
---|
660 | ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
|
---|
661 | }
|
---|
662 |
|
---|
663 | #if LWIP_DHCP_GET_NTP_SRV
|
---|
664 | /* NTP servers */
|
---|
665 | for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) {
|
---|
666 | ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n)));
|
---|
667 | }
|
---|
668 | dhcp_set_ntp_servers(n, ntp_server_addrs);
|
---|
669 | #endif /* LWIP_DHCP_GET_NTP_SRV */
|
---|
670 |
|
---|
671 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS
|
---|
672 | /* DNS servers */
|
---|
673 | for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
|
---|
674 | ip_addr_t dns_addr;
|
---|
675 | ip_addr_set_ip4_u32_val(dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
|
---|
676 | dns_setserver(n, &dns_addr);
|
---|
677 | }
|
---|
678 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
|
---|
679 | }
|
---|
680 |
|
---|
681 | /**
|
---|
682 | * @ingroup dhcp4
|
---|
683 | * Set a statically allocated struct dhcp to work with.
|
---|
684 | * Using this prevents dhcp_start to allocate it using mem_malloc.
|
---|
685 | *
|
---|
686 | * @param netif the netif for which to set the struct dhcp
|
---|
687 | * @param dhcp (uninitialised) dhcp struct allocated by the application
|
---|
688 | */
|
---|
689 | void
|
---|
690 | dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
|
---|
691 | {
|
---|
692 | LWIP_ASSERT_CORE_LOCKED();
|
---|
693 | LWIP_ASSERT("netif != NULL", netif != NULL);
|
---|
694 | LWIP_ASSERT("dhcp != NULL", dhcp != NULL);
|
---|
695 | LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL);
|
---|
696 |
|
---|
697 | /* clear data structure */
|
---|
698 | memset(dhcp, 0, sizeof(struct dhcp));
|
---|
699 | /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
|
---|
700 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
|
---|
701 | }
|
---|
702 |
|
---|
703 | /**
|
---|
704 | * @ingroup dhcp4
|
---|
705 | * Removes a struct dhcp from a netif.
|
---|
706 | *
|
---|
707 | * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
|
---|
708 | * struct dhcp since the memory is passed back to the heap.
|
---|
709 | *
|
---|
710 | * @param netif the netif from which to remove the struct dhcp
|
---|
711 | */
|
---|
712 | void dhcp_cleanup(struct netif *netif)
|
---|
713 | {
|
---|
714 | LWIP_ASSERT_CORE_LOCKED();
|
---|
715 | LWIP_ASSERT("netif != NULL", netif != NULL);
|
---|
716 |
|
---|
717 | if (netif_dhcp_data(netif) != NULL) {
|
---|
718 | mem_free(netif_dhcp_data(netif));
|
---|
719 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL);
|
---|
720 | }
|
---|
721 | }
|
---|
722 |
|
---|
723 | /**
|
---|
724 | * @ingroup dhcp4
|
---|
725 | * Start DHCP negotiation for a network interface.
|
---|
726 | *
|
---|
727 | * If no DHCP client instance was attached to this interface,
|
---|
728 | * a new client is created first. If a DHCP client instance
|
---|
729 | * was already present, it restarts negotiation.
|
---|
730 | *
|
---|
731 | * @param netif The lwIP network interface
|
---|
732 | * @return lwIP error code
|
---|
733 | * - ERR_OK - No error
|
---|
734 | * - ERR_MEM - Out of memory
|
---|
735 | */
|
---|
736 | err_t
|
---|
737 | dhcp_start(struct netif *netif)
|
---|
738 | {
|
---|
739 | struct dhcp *dhcp;
|
---|
740 | err_t result;
|
---|
741 |
|
---|
742 | LWIP_ASSERT_CORE_LOCKED();
|
---|
743 | LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
|
---|
744 | LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
|
---|
745 | dhcp = netif_dhcp_data(netif);
|
---|
746 | 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));
|
---|
747 |
|
---|
748 | /* check MTU of the netif */
|
---|
749 | if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
|
---|
750 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
|
---|
751 | return ERR_MEM;
|
---|
752 | }
|
---|
753 |
|
---|
754 | /* no DHCP client attached yet? */
|
---|
755 | if (dhcp == NULL) {
|
---|
756 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): mallocing new DHCP client\n"));
|
---|
757 | dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
|
---|
758 | if (dhcp == NULL) {
|
---|
759 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
|
---|
760 | return ERR_MEM;
|
---|
761 | }
|
---|
762 |
|
---|
763 | /* store this dhcp client in the netif */
|
---|
764 | netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
|
---|
765 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
|
---|
766 | /* already has DHCP client attached */
|
---|
767 | } else {
|
---|
768 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
|
---|
769 |
|
---|
770 | if (dhcp->pcb_allocated != 0) {
|
---|
771 | dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
|
---|
772 | }
|
---|
773 | /* dhcp is cleared below, no need to reset flag*/
|
---|
774 | }
|
---|
775 |
|
---|
776 | /* clear data structure */
|
---|
777 | memset(dhcp, 0, sizeof(struct dhcp));
|
---|
778 | /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
|
---|
779 |
|
---|
780 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
|
---|
781 |
|
---|
782 | if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */
|
---|
783 | return ERR_MEM;
|
---|
784 | }
|
---|
785 | dhcp->pcb_allocated = 1;
|
---|
786 |
|
---|
787 | if (!netif_is_link_up(netif)) {
|
---|
788 | /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */
|
---|
789 | dhcp_set_state(dhcp, DHCP_STATE_INIT);
|
---|
790 | return ERR_OK;
|
---|
791 | }
|
---|
792 |
|
---|
793 | /* (re)start the DHCP negotiation */
|
---|
794 | result = dhcp_discover(netif);
|
---|
795 | if (result != ERR_OK) {
|
---|
796 | /* free resources allocated above */
|
---|
797 | dhcp_release_and_stop(netif);
|
---|
798 | return ERR_MEM;
|
---|
799 | }
|
---|
800 | return result;
|
---|
801 | }
|
---|
802 |
|
---|
803 | /**
|
---|
804 | * @ingroup dhcp4
|
---|
805 | * Inform a DHCP server of our manual configuration.
|
---|
806 | *
|
---|
807 | * This informs DHCP servers of our fixed IP address configuration
|
---|
808 | * by sending an INFORM message. It does not involve DHCP address
|
---|
809 | * configuration, it is just here to be nice to the network.
|
---|
810 | *
|
---|
811 | * @param netif The lwIP network interface
|
---|
812 | */
|
---|
813 | void
|
---|
814 | dhcp_inform(struct netif *netif)
|
---|
815 | {
|
---|
816 | struct dhcp dhcp;
|
---|
817 | struct pbuf *p_out;
|
---|
818 | u16_t options_out_len;
|
---|
819 |
|
---|
820 | LWIP_ASSERT_CORE_LOCKED();
|
---|
821 | LWIP_ERROR("netif != NULL", (netif != NULL), return;);
|
---|
822 |
|
---|
823 | if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */
|
---|
824 | return;
|
---|
825 | }
|
---|
826 |
|
---|
827 | memset(&dhcp, 0, sizeof(struct dhcp));
|
---|
828 | dhcp_set_state(&dhcp, DHCP_STATE_INFORMING);
|
---|
829 |
|
---|
830 | /* create and initialize the DHCP message header */
|
---|
831 | p_out = dhcp_create_msg(netif, &dhcp, DHCP_INFORM, &options_out_len);
|
---|
832 | if (p_out != NULL) {
|
---|
833 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
834 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
835 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif));
|
---|
836 |
|
---|
837 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, &dhcp, DHCP_STATE_INFORMING, msg_out, DHCP_INFORM, &options_out_len);
|
---|
838 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
839 |
|
---|
840 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
|
---|
841 |
|
---|
842 | udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif);
|
---|
843 |
|
---|
844 | pbuf_free(p_out);
|
---|
845 | } else {
|
---|
846 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
|
---|
847 | }
|
---|
848 |
|
---|
849 | dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */
|
---|
850 | }
|
---|
851 |
|
---|
852 | /** Handle a possible change in the network configuration.
|
---|
853 | *
|
---|
854 | * This enters the REBOOTING state to verify that the currently bound
|
---|
855 | * address is still valid.
|
---|
856 | */
|
---|
857 | void
|
---|
858 | dhcp_network_changed(struct netif *netif)
|
---|
859 | {
|
---|
860 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
861 |
|
---|
862 | if (!dhcp) {
|
---|
863 | return;
|
---|
864 | }
|
---|
865 | switch (dhcp->state) {
|
---|
866 | case DHCP_STATE_REBINDING:
|
---|
867 | case DHCP_STATE_RENEWING:
|
---|
868 | case DHCP_STATE_BOUND:
|
---|
869 | case DHCP_STATE_REBOOTING:
|
---|
870 | dhcp->tries = 0;
|
---|
871 | dhcp_reboot(netif);
|
---|
872 | break;
|
---|
873 | case DHCP_STATE_OFF:
|
---|
874 | /* stay off */
|
---|
875 | break;
|
---|
876 | default:
|
---|
877 | LWIP_ASSERT("invalid dhcp->state", dhcp->state <= DHCP_STATE_BACKING_OFF);
|
---|
878 | /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the
|
---|
879 | state changes, SELECTING: continue with current 'rid' as we stay in the
|
---|
880 | same state */
|
---|
881 | #if LWIP_DHCP_AUTOIP_COOP
|
---|
882 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
|
---|
883 | autoip_stop(netif);
|
---|
884 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
|
---|
885 | }
|
---|
886 | #endif /* LWIP_DHCP_AUTOIP_COOP */
|
---|
887 | /* ensure we start with short timeouts, even if already discovering */
|
---|
888 | dhcp->tries = 0;
|
---|
889 | dhcp_discover(netif);
|
---|
890 | break;
|
---|
891 | }
|
---|
892 | }
|
---|
893 |
|
---|
894 | #if DHCP_DOES_ARP_CHECK
|
---|
895 | /**
|
---|
896 | * Match an ARP reply with the offered IP address:
|
---|
897 | * check whether the offered IP address is not in use using ARP
|
---|
898 | *
|
---|
899 | * @param netif the network interface on which the reply was received
|
---|
900 | * @param addr The IP address we received a reply from
|
---|
901 | */
|
---|
902 | void
|
---|
903 | dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr)
|
---|
904 | {
|
---|
905 | struct dhcp *dhcp;
|
---|
906 |
|
---|
907 | LWIP_ERROR("netif != NULL", (netif != NULL), return;);
|
---|
908 | dhcp = netif_dhcp_data(netif);
|
---|
909 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
|
---|
910 | /* is a DHCP client doing an ARP check? */
|
---|
911 | if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) {
|
---|
912 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
|
---|
913 | ip4_addr_get_u32(addr)));
|
---|
914 | /* did a host respond with the address we
|
---|
915 | were offered by the DHCP server? */
|
---|
916 | if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) {
|
---|
917 | /* we will not accept the offered address */
|
---|
918 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
---|
919 | ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
|
---|
920 | dhcp_decline(netif);
|
---|
921 | }
|
---|
922 | }
|
---|
923 | }
|
---|
924 |
|
---|
925 | /**
|
---|
926 | * Decline an offered lease.
|
---|
927 | *
|
---|
928 | * Tell the DHCP server we do not accept the offered address.
|
---|
929 | * One reason to decline the lease is when we find out the address
|
---|
930 | * is already in use by another host (through ARP).
|
---|
931 | *
|
---|
932 | * @param netif the netif under DHCP control
|
---|
933 | */
|
---|
934 | static err_t
|
---|
935 | dhcp_decline(struct netif *netif)
|
---|
936 | {
|
---|
937 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
938 | err_t result;
|
---|
939 | u16_t msecs;
|
---|
940 | struct pbuf *p_out;
|
---|
941 | u16_t options_out_len;
|
---|
942 |
|
---|
943 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
|
---|
944 | dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
|
---|
945 | /* create and initialize the DHCP message header */
|
---|
946 | p_out = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len);
|
---|
947 | if (p_out != NULL) {
|
---|
948 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
949 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4);
|
---|
950 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
|
---|
951 |
|
---|
952 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_BACKING_OFF, msg_out, DHCP_DECLINE, &options_out_len);
|
---|
953 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
954 |
|
---|
955 | /* per section 4.4.4, broadcast DECLINE messages */
|
---|
956 | result = udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
|
---|
957 | pbuf_free(p_out);
|
---|
958 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
|
---|
959 | } else {
|
---|
960 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
---|
961 | ("dhcp_decline: could not allocate DHCP request\n"));
|
---|
962 | result = ERR_MEM;
|
---|
963 | }
|
---|
964 | if (dhcp->tries < 255) {
|
---|
965 | dhcp->tries++;
|
---|
966 | }
|
---|
967 | msecs = 10 * 1000;
|
---|
968 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
969 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
970 | return result;
|
---|
971 | }
|
---|
972 | #endif /* DHCP_DOES_ARP_CHECK */
|
---|
973 |
|
---|
974 |
|
---|
975 | /**
|
---|
976 | * Start the DHCP process, discover a DHCP server.
|
---|
977 | *
|
---|
978 | * @param netif the netif under DHCP control
|
---|
979 | */
|
---|
980 | static err_t
|
---|
981 | dhcp_discover(struct netif *netif)
|
---|
982 | {
|
---|
983 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
984 | err_t result = ERR_OK;
|
---|
985 | u16_t msecs;
|
---|
986 | u8_t i;
|
---|
987 | struct pbuf *p_out;
|
---|
988 | u16_t options_out_len;
|
---|
989 |
|
---|
990 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
|
---|
991 |
|
---|
992 | ip4_addr_set_any(&dhcp->offered_ip_addr);
|
---|
993 | dhcp_set_state(dhcp, DHCP_STATE_SELECTING);
|
---|
994 | /* create and initialize the DHCP message header */
|
---|
995 | p_out = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER, &options_out_len);
|
---|
996 | if (p_out != NULL) {
|
---|
997 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
998 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
|
---|
999 |
|
---|
1000 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
1001 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif));
|
---|
1002 |
|
---|
1003 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
|
---|
1004 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
|
---|
1005 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]);
|
---|
1006 | }
|
---|
1007 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_SELECTING, msg_out, DHCP_DISCOVER, &options_out_len);
|
---|
1008 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
1009 |
|
---|
1010 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n"));
|
---|
1011 | udp_sendto_if_src(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
|
---|
1012 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
|
---|
1013 | pbuf_free(p_out);
|
---|
1014 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
|
---|
1015 | } else {
|
---|
1016 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n"));
|
---|
1017 | }
|
---|
1018 | if (dhcp->tries < 255) {
|
---|
1019 | dhcp->tries++;
|
---|
1020 | }
|
---|
1021 | #if LWIP_DHCP_AUTOIP_COOP
|
---|
1022 | if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
|
---|
1023 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
|
---|
1024 | autoip_start(netif);
|
---|
1025 | }
|
---|
1026 | #endif /* LWIP_DHCP_AUTOIP_COOP */
|
---|
1027 | msecs = (u16_t)((dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000);
|
---|
1028 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
1029 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
1030 | return result;
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 |
|
---|
1034 | /**
|
---|
1035 | * Bind the interface to the offered IP address.
|
---|
1036 | *
|
---|
1037 | * @param netif network interface to bind to the offered address
|
---|
1038 | */
|
---|
1039 | static void
|
---|
1040 | dhcp_bind(struct netif *netif)
|
---|
1041 | {
|
---|
1042 | u32_t timeout;
|
---|
1043 | struct dhcp *dhcp;
|
---|
1044 | ip4_addr_t sn_mask, gw_addr;
|
---|
1045 | LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
|
---|
1046 | dhcp = netif_dhcp_data(netif);
|
---|
1047 | LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
|
---|
1048 | 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));
|
---|
1049 |
|
---|
1050 | /* reset time used of lease */
|
---|
1051 | dhcp->lease_used = 0;
|
---|
1052 |
|
---|
1053 | if (dhcp->offered_t0_lease != 0xffffffffUL) {
|
---|
1054 | /* set renewal period timer */
|
---|
1055 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease));
|
---|
1056 | timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
|
---|
1057 | if (timeout > 0xffff) {
|
---|
1058 | timeout = 0xffff;
|
---|
1059 | }
|
---|
1060 | dhcp->t0_timeout = (u16_t)timeout;
|
---|
1061 | if (dhcp->t0_timeout == 0) {
|
---|
1062 | dhcp->t0_timeout = 1;
|
---|
1063 | }
|
---|
1064 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000));
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | /* temporary DHCP lease? */
|
---|
1068 | if (dhcp->offered_t1_renew != 0xffffffffUL) {
|
---|
1069 | /* set renewal period timer */
|
---|
1070 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
|
---|
1071 | timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
|
---|
1072 | if (timeout > 0xffff) {
|
---|
1073 | timeout = 0xffff;
|
---|
1074 | }
|
---|
1075 | dhcp->t1_timeout = (u16_t)timeout;
|
---|
1076 | if (dhcp->t1_timeout == 0) {
|
---|
1077 | dhcp->t1_timeout = 1;
|
---|
1078 | }
|
---|
1079 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew * 1000));
|
---|
1080 | dhcp->t1_renew_time = dhcp->t1_timeout;
|
---|
1081 | }
|
---|
1082 | /* set renewal period timer */
|
---|
1083 | if (dhcp->offered_t2_rebind != 0xffffffffUL) {
|
---|
1084 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
|
---|
1085 | timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
|
---|
1086 | if (timeout > 0xffff) {
|
---|
1087 | timeout = 0xffff;
|
---|
1088 | }
|
---|
1089 | dhcp->t2_timeout = (u16_t)timeout;
|
---|
1090 | if (dhcp->t2_timeout == 0) {
|
---|
1091 | dhcp->t2_timeout = 1;
|
---|
1092 | }
|
---|
1093 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind * 1000));
|
---|
1094 | dhcp->t2_rebind_time = dhcp->t2_timeout;
|
---|
1095 | }
|
---|
1096 |
|
---|
1097 | /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */
|
---|
1098 | if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) {
|
---|
1099 | dhcp->t1_timeout = 0;
|
---|
1100 | }
|
---|
1101 |
|
---|
1102 | if (dhcp->subnet_mask_given) {
|
---|
1103 | /* copy offered network mask */
|
---|
1104 | ip4_addr_copy(sn_mask, dhcp->offered_sn_mask);
|
---|
1105 | } else {
|
---|
1106 | /* subnet mask not given, choose a safe subnet mask given the network class */
|
---|
1107 | u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
|
---|
1108 | if (first_octet <= 127) {
|
---|
1109 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
|
---|
1110 | } else if (first_octet >= 192) {
|
---|
1111 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
|
---|
1112 | } else {
|
---|
1113 | ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
|
---|
1114 | }
|
---|
1115 | }
|
---|
1116 |
|
---|
1117 | ip4_addr_copy(gw_addr, dhcp->offered_gw_addr);
|
---|
1118 | /* gateway address not given? */
|
---|
1119 | if (ip4_addr_isany_val(gw_addr)) {
|
---|
1120 | /* copy network address */
|
---|
1121 | ip4_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
|
---|
1122 | /* use first host address on network as gateway */
|
---|
1123 | ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | #if LWIP_DHCP_AUTOIP_COOP
|
---|
1127 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
|
---|
1128 | autoip_stop(netif);
|
---|
1129 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
|
---|
1130 | }
|
---|
1131 | #endif /* LWIP_DHCP_AUTOIP_COOP */
|
---|
1132 |
|
---|
1133 | 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",
|
---|
1134 | ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr)));
|
---|
1135 | /* netif is now bound to DHCP leased address - set this before assigning the address
|
---|
1136 | to ensure the callback can use dhcp_supplied_address() */
|
---|
1137 | dhcp_set_state(dhcp, DHCP_STATE_BOUND);
|
---|
1138 |
|
---|
1139 | netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr);
|
---|
1140 | /* interface is used by routing now that an address is set */
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | /**
|
---|
1144 | * @ingroup dhcp4
|
---|
1145 | * Renew an existing DHCP lease at the involved DHCP server.
|
---|
1146 | *
|
---|
1147 | * @param netif network interface which must renew its lease
|
---|
1148 | */
|
---|
1149 | err_t
|
---|
1150 | dhcp_renew(struct netif *netif)
|
---|
1151 | {
|
---|
1152 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1153 | err_t result;
|
---|
1154 | u16_t msecs;
|
---|
1155 | u8_t i;
|
---|
1156 | struct pbuf *p_out;
|
---|
1157 | u16_t options_out_len;
|
---|
1158 |
|
---|
1159 | LWIP_ASSERT_CORE_LOCKED();
|
---|
1160 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
|
---|
1161 | dhcp_set_state(dhcp, DHCP_STATE_RENEWING);
|
---|
1162 |
|
---|
1163 | /* create and initialize the DHCP message header */
|
---|
1164 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
|
---|
1165 | if (p_out != NULL) {
|
---|
1166 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
1167 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
1168 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif));
|
---|
1169 |
|
---|
1170 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
|
---|
1171 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
|
---|
1172 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]);
|
---|
1173 | }
|
---|
1174 |
|
---|
1175 | #if LWIP_NETIF_HOSTNAME
|
---|
1176 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif);
|
---|
1177 | #endif /* LWIP_NETIF_HOSTNAME */
|
---|
1178 |
|
---|
1179 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_RENEWING, msg_out, DHCP_REQUEST, &options_out_len);
|
---|
1180 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
1181 |
|
---|
1182 | result = udp_sendto_if(dhcp_pcb, p_out, &dhcp->server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif);
|
---|
1183 | pbuf_free(p_out);
|
---|
1184 |
|
---|
1185 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
|
---|
1186 | } else {
|
---|
1187 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
|
---|
1188 | result = ERR_MEM;
|
---|
1189 | }
|
---|
1190 | if (dhcp->tries < 255) {
|
---|
1191 | dhcp->tries++;
|
---|
1192 | }
|
---|
1193 | /* back-off on retries, but to a maximum of 20 seconds */
|
---|
1194 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000);
|
---|
1195 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
1196 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
1197 | return result;
|
---|
1198 | }
|
---|
1199 |
|
---|
1200 | /**
|
---|
1201 | * Rebind with a DHCP server for an existing DHCP lease.
|
---|
1202 | *
|
---|
1203 | * @param netif network interface which must rebind with a DHCP server
|
---|
1204 | */
|
---|
1205 | static err_t
|
---|
1206 | dhcp_rebind(struct netif *netif)
|
---|
1207 | {
|
---|
1208 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1209 | err_t result;
|
---|
1210 | u16_t msecs;
|
---|
1211 | u8_t i;
|
---|
1212 | struct pbuf *p_out;
|
---|
1213 | u16_t options_out_len;
|
---|
1214 |
|
---|
1215 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
|
---|
1216 | dhcp_set_state(dhcp, DHCP_STATE_REBINDING);
|
---|
1217 |
|
---|
1218 | /* create and initialize the DHCP message header */
|
---|
1219 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
|
---|
1220 | if (p_out != NULL) {
|
---|
1221 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
1222 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
1223 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN(netif));
|
---|
1224 |
|
---|
1225 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
|
---|
1226 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
|
---|
1227 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]);
|
---|
1228 | }
|
---|
1229 |
|
---|
1230 | #if LWIP_NETIF_HOSTNAME
|
---|
1231 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif);
|
---|
1232 | #endif /* LWIP_NETIF_HOSTNAME */
|
---|
1233 |
|
---|
1234 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBINDING, msg_out, DHCP_DISCOVER, &options_out_len);
|
---|
1235 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
1236 |
|
---|
1237 | /* broadcast to server */
|
---|
1238 | result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif);
|
---|
1239 | pbuf_free(p_out);
|
---|
1240 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
|
---|
1241 | } else {
|
---|
1242 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
|
---|
1243 | result = ERR_MEM;
|
---|
1244 | }
|
---|
1245 | if (dhcp->tries < 255) {
|
---|
1246 | dhcp->tries++;
|
---|
1247 | }
|
---|
1248 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000);
|
---|
1249 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
1250 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
1251 | return result;
|
---|
1252 | }
|
---|
1253 |
|
---|
1254 | /**
|
---|
1255 | * Enter REBOOTING state to verify an existing lease
|
---|
1256 | *
|
---|
1257 | * @param netif network interface which must reboot
|
---|
1258 | */
|
---|
1259 | static err_t
|
---|
1260 | dhcp_reboot(struct netif *netif)
|
---|
1261 | {
|
---|
1262 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1263 | err_t result;
|
---|
1264 | u16_t msecs;
|
---|
1265 | u8_t i;
|
---|
1266 | struct pbuf *p_out;
|
---|
1267 | u16_t options_out_len;
|
---|
1268 |
|
---|
1269 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
|
---|
1270 | dhcp_set_state(dhcp, DHCP_STATE_REBOOTING);
|
---|
1271 |
|
---|
1272 | /* create and initialize the DHCP message header */
|
---|
1273 | p_out = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
|
---|
1274 | if (p_out != NULL) {
|
---|
1275 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
1276 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
|
---|
1277 | options_out_len = dhcp_option_short(options_out_len, msg_out->options, DHCP_MAX_MSG_LEN_MIN_REQUIRED);
|
---|
1278 |
|
---|
1279 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_REQUESTED_IP, 4);
|
---|
1280 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
|
---|
1281 |
|
---|
1282 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
|
---|
1283 | for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
|
---|
1284 | options_out_len = dhcp_option_byte(options_out_len, msg_out->options, dhcp_discover_request_options[i]);
|
---|
1285 | }
|
---|
1286 |
|
---|
1287 | #if LWIP_NETIF_HOSTNAME
|
---|
1288 | options_out_len = dhcp_option_hostname(options_out_len, msg_out->options, netif);
|
---|
1289 | #endif /* LWIP_NETIF_HOSTNAME */
|
---|
1290 |
|
---|
1291 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REBOOTING, msg_out, DHCP_REQUEST, &options_out_len);
|
---|
1292 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
1293 |
|
---|
1294 | /* broadcast to server */
|
---|
1295 | result = udp_sendto_if(dhcp_pcb, p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif);
|
---|
1296 | pbuf_free(p_out);
|
---|
1297 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
|
---|
1298 | } else {
|
---|
1299 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n"));
|
---|
1300 | result = ERR_MEM;
|
---|
1301 | }
|
---|
1302 | if (dhcp->tries < 255) {
|
---|
1303 | dhcp->tries++;
|
---|
1304 | }
|
---|
1305 | msecs = (u16_t)(dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000);
|
---|
1306 | dhcp->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
|
---|
1307 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
|
---|
1308 | return result;
|
---|
1309 | }
|
---|
1310 |
|
---|
1311 | /**
|
---|
1312 | * @ingroup dhcp4
|
---|
1313 | * Release a DHCP lease and stop DHCP statemachine (and AUTOIP if LWIP_DHCP_AUTOIP_COOP).
|
---|
1314 | *
|
---|
1315 | * @param netif network interface
|
---|
1316 | */
|
---|
1317 | void
|
---|
1318 | dhcp_release_and_stop(struct netif *netif)
|
---|
1319 | {
|
---|
1320 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1321 | ip_addr_t server_ip_addr;
|
---|
1322 |
|
---|
1323 | LWIP_ASSERT_CORE_LOCKED();
|
---|
1324 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release_and_stop()\n"));
|
---|
1325 | if (dhcp == NULL) {
|
---|
1326 | return;
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | /* already off? -> nothing to do */
|
---|
1330 | if (dhcp->state == DHCP_STATE_OFF) {
|
---|
1331 | return;
|
---|
1332 | }
|
---|
1333 |
|
---|
1334 | ip_addr_copy(server_ip_addr, dhcp->server_ip_addr);
|
---|
1335 |
|
---|
1336 | /* clean old DHCP offer */
|
---|
1337 | ip_addr_set_zero_ip4(&dhcp->server_ip_addr);
|
---|
1338 | ip4_addr_set_zero(&dhcp->offered_ip_addr);
|
---|
1339 | ip4_addr_set_zero(&dhcp->offered_sn_mask);
|
---|
1340 | ip4_addr_set_zero(&dhcp->offered_gw_addr);
|
---|
1341 | #if LWIP_DHCP_BOOTP_FILE
|
---|
1342 | ip4_addr_set_zero(&dhcp->offered_si_addr);
|
---|
1343 | #endif /* LWIP_DHCP_BOOTP_FILE */
|
---|
1344 | dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
|
---|
1345 | dhcp->t1_renew_time = dhcp->t2_rebind_time = dhcp->lease_used = dhcp->t0_timeout = 0;
|
---|
1346 |
|
---|
1347 | /* send release message when current IP was assigned via DHCP */
|
---|
1348 | if (dhcp_supplied_address(netif)) {
|
---|
1349 | /* create and initialize the DHCP message header */
|
---|
1350 | struct pbuf *p_out;
|
---|
1351 | u16_t options_out_len;
|
---|
1352 | p_out = dhcp_create_msg(netif, dhcp, DHCP_RELEASE, &options_out_len);
|
---|
1353 | if (p_out != NULL) {
|
---|
1354 | struct dhcp_msg *msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
1355 | options_out_len = dhcp_option(options_out_len, msg_out->options, DHCP_OPTION_SERVER_ID, 4);
|
---|
1356 | options_out_len = dhcp_option_long(options_out_len, msg_out->options, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr))));
|
---|
1357 |
|
---|
1358 | LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, dhcp->state, msg_out, DHCP_RELEASE, &options_out_len);
|
---|
1359 | dhcp_option_trailer(options_out_len, msg_out->options, p_out);
|
---|
1360 |
|
---|
1361 | udp_sendto_if(dhcp_pcb, p_out, &server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif);
|
---|
1362 | pbuf_free(p_out);
|
---|
1363 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n"));
|
---|
1364 | } else {
|
---|
1365 | /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */
|
---|
1366 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
|
---|
1367 | }
|
---|
1368 | }
|
---|
1369 |
|
---|
1370 | /* remove IP address from interface (prevents routing from selecting this interface) */
|
---|
1371 | netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
|
---|
1372 |
|
---|
1373 | #if LWIP_DHCP_AUTOIP_COOP
|
---|
1374 | if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
|
---|
1375 | autoip_stop(netif);
|
---|
1376 | dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
|
---|
1377 | }
|
---|
1378 | #endif /* LWIP_DHCP_AUTOIP_COOP */
|
---|
1379 |
|
---|
1380 | dhcp_set_state(dhcp, DHCP_STATE_OFF);
|
---|
1381 |
|
---|
1382 | if (dhcp->pcb_allocated != 0) {
|
---|
1383 | dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
|
---|
1384 | dhcp->pcb_allocated = 0;
|
---|
1385 | }
|
---|
1386 | }
|
---|
1387 |
|
---|
1388 | /**
|
---|
1389 | * @ingroup dhcp4
|
---|
1390 | * This function calls dhcp_release_and_stop() internally.
|
---|
1391 | * @deprecated Use dhcp_release_and_stop() instead.
|
---|
1392 | */
|
---|
1393 | err_t
|
---|
1394 | dhcp_release(struct netif *netif)
|
---|
1395 | {
|
---|
1396 | dhcp_release_and_stop(netif);
|
---|
1397 | return ERR_OK;
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | /**
|
---|
1401 | * @ingroup dhcp4
|
---|
1402 | * This function calls dhcp_release_and_stop() internally.
|
---|
1403 | * @deprecated Use dhcp_release_and_stop() instead.
|
---|
1404 | */
|
---|
1405 | void
|
---|
1406 | dhcp_stop(struct netif *netif)
|
---|
1407 | {
|
---|
1408 | dhcp_release_and_stop(netif);
|
---|
1409 | }
|
---|
1410 |
|
---|
1411 | /*
|
---|
1412 | * Set the DHCP state of a DHCP client.
|
---|
1413 | *
|
---|
1414 | * If the state changed, reset the number of tries.
|
---|
1415 | */
|
---|
1416 | static void
|
---|
1417 | dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
|
---|
1418 | {
|
---|
1419 | if (new_state != dhcp->state) {
|
---|
1420 | dhcp->state = new_state;
|
---|
1421 | dhcp->tries = 0;
|
---|
1422 | dhcp->request_timeout = 0;
|
---|
1423 | }
|
---|
1424 | }
|
---|
1425 |
|
---|
1426 | /*
|
---|
1427 | * Concatenate an option type and length field to the outgoing
|
---|
1428 | * DHCP message.
|
---|
1429 | *
|
---|
1430 | */
|
---|
1431 | static u16_t
|
---|
1432 | dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len)
|
---|
1433 | {
|
---|
1434 | LWIP_ASSERT("dhcp_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
|
---|
1435 | options[options_out_len++] = option_type;
|
---|
1436 | options[options_out_len++] = option_len;
|
---|
1437 | return options_out_len;
|
---|
1438 | }
|
---|
1439 | /*
|
---|
1440 | * Concatenate a single byte to the outgoing DHCP message.
|
---|
1441 | *
|
---|
1442 | */
|
---|
1443 | static u16_t
|
---|
1444 | dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value)
|
---|
1445 | {
|
---|
1446 | LWIP_ASSERT("dhcp_option_byte: options_out_len < DHCP_OPTIONS_LEN", options_out_len < DHCP_OPTIONS_LEN);
|
---|
1447 | options[options_out_len++] = value;
|
---|
1448 | return options_out_len;
|
---|
1449 | }
|
---|
1450 |
|
---|
1451 | static u16_t
|
---|
1452 | dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value)
|
---|
1453 | {
|
---|
1454 | LWIP_ASSERT("dhcp_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN", options_out_len + 2U <= DHCP_OPTIONS_LEN);
|
---|
1455 | options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
|
---|
1456 | options[options_out_len++] = (u8_t) (value & 0x00ffU);
|
---|
1457 | return options_out_len;
|
---|
1458 | }
|
---|
1459 |
|
---|
1460 | static u16_t
|
---|
1461 | dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value)
|
---|
1462 | {
|
---|
1463 | LWIP_ASSERT("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN", options_out_len + 4U <= DHCP_OPTIONS_LEN);
|
---|
1464 | options[options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
|
---|
1465 | options[options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
|
---|
1466 | options[options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
|
---|
1467 | options[options_out_len++] = (u8_t)((value & 0x000000ffUL));
|
---|
1468 | return options_out_len;
|
---|
1469 | }
|
---|
1470 |
|
---|
1471 | #if LWIP_NETIF_HOSTNAME
|
---|
1472 | static u16_t
|
---|
1473 | dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif)
|
---|
1474 | {
|
---|
1475 | if (netif->hostname != NULL) {
|
---|
1476 | size_t namelen = strlen(netif->hostname);
|
---|
1477 | if (namelen > 0) {
|
---|
1478 | size_t len;
|
---|
1479 | const char *p = netif->hostname;
|
---|
1480 | /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME
|
---|
1481 | and 1 byte for trailer) */
|
---|
1482 | size_t available = DHCP_OPTIONS_LEN - options_out_len - 3;
|
---|
1483 | LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available);
|
---|
1484 | len = LWIP_MIN(namelen, available);
|
---|
1485 | LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF);
|
---|
1486 | options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_HOSTNAME, (u8_t)len);
|
---|
1487 | while (len--) {
|
---|
1488 | options_out_len = dhcp_option_byte(options_out_len, options, *p++);
|
---|
1489 | }
|
---|
1490 | }
|
---|
1491 | }
|
---|
1492 | return options_out_len;
|
---|
1493 | }
|
---|
1494 | #endif /* LWIP_NETIF_HOSTNAME */
|
---|
1495 |
|
---|
1496 | /**
|
---|
1497 | * Extract the DHCP message and the DHCP options.
|
---|
1498 | *
|
---|
1499 | * Extract the DHCP message and the DHCP options, each into a contiguous
|
---|
1500 | * piece of memory. As a DHCP message is variable sized by its options,
|
---|
1501 | * and also allows overriding some fields for options, the easy approach
|
---|
1502 | * is to first unfold the options into a contiguous piece of memory, and
|
---|
1503 | * use that further on.
|
---|
1504 | *
|
---|
1505 | */
|
---|
1506 | static err_t
|
---|
1507 | dhcp_parse_reply(struct pbuf *p, struct dhcp *dhcp)
|
---|
1508 | {
|
---|
1509 | u8_t *options;
|
---|
1510 | u16_t offset;
|
---|
1511 | u16_t offset_max;
|
---|
1512 | u16_t options_idx;
|
---|
1513 | u16_t options_idx_max;
|
---|
1514 | struct pbuf *q;
|
---|
1515 | int parse_file_as_options = 0;
|
---|
1516 | int parse_sname_as_options = 0;
|
---|
1517 | struct dhcp_msg *msg_in;
|
---|
1518 | #if LWIP_DHCP_BOOTP_FILE
|
---|
1519 | int file_overloaded = 0;
|
---|
1520 | #endif
|
---|
1521 |
|
---|
1522 | LWIP_UNUSED_ARG(dhcp);
|
---|
1523 |
|
---|
1524 | /* clear received options */
|
---|
1525 | dhcp_clear_all_options(dhcp);
|
---|
1526 | /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
|
---|
1527 | if (p->len < DHCP_SNAME_OFS) {
|
---|
1528 | return ERR_BUF;
|
---|
1529 | }
|
---|
1530 | msg_in = (struct dhcp_msg *)p->payload;
|
---|
1531 | #if LWIP_DHCP_BOOTP_FILE
|
---|
1532 | /* clear boot file name */
|
---|
1533 | dhcp->boot_file_name[0] = 0;
|
---|
1534 | #endif /* LWIP_DHCP_BOOTP_FILE */
|
---|
1535 |
|
---|
1536 | /* parse options */
|
---|
1537 |
|
---|
1538 | /* start with options field */
|
---|
1539 | options_idx = DHCP_OPTIONS_OFS;
|
---|
1540 | /* parse options to the end of the received packet */
|
---|
1541 | options_idx_max = p->tot_len;
|
---|
1542 | again:
|
---|
1543 | q = p;
|
---|
1544 | while ((q != NULL) && (options_idx >= q->len)) {
|
---|
1545 | options_idx = (u16_t)(options_idx - q->len);
|
---|
1546 | options_idx_max = (u16_t)(options_idx_max - q->len);
|
---|
1547 | q = q->next;
|
---|
1548 | }
|
---|
1549 | if (q == NULL) {
|
---|
1550 | return ERR_BUF;
|
---|
1551 | }
|
---|
1552 | offset = options_idx;
|
---|
1553 | offset_max = options_idx_max;
|
---|
1554 | options = (u8_t *)q->payload;
|
---|
1555 | /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
|
---|
1556 | while ((q != NULL) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) {
|
---|
1557 | u8_t op = options[offset];
|
---|
1558 | u8_t len;
|
---|
1559 | u8_t decode_len = 0;
|
---|
1560 | int decode_idx = -1;
|
---|
1561 | u16_t val_offset = (u16_t)(offset + 2);
|
---|
1562 | if (val_offset < offset) {
|
---|
1563 | /* overflow */
|
---|
1564 | return ERR_BUF;
|
---|
1565 | }
|
---|
1566 | /* len byte might be in the next pbuf */
|
---|
1567 | if ((offset + 1) < q->len) {
|
---|
1568 | len = options[offset + 1];
|
---|
1569 | } else {
|
---|
1570 | len = (q->next != NULL ? ((u8_t *)q->next->payload)[0] : 0);
|
---|
1571 | }
|
---|
1572 | /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
|
---|
1573 | decode_len = len;
|
---|
1574 | switch (op) {
|
---|
1575 | /* case(DHCP_OPTION_END): handled above */
|
---|
1576 | case (DHCP_OPTION_PAD):
|
---|
1577 | /* special option: no len encoded */
|
---|
1578 | decode_len = len = 0;
|
---|
1579 | /* will be increased below */
|
---|
1580 | break;
|
---|
1581 | case (DHCP_OPTION_SUBNET_MASK):
|
---|
1582 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
---|
1583 | decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
|
---|
1584 | break;
|
---|
1585 | case (DHCP_OPTION_ROUTER):
|
---|
1586 | decode_len = 4; /* only copy the first given router */
|
---|
1587 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
---|
1588 | decode_idx = DHCP_OPTION_IDX_ROUTER;
|
---|
1589 | break;
|
---|
1590 | #if LWIP_DHCP_PROVIDE_DNS_SERVERS
|
---|
1591 | case (DHCP_OPTION_DNS_SERVER):
|
---|
1592 | /* special case: there might be more than one server */
|
---|
1593 | LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
|
---|
1594 | /* limit number of DNS servers */
|
---|
1595 | decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
|
---|
1596 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
---|
1597 | decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
|
---|
1598 | break;
|
---|
1599 | #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
|
---|
1600 | case (DHCP_OPTION_LEASE_TIME):
|
---|
1601 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
---|
1602 | decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
|
---|
1603 | break;
|
---|
1604 | #if LWIP_DHCP_GET_NTP_SRV
|
---|
1605 | case (DHCP_OPTION_NTP):
|
---|
1606 | /* special case: there might be more than one server */
|
---|
1607 | LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
|
---|
1608 | /* limit number of NTP servers */
|
---|
1609 | decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS);
|
---|
1610 | LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
|
---|
1611 | decode_idx = DHCP_OPTION_IDX_NTP_SERVER;
|
---|
1612 | break;
|
---|
1613 | #endif /* LWIP_DHCP_GET_NTP_SRV*/
|
---|
1614 | case (DHCP_OPTION_OVERLOAD):
|
---|
1615 | LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
|
---|
1616 | /* decode overload only in options, not in file/sname: invalid packet */
|
---|
1617 | LWIP_ERROR("overload in file/sname", options_idx == DHCP_OPTIONS_OFS, return ERR_VAL;);
|
---|
1618 | decode_idx = DHCP_OPTION_IDX_OVERLOAD;
|
---|
1619 | break;
|
---|
1620 | case (DHCP_OPTION_MESSAGE_TYPE):
|
---|
1621 | LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
|
---|
1622 | decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
|
---|
1623 | break;
|
---|
1624 | case (DHCP_OPTION_SERVER_ID):
|
---|
1625 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
---|
1626 | decode_idx = DHCP_OPTION_IDX_SERVER_ID;
|
---|
1627 | break;
|
---|
1628 | case (DHCP_OPTION_T1):
|
---|
1629 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
---|
1630 | decode_idx = DHCP_OPTION_IDX_T1;
|
---|
1631 | break;
|
---|
1632 | case (DHCP_OPTION_T2):
|
---|
1633 | LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
|
---|
1634 | decode_idx = DHCP_OPTION_IDX_T2;
|
---|
1635 | break;
|
---|
1636 | default:
|
---|
1637 | decode_len = 0;
|
---|
1638 | LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op));
|
---|
1639 | LWIP_HOOK_DHCP_PARSE_OPTION(ip_current_netif(), dhcp, dhcp->state, msg_in,
|
---|
1640 | dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) ? (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) : 0,
|
---|
1641 | op, len, q, val_offset);
|
---|
1642 | break;
|
---|
1643 | }
|
---|
1644 | if (op == DHCP_OPTION_PAD) {
|
---|
1645 | offset++;
|
---|
1646 | } else {
|
---|
1647 | if (offset + len + 2 > 0xFFFF) {
|
---|
1648 | /* overflow */
|
---|
1649 | return ERR_BUF;
|
---|
1650 | }
|
---|
1651 | offset = (u16_t)(offset + len + 2);
|
---|
1652 | if (decode_len > 0) {
|
---|
1653 | u32_t value = 0;
|
---|
1654 | u16_t copy_len;
|
---|
1655 | decode_next:
|
---|
1656 | LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
|
---|
1657 | if (!dhcp_option_given(dhcp, decode_idx)) {
|
---|
1658 | copy_len = LWIP_MIN(decode_len, 4);
|
---|
1659 | if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) {
|
---|
1660 | return ERR_BUF;
|
---|
1661 | }
|
---|
1662 | if (decode_len > 4) {
|
---|
1663 | /* decode more than one u32_t */
|
---|
1664 | u16_t next_val_offset;
|
---|
1665 | LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
|
---|
1666 | dhcp_got_option(dhcp, decode_idx);
|
---|
1667 | dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value));
|
---|
1668 | decode_len = (u8_t)(decode_len - 4);
|
---|
1669 | next_val_offset = (u16_t)(val_offset + 4);
|
---|
1670 | if (next_val_offset < val_offset) {
|
---|
1671 | /* overflow */
|
---|
1672 | return ERR_BUF;
|
---|
1673 | }
|
---|
1674 | val_offset = next_val_offset;
|
---|
1675 | decode_idx++;
|
---|
1676 | goto decode_next;
|
---|
1677 | } else if (decode_len == 4) {
|
---|
1678 | value = lwip_ntohl(value);
|
---|
1679 | } else {
|
---|
1680 | LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
|
---|
1681 | value = ((u8_t *)&value)[0];
|
---|
1682 | }
|
---|
1683 | dhcp_got_option(dhcp, decode_idx);
|
---|
1684 | dhcp_set_option_value(dhcp, decode_idx, value);
|
---|
1685 | }
|
---|
1686 | }
|
---|
1687 | }
|
---|
1688 | if (offset >= q->len) {
|
---|
1689 | offset = (u16_t)(offset - q->len);
|
---|
1690 | offset_max = (u16_t)(offset_max - q->len);
|
---|
1691 | if (offset < offset_max) {
|
---|
1692 | q = q->next;
|
---|
1693 | LWIP_ERROR("next pbuf was null", q != NULL, return ERR_VAL;);
|
---|
1694 | options = (u8_t *)q->payload;
|
---|
1695 | } else {
|
---|
1696 | /* We've run out of bytes, probably no end marker. Don't proceed. */
|
---|
1697 | return ERR_BUF;
|
---|
1698 | }
|
---|
1699 | }
|
---|
1700 | }
|
---|
1701 | /* is this an overloaded message? */
|
---|
1702 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
|
---|
1703 | u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
|
---|
1704 | dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
|
---|
1705 | if (overload == DHCP_OVERLOAD_FILE) {
|
---|
1706 | parse_file_as_options = 1;
|
---|
1707 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
|
---|
1708 | } else if (overload == DHCP_OVERLOAD_SNAME) {
|
---|
1709 | parse_sname_as_options = 1;
|
---|
1710 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
|
---|
1711 | } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
|
---|
1712 | parse_sname_as_options = 1;
|
---|
1713 | parse_file_as_options = 1;
|
---|
1714 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
|
---|
1715 | } else {
|
---|
1716 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
|
---|
1717 | }
|
---|
1718 | }
|
---|
1719 | if (parse_file_as_options) {
|
---|
1720 | /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
|
---|
1721 | parse_file_as_options = 0;
|
---|
1722 | options_idx = DHCP_FILE_OFS;
|
---|
1723 | options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
|
---|
1724 | #if LWIP_DHCP_BOOTP_FILE
|
---|
1725 | file_overloaded = 1;
|
---|
1726 | #endif
|
---|
1727 | goto again;
|
---|
1728 | } else if (parse_sname_as_options) {
|
---|
1729 | parse_sname_as_options = 0;
|
---|
1730 | options_idx = DHCP_SNAME_OFS;
|
---|
1731 | options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
|
---|
1732 | goto again;
|
---|
1733 | }
|
---|
1734 | #if LWIP_DHCP_BOOTP_FILE
|
---|
1735 | if (!file_overloaded) {
|
---|
1736 | /* only do this for ACK messages */
|
---|
1737 | if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
|
---|
1738 | (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
|
---|
1739 | /* copy bootp file name, don't care for sname (server hostname) */
|
---|
1740 | if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS) != (DHCP_FILE_LEN-1)) {
|
---|
1741 | return ERR_BUF;
|
---|
1742 | }
|
---|
1743 | /* make sure the string is really NULL-terminated */
|
---|
1744 | dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
|
---|
1745 | }
|
---|
1746 | #endif /* LWIP_DHCP_BOOTP_FILE */
|
---|
1747 | return ERR_OK;
|
---|
1748 | }
|
---|
1749 |
|
---|
1750 | /**
|
---|
1751 | * If an incoming DHCP message is in response to us, then trigger the state machine
|
---|
1752 | */
|
---|
1753 | static void
|
---|
1754 | dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
---|
1755 | {
|
---|
1756 | struct netif *netif = ip_current_input_netif();
|
---|
1757 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1758 | struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
|
---|
1759 | u8_t msg_type;
|
---|
1760 | u8_t i;
|
---|
1761 | struct dhcp_msg *msg_in;
|
---|
1762 |
|
---|
1763 | LWIP_UNUSED_ARG(arg);
|
---|
1764 |
|
---|
1765 | /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */
|
---|
1766 | if ((dhcp == NULL) || (dhcp->pcb_allocated == 0)) {
|
---|
1767 | goto free_pbuf_and_return;
|
---|
1768 | }
|
---|
1769 |
|
---|
1770 | LWIP_ASSERT("invalid server address type", IP_IS_V4(addr));
|
---|
1771 |
|
---|
1772 | 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,
|
---|
1773 | 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));
|
---|
1774 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
|
---|
1775 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
|
---|
1776 | /* prevent warnings about unused arguments */
|
---|
1777 | LWIP_UNUSED_ARG(pcb);
|
---|
1778 | LWIP_UNUSED_ARG(addr);
|
---|
1779 | LWIP_UNUSED_ARG(port);
|
---|
1780 |
|
---|
1781 | if (p->len < DHCP_MIN_REPLY_LEN) {
|
---|
1782 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
|
---|
1783 | goto free_pbuf_and_return;
|
---|
1784 | }
|
---|
1785 |
|
---|
1786 | if (reply_msg->op != DHCP_BOOTREPLY) {
|
---|
1787 | 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));
|
---|
1788 | goto free_pbuf_and_return;
|
---|
1789 | }
|
---|
1790 | /* iterate through hardware address and match against DHCP message */
|
---|
1791 | for (i = 0; i < netif->hwaddr_len && i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) {
|
---|
1792 | if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
|
---|
1793 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
---|
1794 | ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
|
---|
1795 | (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
|
---|
1796 | goto free_pbuf_and_return;
|
---|
1797 | }
|
---|
1798 | }
|
---|
1799 | /* match transaction ID against what we expected */
|
---|
1800 | if (lwip_ntohl(reply_msg->xid) != dhcp->xid) {
|
---|
1801 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
|
---|
1802 | ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n", lwip_ntohl(reply_msg->xid), dhcp->xid));
|
---|
1803 | goto free_pbuf_and_return;
|
---|
1804 | }
|
---|
1805 | /* option fields could be unfold? */
|
---|
1806 | if (dhcp_parse_reply(p, dhcp) != ERR_OK) {
|
---|
1807 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
---|
1808 | ("problem unfolding DHCP message - too short on memory?\n"));
|
---|
1809 | goto free_pbuf_and_return;
|
---|
1810 | }
|
---|
1811 |
|
---|
1812 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
|
---|
1813 | /* obtain pointer to DHCP message type */
|
---|
1814 | if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
|
---|
1815 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
|
---|
1816 | goto free_pbuf_and_return;
|
---|
1817 | }
|
---|
1818 |
|
---|
1819 | msg_in = (struct dhcp_msg *)p->payload;
|
---|
1820 | /* read DHCP message type */
|
---|
1821 | msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
|
---|
1822 | /* message type is DHCP ACK? */
|
---|
1823 | if (msg_type == DHCP_ACK) {
|
---|
1824 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
|
---|
1825 | /* in requesting state? */
|
---|
1826 | if (dhcp->state == DHCP_STATE_REQUESTING) {
|
---|
1827 | dhcp_handle_ack(netif, msg_in);
|
---|
1828 | #if DHCP_DOES_ARP_CHECK
|
---|
1829 | if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
|
---|
1830 | /* check if the acknowledged lease address is already in use */
|
---|
1831 | dhcp_check(netif);
|
---|
1832 | } else {
|
---|
1833 | /* bind interface to the acknowledged lease address */
|
---|
1834 | dhcp_bind(netif);
|
---|
1835 | }
|
---|
1836 | #else
|
---|
1837 | /* bind interface to the acknowledged lease address */
|
---|
1838 | dhcp_bind(netif);
|
---|
1839 | #endif
|
---|
1840 | }
|
---|
1841 | /* already bound to the given lease address? */
|
---|
1842 | else if ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) ||
|
---|
1843 | (dhcp->state == DHCP_STATE_RENEWING)) {
|
---|
1844 | dhcp_handle_ack(netif, msg_in);
|
---|
1845 | dhcp_bind(netif);
|
---|
1846 | }
|
---|
1847 | }
|
---|
1848 | /* received a DHCP_NAK in appropriate state? */
|
---|
1849 | else if ((msg_type == DHCP_NAK) &&
|
---|
1850 | ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REQUESTING) ||
|
---|
1851 | (dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING ))) {
|
---|
1852 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
|
---|
1853 | dhcp_handle_nak(netif);
|
---|
1854 | }
|
---|
1855 | /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */
|
---|
1856 | else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_STATE_SELECTING)) {
|
---|
1857 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n"));
|
---|
1858 | /* remember offered lease */
|
---|
1859 | dhcp_handle_offer(netif, msg_in);
|
---|
1860 | }
|
---|
1861 |
|
---|
1862 | free_pbuf_and_return:
|
---|
1863 | pbuf_free(p);
|
---|
1864 | }
|
---|
1865 |
|
---|
1866 | /**
|
---|
1867 | * Create a DHCP request, fill in common headers
|
---|
1868 | *
|
---|
1869 | * @param netif the netif under DHCP control
|
---|
1870 | * @param dhcp dhcp control struct
|
---|
1871 | * @param message_type message type of the request
|
---|
1872 | */
|
---|
1873 | static struct pbuf *
|
---|
1874 | dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type, u16_t *options_out_len)
|
---|
1875 | {
|
---|
1876 | u16_t i;
|
---|
1877 | struct pbuf *p_out;
|
---|
1878 | struct dhcp_msg *msg_out;
|
---|
1879 | u16_t options_out_len_loc;
|
---|
1880 |
|
---|
1881 | #ifndef DHCP_GLOBAL_XID
|
---|
1882 | /** default global transaction identifier starting value (easy to match
|
---|
1883 | * with a packet analyser). We simply increment for each new request.
|
---|
1884 | * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
|
---|
1885 | * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
|
---|
1886 | #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
|
---|
1887 | static u32_t xid;
|
---|
1888 | #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
---|
1889 | static u32_t xid = 0xABCD0000;
|
---|
1890 | #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
---|
1891 | #else
|
---|
1892 | if (!xid_initialised) {
|
---|
1893 | xid = DHCP_GLOBAL_XID;
|
---|
1894 | xid_initialised = !xid_initialised;
|
---|
1895 | }
|
---|
1896 | #endif
|
---|
1897 | LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return NULL;);
|
---|
1898 | LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return NULL;);
|
---|
1899 | p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
|
---|
1900 | if (p_out == NULL) {
|
---|
1901 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
---|
1902 | ("dhcp_create_msg(): could not allocate pbuf\n"));
|
---|
1903 | return NULL;
|
---|
1904 | }
|
---|
1905 | LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
|
---|
1906 | (p_out->len >= sizeof(struct dhcp_msg)));
|
---|
1907 |
|
---|
1908 | /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */
|
---|
1909 | if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) {
|
---|
1910 | /* reuse transaction identifier in retransmissions */
|
---|
1911 | if (dhcp->tries == 0) {
|
---|
1912 | #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
|
---|
1913 | xid = LWIP_RAND();
|
---|
1914 | #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
---|
1915 | xid++;
|
---|
1916 | #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
|
---|
1917 | }
|
---|
1918 | dhcp->xid = xid;
|
---|
1919 | }
|
---|
1920 | LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
|
---|
1921 | ("transaction id xid(%"X32_F")\n", xid));
|
---|
1922 |
|
---|
1923 | msg_out = (struct dhcp_msg *)p_out->payload;
|
---|
1924 | memset(msg_out, 0, sizeof(struct dhcp_msg));
|
---|
1925 |
|
---|
1926 | msg_out->op = DHCP_BOOTREQUEST;
|
---|
1927 | /* @todo: make link layer independent */
|
---|
1928 | msg_out->htype = LWIP_IANA_HWTYPE_ETHERNET;
|
---|
1929 | msg_out->hlen = netif->hwaddr_len;
|
---|
1930 | msg_out->xid = lwip_htonl(dhcp->xid);
|
---|
1931 | /* we don't need the broadcast flag since we can receive unicast traffic
|
---|
1932 | before being fully configured! */
|
---|
1933 | /* set ciaddr to netif->ip_addr based on message_type and state */
|
---|
1934 | if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_RELEASE) ||
|
---|
1935 | ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */
|
---|
1936 | ((dhcp->state == DHCP_STATE_RENEWING) || dhcp->state == DHCP_STATE_REBINDING))) {
|
---|
1937 | ip4_addr_copy(msg_out->ciaddr, *netif_ip4_addr(netif));
|
---|
1938 | }
|
---|
1939 | for (i = 0; i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) {
|
---|
1940 | /* copy netif hardware address (padded with zeroes through memset already) */
|
---|
1941 | msg_out->chaddr[i] = netif->hwaddr[i];
|
---|
1942 | }
|
---|
1943 | msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
|
---|
1944 | /* Add option MESSAGE_TYPE */
|
---|
1945 | options_out_len_loc = dhcp_option(0, msg_out->options, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
|
---|
1946 | options_out_len_loc = dhcp_option_byte(options_out_len_loc, msg_out->options, message_type);
|
---|
1947 | if (options_out_len) {
|
---|
1948 | *options_out_len = options_out_len_loc;
|
---|
1949 | }
|
---|
1950 | return p_out;
|
---|
1951 | }
|
---|
1952 |
|
---|
1953 | /**
|
---|
1954 | * Add a DHCP message trailer
|
---|
1955 | *
|
---|
1956 | * Adds the END option to the DHCP message, and if
|
---|
1957 | * necessary, up to three padding bytes.
|
---|
1958 | */
|
---|
1959 | static void
|
---|
1960 | dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out)
|
---|
1961 | {
|
---|
1962 | options[options_out_len++] = DHCP_OPTION_END;
|
---|
1963 | /* packet is too small, or not 4 byte aligned? */
|
---|
1964 | while (((options_out_len < DHCP_MIN_OPTIONS_LEN) || (options_out_len & 3)) &&
|
---|
1965 | (options_out_len < DHCP_OPTIONS_LEN)) {
|
---|
1966 | /* add a fill/padding byte */
|
---|
1967 | options[options_out_len++] = 0;
|
---|
1968 | }
|
---|
1969 | /* shrink the pbuf to the actual content length */
|
---|
1970 | pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + options_out_len));
|
---|
1971 | }
|
---|
1972 |
|
---|
1973 | /** check if DHCP supplied netif->ip_addr
|
---|
1974 | *
|
---|
1975 | * @param netif the netif to check
|
---|
1976 | * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING),
|
---|
1977 | * 0 otherwise
|
---|
1978 | */
|
---|
1979 | u8_t
|
---|
1980 | dhcp_supplied_address(const struct netif *netif)
|
---|
1981 | {
|
---|
1982 | if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) {
|
---|
1983 | struct dhcp *dhcp = netif_dhcp_data(netif);
|
---|
1984 | return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING) ||
|
---|
1985 | (dhcp->state == DHCP_STATE_REBINDING);
|
---|
1986 | }
|
---|
1987 | return 0;
|
---|
1988 | }
|
---|
1989 |
|
---|
1990 | #endif /* LWIP_IPV4 && LWIP_DHCP */
|
---|