• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if LWIP_NAT64
83 #include "lwip/nat64_v4_dhcpc.h"
84 #include "lwip/nat64_addr.h"
85 #include "lwip/nat64.h"
86 #endif
87 #include <string.h>
88 
89 #ifdef LWIP_HOOK_FILENAME
90 #include LWIP_HOOK_FILENAME
91 #endif
92 #ifndef LWIP_HOOK_DHCP_APPEND_OPTIONS
93 #define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr)
94 #endif
95 #ifndef LWIP_HOOK_DHCP_PARSE_OPTION
96 #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0)
97 #endif
98 
99 /** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using
100  * LWIP_RAND() (this overrides DHCP_GLOBAL_XID)
101  */
102 #ifndef DHCP_CREATE_RAND_XID
103 #define DHCP_CREATE_RAND_XID        1
104 #endif
105 
106 #ifndef DHCP_REQUEST_TIMEOUT_DEFAULT
107 #define DHCP_REQUEST_TIMEOUT_DEFAULT   10  // 10 second
108 #endif
109 
110 /** Default for DHCP_GLOBAL_XID is 0xABCD0000
111  * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
112  *  \#define DHCP_GLOBAL_XID_HEADER "stdlib.h"
113  *  \#define DHCP_GLOBAL_XID rand()
114  */
115 #ifdef DHCP_GLOBAL_XID_HEADER
116 #include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
117 #endif
118 
119 /** Holds the decoded option values, only valid while in dhcp_recv.
120     @todo: move this into struct dhcp? */
121 u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
122 /** Holds a flag which option was received and is contained in dhcp_rx_options_val,
123     only valid while in dhcp_recv.
124     @todo: move this into struct dhcp? */
125 u8_t  dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
126 
127 static u8_t dhcp_discover_request_options[] = {
128   DHCP_OPTION_SUBNET_MASK,
129   DHCP_OPTION_ROUTER,
130   DHCP_OPTION_BROADCAST
131 #if LWIP_DHCP_PROVIDE_DNS_SERVERS
132   , DHCP_OPTION_DNS_SERVER
133 #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
134 #if LWIP_DHCP_GET_NTP_SRV
135   , DHCP_OPTION_NTP
136 #endif /* LWIP_DHCP_GET_NTP_SRV */
137 };
138 
139 #ifdef DHCP_GLOBAL_XID
140 static u32_t xid;
141 static u8_t xid_initialised;
142 #endif /* DHCP_GLOBAL_XID */
143 
144 #if LWIP_DHCP_VENDOR_CLASS_IDENTIFIER
145 static struct vci_info g_vci_info = {{0}, 0};
146 #endif /* LWIP_DHCP_VENDOR_CLASS_IDENTIFIER */
147 
148 #define dhcp_option_given(dhcp, idx)          (dhcp_rx_options_given[idx] != 0)
149 #define dhcp_got_option(dhcp, idx)            (dhcp_rx_options_given[idx] = 1)
150 #define dhcp_clear_option(dhcp, idx)          (dhcp_rx_options_given[idx] = 0)
151 #define dhcp_clear_all_options(dhcp)          (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given)))
152 #define dhcp_get_option_value(dhcp, idx)      (dhcp_rx_options_val[idx])
153 #define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val))
154 
155 static struct udp_pcb *dhcp_pcb;
156 #if LWIP_DHCP_SUBSTITUTE
157 static u16_t dhcp_pcb_refcount;
158 #define DHCP_REF_F "hu"
159 
160 #if LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS
161 static u16_t g_dhcp_max_concurrent_num = LWIP_DHCP_MAX_CONCURRENT_REQUESTS_NUM;
162 #endif
163 #else
164 static u8_t dhcp_pcb_refcount;
165 #define DHCP_REF_F "hhu"
166 #endif
167 
168 static err_t dhcp_release_client(struct netif *netif, struct dhcp_client *dhcp);
169 static err_t dhcp_renew_client(struct netif *netif, struct dhcp_client *dhcp);
170 static void dhcp_stop_client(struct netif *netif, struct dhcp_client *dhcp);
171 #if LWIP_DHCP_SUBSTITUTE
172 static void dhcp_substitute_clients_restart(struct netif *netif, struct dhcp_client *dhcp);
173 static s32_t dhcp_addr_clients_check(struct dhcp *netif_dhcp, const ip4_addr_t *ipaddr);
174 #if LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS
175 static u8_t dhcp_client_request_processing(u8_t state);
176 static void dhcp_concurrent_limit_wait_timeout(struct netif *netif, struct dhcp_client *dhcp);
177 static void dhcp_concurrent_num_update(struct dhcp_client *dhcp);
178 static err_t dhcp_concurrent_start_client(struct dhcp_client *dhcp);
179 static void dhcp_concurrent_stop_client(struct dhcp_client *dhcp);
180 static void dhcp_concurrent_start_next_client(struct netif *netif, u8_t all);
181 #endif
182 #endif /* LWIP_DHCP_SUBSTITUTE */
183 
184 #if LWIP_DHCP_SUBSTITUTE_MMBR
185 static void dhcp_release_check(struct netif *netif, struct dhcp_client *dhcp);
186 #endif
187 
188 /* DHCP client state machine functions */
189 static err_t dhcp_discover(struct netif *netif, struct dhcp_client *dhcp);
190 static err_t dhcp_select(struct netif *netif, struct dhcp_client *dhcp);
191 static void dhcp_bind(struct netif *netif, struct dhcp_client *dhcp);
192 #if LWIP_ARP
193 static void dhcp_announce(struct netif *netif, struct dhcp_client *dhcp);
194 #endif
195 #if DHCP_DOES_ARP_CHECK
196 static err_t dhcp_decline(struct netif *netif, struct dhcp_client *dhcp);
197 #endif /* DHCP_DOES_ARP_CHECK */
198 static err_t dhcp_rebind(struct netif *netif, struct dhcp_client *dhcp);
199 static err_t dhcp_reboot(struct netif *netif);
200 static void dhcp_set_state(struct dhcp_client *dhcp, u8_t new_state);
201 
202 /* receive, unfold, parse and free incoming messages */
203 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
204 
205 /* set the DHCP timers */
206 static void dhcp_timeout(struct netif *netif, struct dhcp_client *dhcp);
207 static void dhcp_t1_timeout(struct netif *netif, struct dhcp_client *dhcp);
208 static void dhcp_t2_timeout(struct netif *netif, struct dhcp_client *dhcp);
209 
210 /* build outgoing messages */
211 /* create a DHCP message, fill in common headers */
212 static err_t dhcp_create_msg(struct netif *netif, struct dhcp_client *dhcp, u8_t message_type, u16_t *options_out_len);
213 /* free a DHCP request */
214 static void dhcp_delete_msg(struct dhcp_client *dhcp);
215 /* add a DHCP option (type, then length in bytes) */
216 static u16_t dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len);
217 /* add option values */
218 static u16_t dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value);
219 static u16_t dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value);
220 static u16_t dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value);
221 #if LWIP_NETIF_HOSTNAME
222 static u16_t dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif);
223 #endif /* LWIP_NETIF_HOSTNAME */
224 
225 #if LWIP_DHCP_VENDOR_CLASS_IDENTIFIER
226 static u16_t dhcp_option_vci(u16_t options_out_len, u8_t *options, const struct netif *netif);
227 #endif /* LWIP_DHCP_VENDOR_CLASS_IDENTIFIER */
228 
229 /* always add the DHCP options trailer to end and pad */
230 static void dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out);
231 
232 /** Ensure DHCP PCB is allocated and bound */
233 static err_t
dhcp_inc_pcb_refcount(u8_t ifindex)234 dhcp_inc_pcb_refcount(u8_t ifindex)
235 {
236   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_inc_pcb_refcount:enter %"DHCP_REF_F"\n", dhcp_pcb_refcount);
237   if (dhcp_pcb_refcount == 0) {
238     LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL);
239 
240     /* allocate UDP PCB */
241     dhcp_pcb = udp_new();
242 
243     if (dhcp_pcb == NULL) {
244       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, "dhcp_inc_pcb_refcount:udp new failed\n");
245       return ERR_MEM;
246     }
247 
248 #if LWIP_SO_PRIORITY
249     dhcp_pcb->priority = LWIP_PKT_PRIORITY_DHCP;
250 #endif /* LWIP_SO_PRIORITY */
251 
252     ip_set_option(dhcp_pcb, SOF_BROADCAST);
253     LWIP_UNUSED_ARG(ifindex);
254 
255     /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */
256     udp_bind(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT);
257     udp_connect(dhcp_pcb, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
258     udp_recv(dhcp_pcb, dhcp_recv, NULL);
259   }
260 
261   dhcp_pcb_refcount++;
262   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_inc_pcb_refcount:leave %"DHCP_REF_F"\n", dhcp_pcb_refcount);
263 
264   return ERR_OK;
265 }
266 
267 /** Free DHCP PCB if the last netif stops using it */
268 static void
dhcp_dec_pcb_refcount(void)269 dhcp_dec_pcb_refcount(void)
270 {
271   LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0));
272   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_dec_pcb_refcount:enter %"DHCP_REF_F"\n", dhcp_pcb_refcount);
273   dhcp_pcb_refcount--;
274 
275   if (dhcp_pcb_refcount == 0) {
276     udp_remove(dhcp_pcb);
277     dhcp_pcb = NULL;
278   }
279   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_dec_pcb_refcount:leave %"DHCP_REF_F"\n", dhcp_pcb_refcount);
280 }
281 
282 static void
dhcp_get_client_ip(u32_t * cli_ip,struct dhcp_client * dhcp,struct dhcp_state * dhcp_state)283 dhcp_get_client_ip(u32_t *cli_ip, struct dhcp_client *dhcp, struct dhcp_state *dhcp_state)
284 {
285   if (ip4_addr_isany_val(dhcp->relay_ip)) {
286     DHCP_HOST_TO_IP(*cli_ip, ip_2_ip4(&dhcp->server_ip_addr)->addr, dhcp->offered_sn_mask.addr,
287                     dhcp_state->offered_ip_addr);
288   } else {
289     DHCP_HOST_TO_IP(*cli_ip, dhcp->relay_ip.addr, dhcp->offered_sn_mask.addr,
290                     dhcp_state->offered_ip_addr);
291   }
292 }
293 
294 static void
dhcp_ip_to_mask(ip4_addr_t * server_ip_addr,ip4_addr_t * sn_mask)295 dhcp_ip_to_mask(ip4_addr_t *server_ip_addr, ip4_addr_t *sn_mask)
296 {
297   u8_t first_octet = ip4_addr1(server_ip_addr);
298   if (first_octet <= IPV4_ADDRESS_PREFIX_CLASS_A) {
299     ip4_addr_set_u32(sn_mask, PP_HTONL(0xff000000UL));
300   } else if (first_octet >= IPV4_ADDRESS_PREFIX_CLASS_C) {
301     ip4_addr_set_u32(sn_mask, PP_HTONL(0xffffff00UL));
302   } else {
303     ip4_addr_set_u32(sn_mask, PP_HTONL(0xffff0000UL));
304   }
305 
306   return;
307 }
308 
309 static err_t
dhcp_mac_to_idx(struct netif * netif,const u8_t * hwaddr,u8_t hwaddr_len,dhcp_num_t * mac_idx)310 dhcp_mac_to_idx(struct netif *netif, const u8_t *hwaddr, u8_t hwaddr_len, dhcp_num_t *mac_idx)
311 {
312   if ((netif->hwaddr_len == hwaddr_len) && (memcmp(netif->hwaddr, hwaddr, hwaddr_len) == 0)) {
313     *mac_idx = LWIP_DHCP_NATIVE_IDX;
314     return ERR_OK;
315   }
316 
317 #if LWIP_DHCP_SUBSTITUTE && LWIP_NAT64
318   return nat64_entry_mac_to_idx(hwaddr, hwaddr_len, mac_idx);
319 #else
320   return ERR_VAL;
321 #endif /* LWIP_DHCP_SUBSTITUTE && LWIP_NAT64 */
322 }
323 
324 err_t
dhcp_idx_to_mac(struct netif * netif,dhcp_num_t mac_idx,u8_t * hwaddr,u8_t * hwaddr_len)325 dhcp_idx_to_mac(struct netif *netif, dhcp_num_t mac_idx,
326                 u8_t *hwaddr, u8_t *hwaddr_len)
327 {
328   if ((hwaddr == NULL) || (hwaddr_len == NULL)) {
329     return ERR_VAL;
330   }
331   if (mac_idx == LWIP_DHCP_NATIVE_IDX) {
332     if (memcpy_s(hwaddr, NETIF_MAX_HWADDR_LEN, netif->hwaddr, NETIF_MAX_HWADDR_LEN) != EOK) {
333       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_idx_to_mac:memcpy failed\n"));
334       return ERR_MEM;
335     }
336     *hwaddr_len = netif->hwaddr_len;
337     return ERR_OK;
338   }
339 
340 #if LWIP_DHCP_SUBSTITUTE && LWIP_NAT64
341   u8_t hw_len = NETIF_MAX_HWADDR_LEN;
342   if (nat64_entry_idx_to_mac(mac_idx, hwaddr, &hw_len) == ERR_OK) {
343     *hwaddr_len = hw_len;
344     return ERR_OK;
345   }
346 #endif /* LWIP_DHCP_SUBSTITUTE && LWIP_NAT64 */
347   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_idx_to_mac:not find in nat64\n"));
348   return ERR_VAL;
349 }
350 
351 static err_t
dhcp_client_find_by_mac_idx(struct dhcp_client * dhcp,dhcp_num_t mac_idx,dhcp_num_t * cli_idx)352 dhcp_client_find_by_mac_idx(struct dhcp_client *dhcp, dhcp_num_t mac_idx, dhcp_num_t *cli_idx)
353 {
354   int i;
355 
356   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
357     if ((dhcp->states)[i].idx == mac_idx) {
358       *cli_idx = (dhcp_num_t)i;
359       return ERR_OK;
360     }
361   }
362 
363   return ERR_VAL;
364 }
365 
366 static err_t
dhcp_client_state_new(struct dhcp_client * dhcp,dhcp_num_t mac_idx,dhcp_num_t * cli_idx)367 dhcp_client_state_new(struct dhcp_client *dhcp, dhcp_num_t mac_idx, dhcp_num_t *cli_idx)
368 {
369   int i;
370 
371   if (dhcp->cli_cnt == DHCP_CLIENT_NUM) {
372     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_client_state_new:max cnt\n"));
373     return ERR_VAL;
374   }
375 
376   for (i = 1; i < DHCP_CLIENT_NUM; i++) {
377     if ((dhcp->states)[i].idx == 0) {
378       *cli_idx = (dhcp_num_t)i;
379       (dhcp->states)[i].idx = mac_idx;
380       return ERR_OK;
381     }
382   }
383 
384   return ERR_VAL;
385 }
386 
387 static void
dhcp_clients_count_update(struct dhcp_client * dhcp)388 dhcp_clients_count_update(struct dhcp_client *dhcp)
389 {
390   int i;
391   dhcp_num_t cnt = 0;
392 
393   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
394     if ((dhcp->states)[i].hwaddr_len != 0) {
395       cnt++;
396     }
397   }
398 
399   dhcp->cli_cnt = cnt;
400   return;
401 }
402 
403 /**
404  * Back-off the DHCP client (because of a received NAK response).
405  *
406  * Back-off the DHCP client because of a received NAK. Receiving a
407  * NAK means the client asked for something non-sensible, for
408  * example when it tries to renew a lease obtained on another network.
409  *
410  * We clear any existing set IP address and restart DHCP negotiation
411  * afresh (as per RFC2131 3.2.3).
412  *
413  * @param netif the netif under DHCP control
414  */
415 static void
dhcp_handle_nak(struct netif * netif,struct dhcp_client * dhcp)416 dhcp_handle_nak(struct netif *netif, struct dhcp_client *dhcp)
417 {
418   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %s%"U16_F"\n",
419               (void *)netif, netif->name, (u16_t)netif->num));
420   /* Change to a defined state - set this before assigning the address
421      to ensure the callback can use dhcp_supplied_address() */
422   dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
423   /* remove IP address from interface (must no longer be used, as per RFC2131) */
424   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
425     (void)netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
426   }
427   /* We can immediately restart discovery */
428   (void)dhcp_discover(netif, dhcp);
429 }
430 
431 #if DHCP_DOES_ARP_CHECK
432 /**
433  * Checks if the offered IP address is already in use.
434  *
435  * It does so by sending an ARP request for the offered address and
436  * entering CHECKING state. If no ARP reply is received within a small
437  * interval, the address is assumed to be free for use by us.
438  *
439  * @param netif the netif under DHCP control
440  */
441 static void
dhcp_check(struct netif * netif,struct dhcp_client * dhcp)442 dhcp_check(struct netif *netif, struct dhcp_client *dhcp)
443 {
444   err_t result;
445   u16_t msecs;
446   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
447   ip4_addr_t cli_ip;
448   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %s\n", (void *)netif, netif->name));
449   dhcp_set_state(dhcp, DHCP_STATE_CHECKING);
450   dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
451   /* create an ARP query for the offered IP address, expecting that no host
452      responds, as the IP address should not be in use. */
453   result = etharp_query(netif, &cli_ip, NULL);
454   if (result != ERR_OK) {
455     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n"));
456   }
457   if (dhcp_state->tries < 255) {
458     dhcp_state->tries++;
459   }
460   msecs = 500;
461   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
462   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
463 }
464 #endif /* DHCP_DOES_ARP_CHECK */
465 
466 /**
467  * Remember the configuration offered by a DHCP server.
468  *
469  * @param netif the netif under DHCP control
470  */
471 static void
dhcp_handle_offer(struct netif * netif,struct dhcp_client * dhcp)472 dhcp_handle_offer(struct netif *netif, struct dhcp_client *dhcp)
473 {
474   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
475   ip4_addr_t cli_ip;
476 #if LWIP_DHCP_SUBSTITUTE_MMBR
477   dhcp_num_t offered_ip_addr;
478 #endif
479   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %s%"U16_F"\n",
480               (void *)netif, netif->name, (u16_t)netif->num));
481   /* obtain the server address */
482   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
483     dhcp_state->request_timeout = 0; /* stop timer */
484 
485     ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
486     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
487                 ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
488     if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
489       ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
490     } else {
491       dhcp_ip_to_mask(ip_2_ip4(&dhcp->server_ip_addr), &dhcp->offered_sn_mask);
492     }
493     /* remember offered address */
494     ip4_addr_copy(cli_ip, dhcp->msg_in->yiaddr);
495     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n",
496                 ip4_addr_get_u32(&cli_ip)));
497 #if LWIP_DHCP_SUBSTITUTE_MMBR
498     offered_ip_addr = dhcp_state->offered_ip_addr;
499 #endif
500     DHCP_IP_TO_HOST(dhcp_state->offered_ip_addr, cli_ip.addr, dhcp->offered_sn_mask.addr);
501 #if LWIP_DHCP_SUBSTITUTE_MMBR
502     /* if offered IP is not same with the preferred IP, should do duplicate IP check */
503     if ((dhcp_state->addr_not_dup_check == lwIP_TRUE) && offered_ip_addr != dhcp_state->offered_ip_addr) {
504       dhcp_state->addr_not_dup_check = lwIP_FALSE;
505     }
506 #endif
507     ip4_addr_copy(dhcp->relay_ip, dhcp->msg_in->giaddr);
508     (void)dhcp_select(netif, dhcp);
509   } else {
510     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
511                 ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void *)netif));
512   }
513 }
514 
515 static void
dhcp_fill_options(struct netif * netif,struct dhcp_client * dhcp,u8_t message_type,u32_t opt_flags,u16_t * opts_len)516 dhcp_fill_options(struct netif *netif, struct dhcp_client *dhcp, u8_t message_type, u32_t opt_flags, u16_t *opts_len)
517 {
518   u8_t i;
519   ip4_addr_t cli_ip;
520   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
521 
522   if (opt_flags & GEN_FLG(MAX_MSG_SIZE)) {
523     *opts_len = dhcp_option(*opts_len, dhcp->msg_out->options, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
524     u16_t val = (dhcp_state->state == DHCP_STATE_REBOOTING) ?
525                 (u16_t)DHCP_MAX_MSG_LEN_MIN_REQUIRED : DHCP_MAX_MSG_LEN(netif);
526     *opts_len = dhcp_option_short(*opts_len, dhcp->msg_out->options, val);
527   }
528 
529   if (opt_flags & GEN_FLG(REQUESTED_IP)) {
530     /* MUST request the offered IP address */
531     *opts_len = dhcp_option(*opts_len, dhcp->msg_out->options, DHCP_OPTION_REQUESTED_IP, 4);
532     dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
533     *opts_len = dhcp_option_long(*opts_len, dhcp->msg_out->options, lwip_ntohl(ip4_addr_get_u32(&cli_ip)));
534   }
535 
536   *opts_len = dhcp_option(*opts_len, dhcp->msg_out->options, DHCP_OPTION_CLIENT_ID, 1 + dhcp_state->hwaddr_len);
537   *opts_len = dhcp_option_byte(*opts_len, dhcp->msg_out->options, dhcp->msg_out->htype);
538   for (i = 0; i < dhcp_state->hwaddr_len; i++) {
539     *opts_len = dhcp_option_byte(*opts_len, dhcp->msg_out->options, dhcp->hwaddr[i]);
540   }
541 
542   if (opt_flags & GEN_FLG(PARAMETER_REQUEST_LIST)) {
543     *opts_len = dhcp_option(*opts_len, dhcp->msg_out->options, DHCP_OPTION_PARAMETER_REQUEST_LIST,
544                             LWIP_ARRAYSIZE(dhcp_discover_request_options));
545     for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
546       *opts_len = dhcp_option_byte(*opts_len, dhcp->msg_out->options, dhcp_discover_request_options[i]);
547     }
548   }
549 
550 #if LWIP_NETIF_HOSTNAME
551   if ((message_type == DHCP_DISCOVER) ||
552       ((message_type == DHCP_REQUEST) && (dhcp_state->state != DHCP_STATE_REBOOTING))) {
553     *opts_len = dhcp_option_hostname(*opts_len, dhcp->msg_out->options, netif);
554   }
555 #endif /* LWIP_NETIF_HOSTNAME */
556 
557 #if LWIP_DHCP_VENDOR_CLASS_IDENTIFIER
558   if ((message_type != DHCP_DECLINE) && (message_type != DHCP_RELEASE)) {
559     *opts_len = dhcp_option_vci(*opts_len, dhcp->msg_out->options, netif);
560   }
561 #endif /* LWIP_DHCP_VENDOR_CLASS_IDENTIFIER */
562   (void)message_type;
563   LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, DHCP_STATE_REQUESTING, dhcp->msg_out, DHCP_REQUEST, opts_len);
564   dhcp_option_trailer(*opts_len, dhcp->msg_out->options, dhcp->p_out);
565 }
566 
567 /**
568  * Select a DHCP server offer out of all offers.
569  *
570  * Simply select the first offer received.
571  *
572  * @param netif the netif under DHCP control
573  * @return lwIP specific error (see error.h)
574  */
575 static err_t
dhcp_select(struct netif * netif,struct dhcp_client * dhcp)576 dhcp_select(struct netif *netif, struct dhcp_client *dhcp)
577 {
578   err_t result;
579   u16_t msecs;
580   u16_t options_out_len;
581   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
582 #if LWIP_DHCP_REQUEST_UNICAST
583   ip_addr_t unicast_ip;
584 #endif
585 
586   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %s%"U16_F"\n", (void *)netif, netif->name,
587               (u16_t)netif->num));
588   dhcp_set_state(dhcp, DHCP_STATE_REQUESTING);
589 
590   /* create and initialize the DHCP message header */
591   result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
592   if (result == ERR_OK) {
593     options_out_len = dhcp_option(options_out_len, dhcp->msg_out->options, DHCP_OPTION_SERVER_ID, 4);
594     options_out_len = dhcp_option_long(options_out_len, dhcp->msg_out->options,
595                                        lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
596     dhcp_fill_options(netif, dhcp, DHCP_REQUEST,
597                       GEN_FLG(MAX_MSG_SIZE) | GEN_FLG(REQUESTED_IP) | GEN_FLG(PARAMETER_REQUEST_LIST), &options_out_len);
598 
599 #if LWIP_DHCP_REQUEST_UNICAST
600     if (!ip4_addr_isany_val(dhcp->relay_ip)) {
601       ip_addr_set_ip4_u32_val(unicast_ip, ip4_addr_get_u32(&dhcp->relay_ip));
602       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: UNICAST relay\n"));
603     } else {
604       ip_addr_set_ip4_u32_val(unicast_ip, ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)));
605       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: UNICAST serv\n"));
606     }
607     result = udp_sendto_if_src(dhcp_pcb, dhcp->p_out, &unicast_ip, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
608 #else
609     /* send broadcast to any DHCP server */
610     result = udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
611 #endif
612     dhcp_delete_msg(dhcp);
613     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
614   } else {
615     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
616   }
617   if (dhcp_state->tries < 255) {
618     dhcp_state->tries++;
619   }
620   msecs = (u16_t)((dhcp_state->tries < 6 ? 1 << dhcp_state->tries : 60) * 1000);
621   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
622   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
623   return result;
624 }
625 
626 static void
dhcp_client_coarse_tmr(struct netif * netif,struct dhcp_client * dhcp)627 dhcp_client_coarse_tmr(struct netif *netif, struct dhcp_client *dhcp)
628 {
629   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
630 
631   if ((dhcp_state->state == DHCP_STATE_OFF)) {
632     return;
633   }
634 
635   /* compare lease time to expire timeout */
636   if ((dhcp->t0_timeout != 0) && (++dhcp_state->lease_used >= dhcp->t0_timeout)) {
637     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n"));
638     /* this clients' lease time has expired */
639     if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
640       (void)dhcp_release(netif);
641     } else {
642       (void)dhcp_release_client(netif, dhcp);
643     }
644     (void)dhcp_discover(netif, dhcp);
645     /* timer is active (non zero), and triggers (zeroes) now? */
646   } else if ((dhcp->t2_timeout != 0) && (dhcp_state->lease_used >= dhcp->t2_timeout)) {
647     if ((dhcp_state->re_time == 0) || (dhcp_state->re_time-- != 1)) {
648       return;
649     }
650     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
651     /* this clients' rebind timeout triggered */
652     dhcp_t2_timeout(netif, dhcp);
653     /* timer is active (non zero), and triggers (zeroes) now */
654   } else if ((dhcp->t1_timeout != 0) && (dhcp_state->re_time != 0) && (dhcp_state->re_time-- == 1)) {
655     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
656     /* this clients' renewal timeout triggered */
657     dhcp_t1_timeout(netif, dhcp);
658   }
659 
660   return;
661 }
662 
663 static void
dhcp_netif_coarse_tmr(struct netif * netif,struct dhcp * netif_dhcp)664 dhcp_netif_coarse_tmr(struct netif *netif, struct dhcp *netif_dhcp)
665 {
666   struct dhcp_state *dhcp_state = NULL;
667   int i;
668   u8_t hwaddr_len;
669 
670   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_netif_coarse_tmr()\n"));
671   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
672     netif_dhcp->client.cli_idx = (dhcp_num_t)i;
673     dhcp_state = &((netif_dhcp->client.states)[i]);
674     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
675       continue;
676     }
677     if (dhcp_idx_to_mac(netif, dhcp_state->idx, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
678       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
679                        "dhcp_netif_coarse_tmr:idx %u to mac failed\n", dhcp_state->idx);
680       continue;
681     }
682     dhcp_state->hwaddr_len = hwaddr_len;
683     dhcp_client_coarse_tmr(netif, &(netif_dhcp->client));
684   }
685 
686   return;
687 }
688 
689 /**
690  * The DHCP timer that checks for lease renewal/rebind timeouts.
691  * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS).
692  */
693 void
dhcp_coarse_tmr(void)694 dhcp_coarse_tmr(void)
695 {
696   struct netif *netif;
697   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
698   /* iterate through all network interfaces */
699   NETIF_FOREACH(netif) {
700     /* only act on DHCP configured interfaces */
701     struct dhcp *netif_dhcp = netif_dhcp_data(netif);
702     if (netif_dhcp != NULL) {
703       dhcp_netif_coarse_tmr(netif, netif_dhcp);
704     }
705   }
706 }
707 
708 #if LWIP_LOWPOWER
709 #include "lwip/lowpower.h"
710 
711 static u32_t
dhcp_netif_coarse_tmr_tick(struct dhcp * netif_dhcp)712 dhcp_netif_coarse_tmr_tick(struct dhcp *netif_dhcp)
713 {
714   struct dhcp_state *dhcp_state = NULL;
715   struct dhcp_client *client = NULL;
716   s32_t i;
717   u32_t tick = 0;
718   u32_t val;
719   u16_t lease_used;
720 
721   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
722     dhcp_state = &((netif_dhcp->client.states)[i]);
723     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
724       continue;
725     }
726     if ((dhcp_state->state == DHCP_STATE_OFF)) {
727       continue;
728     }
729 
730     client = &(netif_dhcp->client);
731     lease_used = dhcp_state->lease_used;
732     if (client->t0_timeout > 0) {
733       if (client->t0_timeout > lease_used) {
734         val = client->t0_timeout - lease_used;
735         SET_TMR_TICK(tick, val);
736       } else {
737         SET_TMR_TICK(tick, 1);
738       }
739     }
740 
741     if (client->t2_timeout > 0) {
742       if (client->t2_timeout > lease_used) {
743         val = (client->t2_timeout - lease_used);
744         SET_TMR_TICK(tick, val);
745       } else if (dhcp_state->re_time > 0) {
746         val = dhcp_state->re_time;
747         SET_TMR_TICK(tick, val);
748       } else {
749         SET_TMR_TICK(tick, 1);
750       }
751     }
752 
753     if (dhcp_state->re_time > 0) {
754       val = dhcp_state->re_time;
755       SET_TMR_TICK(tick, val);
756     }
757   }
758 
759   return tick;
760 }
761 
762 u32_t
dhcp_coarse_tmr_tick(void)763 dhcp_coarse_tmr_tick(void)
764 {
765   struct netif *netif = netif_list;
766   u32_t tick = 0;
767   u32_t val;
768 
769   while (netif != NULL) {
770     /* only act on DHCP configured interfaces */
771     struct dhcp *netif_dhcp = netif_dhcp_data(netif);
772     if (netif_dhcp == NULL) {
773       /* proceed to next netif */
774       netif = netif->next;
775       continue;
776     }
777     val = dhcp_netif_coarse_tmr_tick(netif_dhcp);
778     SET_TMR_TICK(tick, val);
779     /* proceed to next netif */
780     netif = netif->next;
781   }
782 
783   LOWPOWER_DEBUG(("%s tmr tick: %u\n", __func__, tick));
784   return tick;
785 }
786 
787 u32_t
dhcp_fine_tmr_tick(void)788 dhcp_fine_tmr_tick(void)
789 {
790   struct netif *netif = netif_list;
791   struct dhcp_state *dhcp_state = NULL;
792   int i;
793   u32_t tick = 0;
794   u32_t val;
795 
796   /* loop through netif's */
797   while (netif != NULL) {
798     struct dhcp *netif_dhcp = netif_dhcp_data(netif);
799     if (netif_dhcp == NULL) {
800       netif = netif->next;
801       continue;
802     }
803 
804     for (i = 0; i < DHCP_CLIENT_NUM; i++) {
805       dhcp_state = &((netif_dhcp->client.states)[i]);
806       if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
807         continue;
808       }
809       if (dhcp_state->request_timeout >= 1) {
810         val = dhcp_state->request_timeout;
811         SET_TMR_TICK(tick, val);
812       }
813     }
814     /* proceed to next network interface */
815     netif = netif->next;
816   }
817   LOWPOWER_DEBUG(("%s tmr tick: %d\n", __func__, tick));
818   return tick;
819 }
820 #endif /* LWIP_LOWPOWER */
821 
822 static void
dhcp_client_fine_tmr(struct netif * netif,struct dhcp_client * dhcp)823 dhcp_client_fine_tmr(struct netif *netif, struct dhcp_client *dhcp)
824 {
825   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
826   /* timer is active (non zero), and is about to trigger now */
827   if (dhcp_state->request_timeout > 1) {
828     dhcp_state->request_timeout--;
829   } else if (dhcp_state->request_timeout == 1) {
830     dhcp_state->request_timeout--;
831     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
832     /* this client's request timeout triggered */
833     dhcp_timeout(netif, dhcp);
834   }
835   return;
836 }
837 
838 static void
dhcp_netif_fine_tmr(struct netif * netif,struct dhcp * netif_dhcp)839 dhcp_netif_fine_tmr(struct netif *netif, struct dhcp *netif_dhcp)
840 {
841   struct dhcp_state *dhcp_state = NULL;
842   int i;
843   u8_t hwaddr_len;
844   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
845     netif_dhcp->client.cli_idx = (dhcp_num_t)i;
846     dhcp_state = &((netif_dhcp->client.states)[i]);
847     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
848       continue;
849     }
850     if (dhcp_idx_to_mac(netif, dhcp_state->idx, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
851       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
852                        "dhcp_netif_fine_tmr:idx %u to mac failed\n", dhcp_state->idx);
853       continue;
854     }
855     dhcp_state->hwaddr_len = hwaddr_len;
856     dhcp_client_fine_tmr(netif, &(netif_dhcp->client));
857   }
858   return;
859 }
860 
861 /**
862  * DHCP transaction timeout handling (this function must be called every 500ms,
863  * see @ref DHCP_FINE_TIMER_MSECS).
864  *
865  * A DHCP server is expected to respond within a short period of time.
866  * This timer checks whether an outstanding DHCP request is timed out.
867  */
868 void
dhcp_fine_tmr(void)869 dhcp_fine_tmr(void)
870 {
871   struct netif *netif;
872   /* loop through netif's */
873   NETIF_FOREACH(netif) {
874     struct dhcp *netif_dhcp = netif_dhcp_data(netif);
875     /* only act on DHCP configured interfaces */
876     if (netif_dhcp != NULL) {
877       dhcp_netif_fine_tmr(netif, netif_dhcp);
878     }
879   }
880 }
881 
882 /**
883  * A DHCP negotiation transaction, or ARP request, has timed out.
884  *
885  * The timer that was started with the DHCP or ARP request has
886  * timed out, indicating no response was received in time.
887  *
888  * @param netif the netif under DHCP control
889  */
890 static void
dhcp_timeout(struct netif * netif,struct dhcp_client * dhcp)891 dhcp_timeout(struct netif *netif, struct dhcp_client *dhcp)
892 {
893   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
894 
895   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
896   /* back-off period has passed, or server selection timed out */
897   if ((dhcp_state->state == DHCP_STATE_BACKING_OFF) || (dhcp_state->state == DHCP_STATE_SELECTING)) {
898     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
899     (void)dhcp_discover(netif, dhcp);
900     /* receiving the requested lease timed out */
901   } else if (dhcp_state->state == DHCP_STATE_REQUESTING) {
902     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
903                      ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
904     if (dhcp_state->tries <= 5) {
905       (void)dhcp_select(netif, dhcp);
906     } else {
907       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING timed out\n"));
908       if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
909         (void)dhcp_release(netif);
910       } else {
911         (void)dhcp_release_client(netif, dhcp);
912       }
913       (void)dhcp_discover(netif, dhcp);
914     }
915 #if DHCP_DOES_ARP_CHECK
916     /* received no ARP reply for the offered address (which is good) */
917   } else if (dhcp_state->state == DHCP_STATE_CHECKING) {
918     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING timed out\n"));
919     if (dhcp_state->tries <= 1) {
920       dhcp_check(netif, dhcp);
921       /* no ARP replies on the offered address,
922          looks like the IP address is indeed free */
923     } else {
924       /* bind the interface to the offered address */
925       dhcp_bind(netif, dhcp);
926     }
927 #endif /* DHCP_DOES_ARP_CHECK */
928 #if LWIP_DHCP_SUBSTITUTE_MMBR
929     /* received no ARP reply for the releasing address (no other using this address) */
930   } else if (dhcp_state->state == DHCP_STATE_RELEASING) {
931     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING timed out\n"));
932     if (dhcp_state->tries <= 1) {
933       dhcp_release_check(netif, dhcp);
934     } else {
935       /* no other MBR using this address, release it */
936       dhcp_stop_client(netif, dhcp);
937     }
938 #endif /* LWIP_DHCP_SUBSTITUTE_MMBR */
939   } else if (dhcp_state->state == DHCP_STATE_REBOOTING) {
940     if (dhcp_state->tries < REBOOT_TRIES) {
941       (void)dhcp_reboot(netif);
942     } else {
943       (void)dhcp_discover(netif, dhcp);
944     }
945   } else if (dhcp_state->state == DHCP_STATE_RENEWING) {
946     /* 5: send dhcp request package six times to renew its lease */
947     if (dhcp_state->tries <= 5) {
948       (void)dhcp_renew_client(netif, dhcp);
949     }
950   } else if (dhcp_state->state == DHCP_STATE_REBINDING) {
951     /* 5: send dhcp request package six times to Rebind with a DHCP server for an existing DHCP lease. */
952     if (dhcp_state->tries <= 5) {
953       (void)dhcp_rebind(netif, dhcp);
954     }
955 #if LWIP_ARP
956   } else if (dhcp_state->state == DHCP_STATE_BOUND) {
957     if (dhcp_state->tries < LWIP_DHCP_ANNOUNCE_NUM) {
958       dhcp_announce(netif, dhcp);
959     } else {
960       dhcp_state->tries = 0;
961     }
962 #endif
963 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
964   } else if (dhcp_state->state == DHCP_STATE_LIMIT_WAIT) {
965     dhcp_concurrent_limit_wait_timeout(netif, dhcp);
966 #endif
967   }
968 }
969 
970 /**
971  * The renewal period has timed out.
972  *
973  * @param netif the netif under DHCP control
974  */
975 static void
dhcp_t1_timeout(struct netif * netif,struct dhcp_client * dhcp)976 dhcp_t1_timeout(struct netif *netif, struct dhcp_client *dhcp)
977 {
978   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
979 
980   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
981   if ((dhcp_state->state == DHCP_STATE_REQUESTING) || (dhcp_state->state == DHCP_STATE_BOUND) ||
982       (dhcp_state->state == DHCP_STATE_RENEWING)) {
983     /* just retry to renew - note that the rebind timer (t2) will
984      * eventually time-out if renew tries fail. */
985     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
986     /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
987        DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */
988     (void)dhcp_renew_client(netif, dhcp);
989     /* Calculate next timeout */
990     if (((dhcp->t2_timeout - dhcp_state->lease_used) / 2) >=
991         ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) {
992       dhcp_state->re_time = (u16_t)((dhcp->t2_timeout - dhcp_state->lease_used) / 2);
993     } else {
994       dhcp_state->re_time = (u16_t)(dhcp->t2_timeout - dhcp_state->lease_used);
995     }
996   }
997 }
998 
999 /**
1000  * The rebind period has timed out.
1001  *
1002  * @param netif the netif under DHCP control
1003  */
1004 static void
dhcp_t2_timeout(struct netif * netif,struct dhcp_client * dhcp)1005 dhcp_t2_timeout(struct netif *netif, struct dhcp_client *dhcp)
1006 {
1007   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1008 
1009   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
1010   if ((dhcp_state->state == DHCP_STATE_REQUESTING) || (dhcp_state->state == DHCP_STATE_BOUND) ||
1011       (dhcp_state->state == DHCP_STATE_RENEWING) || (dhcp_state->state == DHCP_STATE_REBINDING)) {
1012     /* just retry to rebind */
1013     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
1014     /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
1015        DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */
1016     (void)dhcp_rebind(netif, dhcp);
1017     /* Calculate next timeout */
1018     if (((dhcp->t0_timeout - dhcp_state->lease_used) / 2) >=
1019         ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) {
1020       dhcp_state->re_time = (u16_t)((dhcp->t0_timeout - dhcp_state->lease_used) / 2);
1021     }
1022   }
1023 }
1024 
1025 /**
1026  * Handle a DHCP ACK packet
1027  *
1028  * @param netif the netif under DHCP control
1029  */
1030 static void
dhcp_handle_ack(struct netif * netif,struct dhcp_client * dhcp)1031 dhcp_handle_ack(struct netif *netif, struct dhcp_client *dhcp)
1032 {
1033 #if LWIP_DHCP_BOOTP_FILE
1034   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
1035 #else
1036   (void)netif;
1037 #endif /* LWIP_DHCP_BOOTP_FILE */
1038   ip4_addr_t cli_ip;
1039   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1040 
1041 #if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV
1042   u8_t n;
1043 #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */
1044 #if LWIP_DHCP_GET_NTP_SRV
1045   ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS];
1046 #endif
1047 
1048   /* clear options we might not get from the ACK */
1049   ip4_addr_set_zero(&dhcp->offered_sn_mask);
1050   ip4_addr_set_zero(&dhcp->offered_gw_addr);
1051 #if LWIP_DHCP_BOOTP_FILE
1052   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
1053     ip4_addr_set_zero(&netif_dhcp->offered_si_addr);
1054   }
1055 #endif /* LWIP_DHCP_BOOTP_FILE */
1056 
1057   /* lease time given? */
1058   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {
1059     /* remember offered lease time */
1060     dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);
1061   }
1062   /* renewal period given? */
1063   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {
1064     /* remember given renewal period */
1065     dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);
1066   } else {
1067     /* calculate safe periods for renewal */
1068     dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
1069   }
1070 
1071   /* renewal period given? */
1072   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {
1073     /* remember given rebind period */
1074     dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);
1075   } else {
1076     /* calculate safe periods for rebinding (offered_t0_lease * 0.875 -> 87.5%)*/
1077     dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U;
1078   }
1079 
1080 #if LWIP_DHCP_BOOTP_FILE
1081   /* copy boot server address,
1082      boot file name copied in dhcp_parse_reply if not overloaded */
1083   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
1084     ip4_addr_copy(netif_dhcp->offered_si_addr, dhcp->msg_in->siaddr);
1085   }
1086 #endif /* LWIP_DHCP_BOOTP_FILE */
1087 
1088   /* subnet mask given? */
1089   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
1090     /* remember given subnet mask */
1091     ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
1092     dhcp->subnet_mask_given = lwIP_TRUE;
1093   } else {
1094     dhcp_ip_to_mask(ip_2_ip4(&dhcp->server_ip_addr), &dhcp->offered_sn_mask);
1095     dhcp->subnet_mask_given = lwIP_FALSE;
1096   }
1097 
1098   /* (y)our internet address */
1099   ip4_addr_copy(cli_ip, dhcp->msg_in->yiaddr);
1100   DHCP_IP_TO_HOST(dhcp_state->offered_ip_addr, cli_ip.addr, dhcp->offered_sn_mask.addr);
1101 
1102   /* gateway router */
1103   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
1104     ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
1105   }
1106 
1107 #if LWIP_DHCP_GET_NTP_SRV
1108   /* NTP servers */
1109   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
1110     for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) {
1111       ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n)));
1112     }
1113     dhcp_set_ntp_servers(n, ntp_server_addrs);
1114   }
1115 #endif /* LWIP_DHCP_GET_NTP_SRV */
1116 
1117 #if LWIP_DNS
1118 #if LWIP_DHCP_PROVIDE_DNS_SERVERS
1119   /* DNS servers */
1120   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
1121     for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
1122       ip_addr_t dns_addr;
1123       ip_addr_set_ip4_u32_val(dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
1124       dns_setserver(n, &dns_addr);
1125     }
1126   }
1127 #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
1128 #endif
1129 }
1130 
1131 /**
1132  * @ingroup dhcp4
1133  * Set a statically allocated struct dhcp to work with.
1134  * Using this prevents dhcp_start to allocate it using mem_malloc.
1135  *
1136  * @param netif the netif for which to set the struct dhcp
1137  * @param dhcp (uninitialised) dhcp struct allocated by the application
1138  */
1139 void
dhcp_set_struct(struct netif * netif,struct dhcp * dhcp)1140 dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
1141 {
1142   LWIP_ASSERT_CORE_LOCKED();
1143   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
1144   LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return;);
1145 
1146   /* clear data structure */
1147   memset(dhcp, 0, sizeof(struct dhcp));
1148   /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
1149   netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
1150 }
1151 
1152 void
dhcp_remove_struct(struct netif * netif)1153 dhcp_remove_struct(struct netif *netif)
1154 {
1155   LWIP_ERROR("netif != NULL", (netif != NULL), return);
1156 
1157   netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL);
1158   return;
1159 }
1160 
1161 static void
dhcp_cleanup_indeed(void)1162 dhcp_cleanup_indeed(void)
1163 {
1164   if (dhcp_pcb != NULL) {
1165     udp_remove(dhcp_pcb);
1166     dhcp_pcb = NULL;
1167   }
1168   dhcp_pcb_refcount = 0;
1169 }
1170 
1171 /**
1172  * @ingroup dhcp4
1173  * Removes a struct dhcp from a netif.
1174  *
1175  * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
1176  *            struct dhcp since the memory is passed back to the heap.
1177  *
1178  * @param netif the netif from which to remove the struct dhcp
1179  */
dhcp_cleanup(struct netif * netif)1180 void dhcp_cleanup(struct netif *netif)
1181 {
1182   LWIP_ASSERT_CORE_LOCKED();
1183   struct dhcp *netif_dhcp = NULL;
1184 #if LWIP_DHCP_SUBSTITUTE
1185   int i;
1186   struct dhcp_client *dhcp = NULL;
1187   struct dhcp_state *dhcp_state = NULL;
1188 #endif /* LWIP_DHCP_SUBSTITUTE */
1189   LWIP_ERROR("netif != NULL", (netif != NULL), return);
1190 
1191   netif_dhcp = netif_dhcp_data(netif);
1192   if (netif_dhcp == NULL) {
1193     return;
1194   }
1195   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_cleanup\n"));
1196   if (netif_dhcp->pcb_allocated != 0) {
1197     dhcp_stop(netif);
1198   }
1199 #if LWIP_DHCP_SUBSTITUTE
1200   dhcp = &(netif_dhcp->client);
1201   for (i = 1; i < DHCP_CLIENT_NUM; i++) {
1202     dhcp_state = &((dhcp->states)[i]);
1203     if (dhcp_state->idx == 0) {
1204       continue;
1205     }
1206     dhcp_substitute_stop(netif, dhcp_state->idx, lwIP_FALSE);
1207   }
1208   if (netif_dhcp->clis_info != NULL) {
1209     mem_free(netif_dhcp->clis_info);
1210     netif_dhcp->clis_info = NULL;
1211   }
1212 #endif /* LWIP_DHCP_SUBSTITUTE */
1213   dhcp_cleanup_indeed();
1214   mem_free(netif_dhcp_data(netif));
1215   netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL);
1216 }
1217 
1218 /**
1219  * Check DHCP negotiation is done for a network interface.
1220  *
1221  * @param netif The lwIP network interface
1222  * @return
1223  * - ERR_OK - if DHCP is bound
1224  * - ERR_MEM - if DHCP bound is still progressing
1225  */
1226 err_t
dhcp_is_bound(struct netif * netif)1227 dhcp_is_bound(struct netif *netif)
1228 {
1229   struct dhcp *netif_dhcp = NULL;
1230 
1231   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
1232 
1233   netif_dhcp =  netif_dhcp_data(netif);
1234   LWIP_ERROR("netif->dhcp != NULL", (netif_dhcp != NULL), return ERR_ARG);
1235 
1236   if ((netif_dhcp->client.states)[LWIP_DHCP_NATIVE_IDX].state == DHCP_STATE_BOUND) {
1237     return ERR_OK;
1238   } else {
1239     return ERR_INPROGRESS;
1240   }
1241 }
1242 
1243 static void
dhcp_native_reset(struct dhcp * netif_dhcp)1244 dhcp_native_reset(struct dhcp *netif_dhcp)
1245 {
1246   netif_dhcp->pcb_allocated = 0;
1247 #if LWIP_DHCP_AUTOIP_COOP
1248   netif_dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
1249 #endif /* LWIP_DHCP_AUTOIP_COOP */
1250 #if LWIP_DHCP_BOOTP_FILE
1251   (void)memset_s(&(netif_dhcp->offered_si_addr), sizeof(netif_dhcp->offered_si_addr),
1252                  0x0, sizeof(netif_dhcp->offered_si_addr));
1253   (void)memset_s(netif_dhcp->boot_file_name, sizeof(netif_dhcp->boot_file_name),
1254                  0x0, sizeof(netif_dhcp->boot_file_name));
1255 #endif /* LWIP_DHCP_BOOTP_FILE */
1256 
1257   return;
1258 }
1259 
1260 static struct dhcp *
dhcp_netif_dhcp_new(void)1261 dhcp_netif_dhcp_new(void)
1262 {
1263   struct dhcp *netif_dhcp = NULL;
1264 
1265   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_netif_dhcp_new(): starting new DHCP client\n"));
1266   netif_dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
1267   if (netif_dhcp == NULL) {
1268     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_netif_dhcp_new(): could not allocate dhcp\n"));
1269     return NULL;
1270   }
1271 
1272   (void)memset_s(netif_dhcp, sizeof(struct dhcp), 0x0, sizeof(struct dhcp));
1273 
1274   return netif_dhcp;
1275 }
1276 
1277 static err_t
dhcp_start_client_native(struct netif * netif)1278 dhcp_start_client_native(struct netif *netif)
1279 {
1280   struct dhcp *netif_dhcp = NULL;
1281   struct dhcp_client *dhcp = NULL;
1282 
1283   netif_dhcp = netif_dhcp_data(netif);
1284   dhcp = &(netif_dhcp->client);
1285   (void)dhcp;
1286   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1287                    ("dhcp_start_client_native(): restarting DHCP configuration\n"));
1288   LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
1289   LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
1290 
1291   if (netif_dhcp->pcb_allocated != 0) {
1292     dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
1293   }
1294   /* dhcp is cleared below, no need to reset flag */
1295   /* clear data structure */
1296   dhcp_native_reset(netif_dhcp);
1297 
1298   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start_client_native(): starting DHCP configuration\n"));
1299 
1300   if (dhcp_inc_pcb_refcount(netif->ifindex) != ERR_OK) { /* ensure DHCP PCB is allocated */
1301     dhcp_stop(netif);
1302     return ERR_MEM;
1303   }
1304   netif_dhcp->pcb_allocated = 1;
1305 
1306   return ERR_OK;
1307 }
1308 
1309 #if LWIP_DHCP_SUBSTITUTE_MMBR
1310 /*
1311  * substitute client start with a preferred IP, then
1312  * Discover message will carry Request IP option filling with the preferred IP
1313  * it will not do duplicate IP check
1314  */
1315 static void
dhcp_substitute_prefer_ip(struct dhcp_client * dhcp,u32_t pref_ipv4)1316 dhcp_substitute_prefer_ip(struct dhcp_client *dhcp, u32_t pref_ipv4)
1317 {
1318   ip4_addr_t cli_ip, netaddr;
1319   dhcp_num_t offered_ip_addr;
1320   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1321 
1322   if (ip4_addr_isany_val(dhcp->offered_sn_mask)) {
1323     return;
1324   }
1325 
1326   if (ip4_addr_isany_val(dhcp->relay_ip)) {
1327     netaddr.addr = ip_2_ip4(&dhcp->server_ip_addr)->addr;
1328   } else {
1329     netaddr.addr = dhcp->relay_ip.addr;
1330   }
1331   cli_ip.addr = pref_ipv4;
1332 
1333   /* it also can be checkout that pref_ipv4 is 0 */
1334   if (!ip4_addr_netcmp(&cli_ip, &netaddr, &(dhcp->offered_sn_mask))) {
1335     return;
1336   }
1337 
1338   DHCP_IP_TO_HOST(offered_ip_addr, pref_ipv4, dhcp->offered_sn_mask.addr);
1339   dhcp_state->offered_ip_addr = offered_ip_addr;
1340   dhcp_state->addr_not_dup_check = lwIP_TRUE;
1341 
1342   return;
1343 }
1344 #endif
1345 
1346 static err_t
dhcp_start_client(struct netif * netif,dhcp_num_t mac_idx,u32_t pref_ipv4)1347 dhcp_start_client(struct netif *netif, dhcp_num_t mac_idx, u32_t pref_ipv4)
1348 {
1349   struct dhcp *netif_dhcp = NULL;
1350   struct dhcp_client *dhcp = NULL;
1351   struct dhcp_state *dhcp_state = NULL;
1352   u8_t hwaddr_len;
1353   err_t result;
1354 #if LWIP_DHCP_SUBSTITUTE
1355   u8_t is_new = lwIP_FALSE;
1356 #endif /* LWIP_DHCP_SUBSTITUTE */
1357 
1358 #if !(LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_SUBSTITUTE_MMBR)
1359   (void)pref_ipv4;
1360 #endif
1361 
1362   /* check MTU of the netif */
1363   if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
1364     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE,
1365                      ("dhcp_start_client(): Cannot use this netif with DHCP: MTU is too small\n"));
1366     return ERR_MEM;
1367   }
1368 
1369   netif_dhcp = netif_dhcp_data(netif);
1370   /* no DHCP client attached yet? */
1371   if (netif_dhcp == NULL) {
1372     netif_dhcp = dhcp_netif_dhcp_new();
1373     if (netif_dhcp == NULL) {
1374       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client:new dhcp failed\n");
1375       return ERR_MEM;
1376     }
1377     /* store this dhcp client in the netif */
1378     netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, netif_dhcp);
1379     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start_client(): allocated dhcp"));
1380     /* already has DHCP client attached */
1381   }
1382   dhcp = &(netif_dhcp->client);
1383   if (dhcp_client_find_by_mac_idx(dhcp, mac_idx, &(dhcp->cli_idx)) != ERR_OK) {
1384     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client(): client state not find for %u\n", mac_idx);
1385     if (dhcp_client_state_new(dhcp, mac_idx, &(dhcp->cli_idx)) != ERR_OK) {
1386       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client(): no client state for %u\n", mac_idx);
1387       return ERR_MEM;
1388     } else {
1389 #if LWIP_DHCP_SUBSTITUTE
1390       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client(): new client state for %u\n", mac_idx);
1391       is_new = lwIP_TRUE;
1392 #endif /* LWIP_DHCP_SUBSTITUTE */
1393     }
1394   }
1395   dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1396   if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
1397     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client(): no client state for %u\n", mac_idx);
1398     return ERR_MEM;
1399   }
1400   dhcp_state->hwaddr_len = hwaddr_len;
1401 
1402   if (mac_idx == LWIP_DHCP_NATIVE_IDX) {
1403     result = dhcp_start_client_native(netif);
1404     if (result != ERR_OK) {
1405       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client:native failed\n");
1406       (void)memset_s(dhcp_state, sizeof(struct dhcp_state), 0, sizeof(struct dhcp_state));
1407       return result;
1408     }
1409   }
1410 #if LWIP_DHCP_SUBSTITUTE
1411   else {
1412     if ((is_new == lwIP_TRUE) && (dhcp_inc_pcb_refcount(netif->ifindex) != ERR_OK)) {
1413       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client:inc ref failed\n");
1414       (void)memset_s(dhcp_state, sizeof(struct dhcp_state), 0, sizeof(struct dhcp_state));
1415       return ERR_MEM;
1416     }
1417 #if LWIP_DHCP_SUBSTITUTE_MMBR
1418     dhcp_substitute_prefer_ip(dhcp, pref_ipv4);
1419 #endif
1420   }
1421 #if LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS
1422   if (dhcp_concurrent_start_client(dhcp) != ERR_OK) {
1423     return ERR_OK;
1424   }
1425 #endif
1426 #endif /* LWIP_DHCP_SUBSTITUTE */
1427 
1428 #if LWIP_DHCP_CHECK_LINK_UP
1429   if (!netif_is_link_up(netif)) {
1430     /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */
1431     dhcp_set_state(dhcp, DHCP_STATE_INIT);
1432     return ERR_OK;
1433   }
1434 #endif
1435 
1436   /* (re)start the DHCP negotiation */
1437   result = dhcp_discover(netif, dhcp);
1438   if (result != ERR_OK) {
1439     /* free resources allocated above */
1440     if (mac_idx == LWIP_DHCP_NATIVE_IDX) {
1441       dhcp_stop(netif);
1442     } else {
1443       dhcp_stop_client(netif, dhcp);
1444     }
1445     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_start_client:discover failed\n");
1446     return ERR_MEM;
1447   }
1448 
1449   return ERR_OK;
1450 }
1451 
1452 /**
1453  * @ingroup dhcp4
1454  * Start DHCP negotiation for a network interface.
1455  *
1456  * If no DHCP client instance was attached to this interface,
1457  * a new client is created first. If a DHCP client instance
1458  * was already present, it restarts negotiation.
1459  *
1460  * @param netif The lwIP network interface
1461  * @return lwIP error code
1462  * - ERR_OK - No error
1463  * - ERR_MEM - Out of memory
1464  */
1465 err_t
dhcp_start(struct netif * netif)1466 dhcp_start(struct netif *netif)
1467 {
1468   err_t result;
1469 
1470   LWIP_ASSERT_CORE_LOCKED();
1471   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
1472   LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
1473 
1474   netif_set_ipaddr(netif, IP4_ADDR_ANY4);
1475   netif_set_gw(netif, IP4_ADDR_ANY4);
1476   netif_set_netmask(netif, IP4_ADDR_ANY4);
1477 
1478   LWIP_DEBUGF_LOG4(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1479                    "dhcp_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1],
1480                    (u16_t)netif->num);
1481 
1482   /* Remove the flag that says this netif is handled by DHCP,
1483      it is set when we succeeded starting. */
1484   netif->flags = (netif->flags & (~NETIF_FLAG_DHCP));
1485 
1486   result = dhcp_start_client(netif, LWIP_DHCP_NATIVE_IDX, 0);
1487 
1488   if (result != ERR_OK) {
1489     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp start failed\n");
1490     return result;
1491   }
1492 
1493   dhcp_clients_count_update(&(netif_dhcp_data(netif)->client));
1494   /* Set the flag that says this netif is handled by DHCP. */
1495   netif->flags |= NETIF_FLAG_DHCP;
1496   return ERR_OK;
1497 }
1498 
1499 /**
1500  * @ingroup dhcp4
1501  * Inform a DHCP server of our manual configuration.
1502  *
1503  * This informs DHCP servers of our fixed IP address configuration
1504  * by sending an INFORM message. It does not involve DHCP address
1505  * configuration, it is just here to be nice to the network.
1506  *
1507  * @param netif The lwIP network interface
1508  */
1509 void
dhcp_inform(struct netif * netif)1510 dhcp_inform(struct netif *netif)
1511 {
1512   err_t result, ret;
1513   u16_t options_out_len;
1514 
1515   u8_t is_malloc = lwIP_FALSE;
1516   u16_t malloc_size;
1517   u8_t hwaddr_len;
1518   struct dhcp_state *dhcp_state = NULL;
1519   struct dhcp *netif_dhcp = NULL;
1520   struct dhcp_client *dhcp = NULL;
1521 
1522   LWIP_ASSERT_CORE_LOCKED();
1523   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
1524   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_inform\n");
1525   if (dhcp_inc_pcb_refcount(netif->ifindex) != ERR_OK) { /* ensure DHCP PCB is allocated */
1526     return;
1527   }
1528 
1529   netif_dhcp = netif_dhcp_data(netif);
1530   if (netif_dhcp != NULL) {
1531     dhcp = &(netif_dhcp->client);
1532   } else {
1533     malloc_size = (u16_t)(sizeof(struct dhcp_client) - (DHCP_CLIENT_NUM - 1) * sizeof(struct dhcp_state));
1534     dhcp = (struct dhcp_client *)mem_malloc(malloc_size);
1535     if (dhcp == NULL) {
1536       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: malloc failed\n"));
1537       return;
1538     }
1539     (void)memset_s(dhcp, malloc_size, 0, malloc_size);
1540     is_malloc = lwIP_TRUE;
1541   }
1542 
1543   dhcp->cli_idx = LWIP_DHCP_NATIVE_IDX;
1544   dhcp_state = &(dhcp->states[LWIP_DHCP_NATIVE_IDX]);
1545   dhcp_set_state(dhcp, DHCP_STATE_INFORMING);
1546   if (dhcp_idx_to_mac(netif, LWIP_DHCP_NATIVE_IDX, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
1547     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: get mac failed\n"));
1548     dhcp_dec_pcb_refcount();
1549     if (is_malloc == lwIP_TRUE) {
1550       mem_free(dhcp);
1551     }
1552     return;
1553   }
1554   dhcp_state->hwaddr_len = hwaddr_len;
1555 
1556   /* create and initialize the DHCP message header */
1557   result = dhcp_create_msg(netif, dhcp, DHCP_INFORM, &options_out_len);
1558   if (result == ERR_OK) {
1559     dhcp_fill_options(netif, dhcp, DHCP_INFORM, GEN_FLG(MAX_MSG_SIZE), &options_out_len);
1560 
1561     ret = udp_sendto_if(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif);
1562     (void)ret;
1563     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, "dhcp_inform: INFORMING %d\n", ret);
1564     dhcp_delete_msg(dhcp);
1565   } else {
1566     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
1567   }
1568 
1569   dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */
1570   if (is_malloc == lwIP_TRUE) {
1571     mem_free(dhcp);
1572   }
1573 }
1574 
1575 /** Handle a possible change in the network configuration.
1576  *
1577  * This enters the REBOOTING state to verify that the currently bound
1578  * address is still valid.
1579  */
1580 static void
dhcp_network_changed_client(struct netif * netif,struct dhcp_client * dhcp)1581 dhcp_network_changed_client(struct netif *netif, struct dhcp_client *dhcp)
1582 {
1583 #if LWIP_DHCP_AUTOIP_COOP
1584   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
1585 #endif /* LWIP_DHCP_AUTOIP_COOP */
1586   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1587 
1588   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_network_changed_client:state %hhu\n", dhcp_state->state);
1589 
1590   switch (dhcp_state->state) {
1591     case DHCP_STATE_REBINDING:
1592     case DHCP_STATE_RENEWING:
1593     case DHCP_STATE_BOUND:
1594     case DHCP_STATE_REBOOTING:
1595       dhcp_state->tries = 0;
1596 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
1597       if (dhcp_concurrent_start_client(dhcp) != ERR_OK) {
1598         LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_network_changed_client:up limit %hu\n",
1599                          g_dhcp_max_concurrent_num);
1600         return;
1601       }
1602 #endif
1603       (void)dhcp_reboot(netif);
1604       break;
1605     case DHCP_STATE_OFF:
1606       /* stay off */
1607       break;
1608     default:
1609       /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the
1610          state changes, SELECTING: continue with current 'rid' as we stay in the
1611          same state */
1612 #if LWIP_DHCP_AUTOIP_COOP
1613       if ((dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) &&
1614           (netif_dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON)) {
1615         (void)autoip_stop(netif);
1616         netif_dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
1617       }
1618 #endif /* LWIP_DHCP_AUTOIP_COOP */
1619       /* ensure we start with short timeouts, even if already discovering */
1620       dhcp_state->tries = 0;
1621 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
1622       if (dhcp_concurrent_start_client(dhcp) != ERR_OK) {
1623         LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_network_changed_client:up limit %hu\n",
1624                          g_dhcp_max_concurrent_num);
1625         return;
1626       }
1627 #endif
1628       (void)dhcp_discover(netif, dhcp);
1629       break;
1630   }
1631 }
1632 
1633 void
dhcp_network_changed(struct netif * netif)1634 dhcp_network_changed(struct netif *netif)
1635 {
1636   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
1637   struct dhcp_client *dhcp = NULL;
1638   struct dhcp_state *dhcp_state = NULL;
1639 
1640   int i;
1641   u8_t hwaddr_len;
1642   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_network_changed()\n"));
1643   if (netif_dhcp == NULL) {
1644     return;
1645   }
1646   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_network_changed() dhcp\n"));
1647 
1648   dhcp = &(netif_dhcp->client);
1649 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
1650   dhcp->rqst_cli_cnt = 0;
1651 #endif
1652   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
1653     dhcp->cli_idx = (dhcp_num_t)i;
1654     dhcp_state = &((dhcp->states)[i]);
1655     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
1656       continue;
1657     }
1658     if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
1659       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1660                        "dhcp_network_changed:idx %"DHCP_NUM_F" to mac failed\n", dhcp_state->idx);
1661       continue;
1662     }
1663     dhcp_state->hwaddr_len = hwaddr_len;
1664     dhcp_network_changed_client(netif, dhcp);
1665   }
1666 }
1667 
1668 #if DHCP_DOES_ARP_CHECK
1669 /**
1670  * Match an ARP reply with the offered IP address:
1671  * check whether the offered IP address is not in use using ARP
1672  *
1673  * @param netif the network interface on which the reply was received
1674  * @param addr The IP address we received a reply from
1675  */
1676 void
dhcp_arp_reply(struct netif * netif,const ip4_addr_t * addr)1677 dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr)
1678 {
1679   struct dhcp *netif_dhcp = NULL;
1680   struct dhcp_client *dhcp = NULL;
1681   struct dhcp_state *dhcp_state = NULL;
1682   ip4_addr_t cli_ip;
1683   u8_t hwaddr_len;
1684   int i;
1685 
1686   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
1687   netif_dhcp = netif_dhcp_data(netif);
1688   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
1689   /* is a DHCP client doing an ARP check? */
1690   if (netif_dhcp == NULL) {
1691     return;
1692   }
1693   dhcp = &(netif_dhcp->client);
1694   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
1695     dhcp->cli_idx = (dhcp_num_t)i;
1696     dhcp_state = &((dhcp->states)[i]);
1697     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
1698       continue;
1699     }
1700     if (
1701 #if LWIP_DHCP_SUBSTITUTE_MMBR
1702         (dhcp_state->state == DHCP_STATE_RELEASING) ||
1703 #endif
1704         (dhcp_state->state == DHCP_STATE_CHECKING)) {
1705       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1706                        "dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
1707                        ip4_addr_get_u32(addr));
1708       /* did a host respond with the address we
1709          were offered by the DHCP server? */
1710       dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
1711       if (!ip4_addr_cmp(addr, &cli_ip)) {
1712         continue;
1713       }
1714       /* we will not accept the offered address */
1715       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
1716                        ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
1717       if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
1718         LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1719                          "dhcp_arp_reply:idx %u to mac failed\n", dhcp_state->idx);
1720         return;
1721       }
1722       dhcp_state->hwaddr_len = hwaddr_len;
1723 #if LWIP_DHCP_SUBSTITUTE_MMBR
1724       if (dhcp_state->state == DHCP_STATE_RELEASING) {
1725         /* just think that there is a MBR using this address, do not send Release message by me */
1726         dhcp_set_state(dhcp, DHCP_STATE_OFF);
1727         dhcp_stop_client(netif, dhcp);
1728       } else
1729 #endif
1730       {
1731         (void)dhcp_decline(netif, dhcp);
1732       }
1733       return;
1734     }
1735   }
1736 }
1737 
1738 /**
1739  * Decline an offered lease.
1740  *
1741  * Tell the DHCP server we do not accept the offered address.
1742  * One reason to decline the lease is when we find out the address
1743  * is already in use by another host (through ARP).
1744  *
1745  * @param netif the netif under DHCP control
1746  */
1747 static err_t
dhcp_decline(struct netif * netif,struct dhcp_client * dhcp)1748 dhcp_decline(struct netif *netif, struct dhcp_client *dhcp)
1749 {
1750   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1751   err_t result, ret;
1752   u16_t msecs;
1753   u16_t options_out_len;
1754 
1755   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
1756   dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
1757   /* create and initialize the DHCP message header */
1758   result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE, &options_out_len);
1759   if (result == ERR_OK) {
1760     options_out_len = dhcp_option(options_out_len, dhcp->msg_out->options, DHCP_OPTION_SERVER_ID, 4);
1761     options_out_len = dhcp_option_long(options_out_len, dhcp->msg_out->options,
1762                                        lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
1763     dhcp_fill_options(netif, dhcp, DHCP_DECLINE, GEN_FLG(REQUESTED_IP), &options_out_len);
1764 
1765     /* per section 4.4.4, broadcast DECLINE messages */
1766     ret = udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
1767     dhcp_delete_msg(dhcp);
1768     (void)ret;
1769     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
1770   } else {
1771     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
1772                      ("dhcp_decline: could not allocate DHCP request\n"));
1773   }
1774   if (dhcp_state->tries < 255) {
1775     dhcp_state->tries++;
1776   }
1777   msecs = DHCP_REQUEST_TIMEOUT_DEFAULT * MS_PER_SECOND;
1778   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
1779   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
1780   return result;
1781 }
1782 #endif /* DHCP_DOES_ARP_CHECK */
1783 
1784 
1785 /**
1786  * Start the DHCP process, discover a DHCP server.
1787  *
1788  * @param netif the netif under DHCP control
1789  */
1790 static err_t
dhcp_discover(struct netif * netif,struct dhcp_client * dhcp)1791 dhcp_discover(struct netif *netif, struct dhcp_client *dhcp)
1792 {
1793 #if LWIP_DHCP_AUTOIP_COOP
1794   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
1795 #endif
1796   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1797   err_t result, ret;
1798   u16_t msecs;
1799   u16_t options_out_len;
1800   u32_t opt_flags = GEN_FLG(MAX_MSG_SIZE) | GEN_FLG(PARAMETER_REQUEST_LIST);
1801   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
1802 #if LWIP_DHCP_SUBSTITUTE_MMBR
1803   if (dhcp_state->addr_not_dup_check != lwIP_TRUE)
1804 #endif
1805   {
1806     dhcp_state->offered_ip_addr = 0;
1807   }
1808 
1809   dhcp_set_state(dhcp, DHCP_STATE_SELECTING);
1810   /* create and initialize the DHCP message header */
1811   result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER, &options_out_len);
1812   if (result == ERR_OK) {
1813 #if LWIP_DHCP_SUBSTITUTE_MMBR
1814     if ((dhcp_state->addr_not_dup_check == lwIP_TRUE) && dhcp_state->offered_ip_addr != 0) {
1815       /* Request IP option with preferred IP */
1816       opt_flags |= GEN_FLG(REQUESTED_IP);
1817     }
1818 #endif
1819     dhcp_fill_options(netif, dhcp, DHCP_DISCOVER, opt_flags, &options_out_len);
1820     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
1821 
1822     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)\n"));
1823     ret = udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER, netif, IP4_ADDR_ANY);
1824     (void)ret;
1825     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
1826     dhcp_delete_msg(dhcp);
1827     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
1828   } else {
1829     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
1830                      ("dhcp_discover: could not allocate DHCP request\n"));
1831   }
1832   if (dhcp_state->tries < 255) {
1833     dhcp_state->tries++;
1834   }
1835 #if LWIP_DHCP_AUTOIP_COOP
1836   if ((dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) && (dhcp_state->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES) &&
1837       (netif_dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF)) {
1838     netif_dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
1839     autoip_start(netif);
1840   }
1841 #endif /* LWIP_DHCP_AUTOIP_COOP */
1842   msecs = (u16_t)((dhcp_state->tries < 6 ? (1UL << dhcp_state->tries) : 60) * DHCP_DISCOVER_RETRANSMIT_INTERVAL);
1843   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
1844   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1845                    "dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs);
1846   return result;
1847 }
1848 
1849 #if LWIP_ARP
1850 static void
dhcp_announce(struct netif * netif,struct dhcp_client * dhcp)1851 dhcp_announce(struct netif *netif, struct dhcp_client *dhcp)
1852 {
1853   err_t result;
1854   u16_t msecs;
1855   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1856   ip4_addr_t cli_ip;
1857   LWIP_DEBUGF_LOG3(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_announce(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
1858                    (s16_t)netif->name[1]);
1859   dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
1860   result = etharp_announce(netif, (const ip4_addr_t *)(&cli_ip));
1861   if (result != ERR_OK) {
1862     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_announce: arp announce failed\n"));
1863   }
1864   if (dhcp_state->tries < 255) {
1865     dhcp_state->tries++;
1866   }
1867   msecs = LWIP_DHCP_ANNOUNCE_INTERVAL * MS_PER_SECOND;
1868   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
1869   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, "dhcp_announce: set request timeout %"U16_F" msecs\n",
1870                    msecs);
1871 }
1872 #endif
1873 
1874 /**
1875  * Bind the interface to the offered IP address.
1876  *
1877  * @param netif network interface to bind to the offered address
1878  */
1879 static void
dhcp_bind(struct netif * netif,struct dhcp_client * dhcp)1880 dhcp_bind(struct netif *netif, struct dhcp_client *dhcp)
1881 {
1882   u32_t timeout;
1883   struct dhcp *netif_dhcp = NULL;
1884   ip4_addr_t sn_mask, gw_addr;
1885   u8_t is_native = lwIP_FALSE;
1886   ip4_addr_t cli_ip;
1887   struct dhcp_state *dhcp_state = NULL;
1888 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
1889   dhcp_state_enum_t pre_state;
1890 #endif
1891   LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
1892   netif_dhcp = netif_dhcp_data(netif);
1893   LWIP_ERROR("dhcp_bind: netif_dhcp != NULL", (netif_dhcp != NULL), return;);
1894   LWIP_DEBUGF_LOG3(DHCP_DEBUG | LWIP_DBG_TRACE,
1895                    "dhcp_bind(netif=%p) %s%"U16_F"\n", (void *)netif, netif->name, (u16_t)netif->num);
1896 
1897   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
1898     is_native = lwIP_TRUE;
1899   }
1900   dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
1901   /* reset time used of lease */
1902   dhcp_state->lease_used = 0;
1903 
1904   if (dhcp->offered_t0_lease != 0xffffffffUL) {
1905     /* set renewal period timer */
1906     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_bind(): t0 renewal timer %"U32_F" secs\n",
1907                      dhcp->offered_t0_lease);
1908     timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
1909     if (timeout > 0xffff) {
1910       timeout = 0xffff;
1911     }
1912     dhcp->t0_timeout = (u16_t)timeout;
1913     if (dhcp->t0_timeout == 0) {
1914       dhcp->t0_timeout = 1;
1915     }
1916     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1917                      "dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease * 1000);
1918   }
1919 
1920   /* temporary DHCP lease? */
1921   if (dhcp->offered_t1_renew != 0xffffffffUL) {
1922     /* set renewal period timer */
1923     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_bind(): t1 renewal timer %"U32_F" secs\n",
1924                      dhcp->offered_t1_renew);
1925     timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
1926     if (timeout > 0xffff) {
1927       timeout = 0xffff;
1928     }
1929     dhcp->t1_timeout = (u16_t)timeout;
1930     if (dhcp->t1_timeout == 0) {
1931       dhcp->t1_timeout = 1;
1932     }
1933     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1934                      "dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew * 1000);
1935     dhcp_state->re_time = dhcp->t1_timeout;
1936   }
1937   /* set renewal period timer */
1938   if (dhcp->offered_t2_rebind != 0xffffffffUL) {
1939     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_bind(): t2 rebind timer %"U32_F" secs\n",
1940                      dhcp->offered_t2_rebind);
1941     timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
1942     if (timeout > 0xffff) {
1943       timeout = 0xffff;
1944     }
1945     dhcp->t2_timeout = (u16_t)timeout;
1946     if (dhcp->t2_timeout == 0) {
1947       dhcp->t2_timeout = 1;
1948     }
1949     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1950                      "dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind * 1000);
1951   }
1952 
1953   /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */
1954   if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) {
1955     dhcp->t1_timeout = 0;
1956     dhcp_state->re_time = dhcp->t2_timeout;
1957   }
1958 
1959   if (dhcp->subnet_mask_given == lwIP_TRUE) {
1960     /* copy offered network mask */
1961     ip4_addr_copy(sn_mask, dhcp->offered_sn_mask);
1962   } else {
1963     /* subnet mask not given, choose a safe subnet mask given the network class */
1964     dhcp_ip_to_mask(ip_2_ip4(&dhcp->server_ip_addr), &sn_mask);
1965     ip4_addr_copy(dhcp->offered_sn_mask, sn_mask);
1966   }
1967 
1968   dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
1969 
1970   ip4_addr_copy(gw_addr, dhcp->offered_gw_addr);
1971 
1972 #if LWIP_DHCP_AUTOIP_COOP
1973   if ((is_native == lwIP_TRUE) && (netif_dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON)) {
1974     autoip_stop(netif);
1975     netif_dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
1976   }
1977 #endif /* LWIP_DHCP_AUTOIP_COOP */
1978 
1979   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",
1980               ip4_addr_get_u32(&cli_ip), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr)));
1981 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
1982   pre_state = dhcp_state->state;
1983 #endif
1984   /* netif is now bound to DHCP leased address - set this before assigning the address
1985      to ensure the callback can use dhcp_supplied_address() */
1986   dhcp_set_state(dhcp, DHCP_STATE_BOUND);
1987 
1988   if (is_native == lwIP_TRUE) {
1989     (void)netif_set_addr(netif, &cli_ip, &sn_mask, &gw_addr);
1990   }
1991 #if LWIP_NAT64
1992   else {
1993     nat64_dhcp_ip4_event(dhcp->hwaddr, dhcp_state->hwaddr_len, &cli_ip, NAT64_DHCP_EVENT_OFFER);
1994   }
1995 #endif
1996 #if LWIP_ARP
1997   if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
1998     dhcp_announce(netif, dhcp);
1999   }
2000 #endif
2001 
2002 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
2003   if ((g_dhcp_max_concurrent_num != 0) && (dhcp_client_request_processing(pre_state) == lwIP_TRUE)) {
2004     dhcp->rqst_cli_cnt--;
2005     dhcp_concurrent_start_next_client(netif, lwIP_FALSE);
2006   }
2007 #endif
2008 }
2009 
2010 /* handle dhcp renew, rebind, reboot -- hence the name */
2011 static err_t
dhcp_re3(struct netif * netif,struct dhcp_client * dhcp,u8_t state)2012 dhcp_re3(struct netif *netif, struct dhcp_client *dhcp, u8_t state)
2013 {
2014   err_t result, ret;
2015   u16_t options_out_len;
2016   u16_t msecs;
2017   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2018 
2019   dhcp_set_state(dhcp, state);
2020 
2021   /* create and initialize the DHCP message header */
2022   result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST, &options_out_len);
2023   if (result == ERR_OK) {
2024     u32_t opt_flags = GEN_FLG(MAX_MSG_SIZE) | GEN_FLG(PARAMETER_REQUEST_LIST);
2025     if (state == DHCP_STATE_REBOOTING) {
2026       opt_flags |= GEN_FLG(REQUESTED_IP);
2027     }
2028     dhcp_fill_options(netif, dhcp, DHCP_REQUEST, opt_flags, &options_out_len);
2029 
2030     const ip_addr_t *server_ip_addr = (state == DHCP_STATE_RENEWING) ?
2031                                       (&dhcp->server_ip_addr) : IP_ADDR_BROADCAST;
2032     ret = udp_sendto_if(dhcp_pcb, dhcp->p_out, server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif);
2033     (void)ret;
2034 
2035     dhcp_delete_msg(dhcp);
2036 
2037     LWIP_DEBUGF_LOG2(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, "dhcp_re3: state=%u ret %d\n", state, ret);
2038   } else {
2039     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
2040                      ("dhcp_re3: could not allocate DHCP request\n"));
2041   }
2042   if (dhcp_state->tries < 255) {
2043     dhcp_state->tries++;
2044   }
2045   /* back-off on retries, but to a maximum of 20 seconds for RENEW, 10 seccond for others */
2046   msecs = (u16_t)(dhcp_state->tries < 10 ? dhcp_state->tries * 1000 : 10 * 1000);
2047   if (state == DHCP_STATE_RENEWING) {
2048     msecs *= 2U;
2049   }
2050   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
2051   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
2052                    "dhcp_re3: set request timeout %"U16_F" msecs\n", msecs);
2053 
2054   return result;
2055 }
2056 
2057 static err_t
dhcp_renew_client(struct netif * netif,struct dhcp_client * dhcp)2058 dhcp_renew_client(struct netif *netif, struct dhcp_client *dhcp)
2059 {
2060   return dhcp_re3(netif, dhcp, DHCP_STATE_RENEWING);
2061 }
2062 
2063 /**
2064  * @ingroup dhcp4
2065  * Renew an existing DHCP lease at the involved DHCP server.
2066  *
2067  * @param netif network interface which must renew its lease
2068  */
2069 err_t
dhcp_renew(struct netif * netif)2070 dhcp_renew(struct netif *netif)
2071 {
2072   struct dhcp *netif_dhcp = NULL;
2073   struct dhcp_state *dhcp_state = NULL;
2074   u8_t hwaddr_len;
2075 
2076   LWIP_ASSERT_CORE_LOCKED();
2077   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
2078   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
2079 
2080   netif_dhcp = netif_dhcp_data(netif);
2081   LWIP_ERROR("netif != NULL", (netif_dhcp != NULL), return ERR_VAL);
2082   netif_dhcp->client.cli_idx = LWIP_DHCP_NATIVE_IDX;
2083   dhcp_state = &((netif_dhcp->client.states)[LWIP_DHCP_NATIVE_IDX]);
2084 
2085   if (dhcp_idx_to_mac(netif, LWIP_DHCP_NATIVE_IDX, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
2086     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew():get mac failed\n"));
2087     return ERR_VAL;
2088   }
2089   dhcp_state->hwaddr_len = hwaddr_len;
2090 
2091   return dhcp_renew_client(netif, &(netif_dhcp->client));
2092 }
2093 
2094 /**
2095  * Rebind with a DHCP server for an existing DHCP lease.
2096  *
2097  * @param netif network interface which must rebind with a DHCP server
2098  */
2099 static err_t
dhcp_rebind(struct netif * netif,struct dhcp_client * dhcp)2100 dhcp_rebind(struct netif *netif, struct dhcp_client *dhcp)
2101 {
2102   return dhcp_re3(netif, dhcp, DHCP_STATE_REBINDING);
2103 }
2104 
2105 /**
2106  * Enter REBOOTING state to verify an existing lease
2107  *
2108  * @param netif network interface which must reboot
2109  */
2110 static err_t
dhcp_reboot(struct netif * netif)2111 dhcp_reboot(struct netif *netif)
2112 {
2113   struct dhcp_client *dhcp = &(netif_dhcp_data(netif)->client);
2114   return dhcp_re3(netif, dhcp, DHCP_STATE_REBOOTING);
2115 }
2116 
2117 void
dhcp_release_and_stop(struct netif * netif)2118 dhcp_release_and_stop(struct netif *netif)
2119 {
2120   dhcp_stop(netif);
2121 }
2122 
2123 /**
2124  * @ingroup dhcp4
2125  * Release a DHCP lease (usually called before @ref dhcp_stop).
2126  *
2127  * @param netif network interface which must release its lease
2128  */
2129 static err_t
dhcp_release_client(struct netif * netif,struct dhcp_client * dhcp)2130 dhcp_release_client(struct netif *netif, struct dhcp_client *dhcp)
2131 {
2132   err_t result, ret;
2133   ip_addr_t server_ip_addr;
2134   u16_t options_out_len = 0;
2135 
2136   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2137   ip_addr_copy(server_ip_addr, dhcp->server_ip_addr);
2138 
2139   dhcp_state->lease_used = 0;
2140 
2141   if (dhcp->cli_cnt == 1) {
2142     dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
2143     dhcp->t0_timeout = 0;
2144     dhcp->t1_timeout = 0;
2145     dhcp->t2_timeout = 0;
2146   }
2147 
2148   if (!((dhcp_state->state == DHCP_STATE_BOUND) ||
2149         (dhcp_state->state == DHCP_STATE_RENEWING) ||
2150         (dhcp_state->state == DHCP_STATE_REBINDING) ||
2151         (dhcp_state->state == DHCP_STATE_RELEASING))) {
2152     /* clean old DHCP offer */
2153     if (dhcp->cli_cnt == 1) {
2154       ip_addr_set_zero_ip4(&dhcp->server_ip_addr);
2155       ip4_addr_set_zero(&dhcp->offered_sn_mask);
2156       ip4_addr_set_zero(&dhcp->offered_gw_addr);
2157       ip4_addr_set_zero(&dhcp->relay_ip);
2158     }
2159     dhcp_state->offered_ip_addr = 0;
2160     /* don't issue release message when address is not dhcp-assigned */
2161     return ERR_OK;
2162   }
2163 
2164   /* idle DHCP client */
2165   dhcp_set_state(dhcp, DHCP_STATE_OFF);
2166   /* create and initialize the DHCP message header */
2167   result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE, &options_out_len);
2168   if (result == ERR_OK) {
2169     options_out_len = dhcp_option(options_out_len, dhcp->msg_out->options, DHCP_OPTION_SERVER_ID, 4);
2170     options_out_len = dhcp_option_long(options_out_len, dhcp->msg_out->options,
2171                                        lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
2172     dhcp_fill_options(netif, dhcp, DHCP_RELEASE, 0, &options_out_len);
2173     ret = udp_sendto_if(dhcp_pcb, dhcp->p_out, &server_ip_addr, LWIP_IANA_PORT_DHCP_SERVER, netif);
2174     (void)ret;
2175     dhcp_delete_msg(dhcp);
2176     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n"));
2177   } else {
2178     /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */
2179     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
2180                      ("dhcp_release: could not allocate DHCP request\n"));
2181   }
2182   /* clean old DHCP offer */
2183   if (dhcp->cli_cnt == 1) {
2184     ip_addr_set_zero_ip4(&dhcp->server_ip_addr);
2185     ip4_addr_set_zero(&dhcp->offered_sn_mask);
2186     ip4_addr_set_zero(&dhcp->offered_gw_addr);
2187     ip4_addr_set_zero(&dhcp->relay_ip);
2188   }
2189   dhcp_state->offered_ip_addr = 0;
2190 #if LWIP_NAT64
2191   nat64_dhcp_ip4_event(dhcp->hwaddr, dhcp_state->hwaddr_len, NULL, NAT64_DHCP_EVENT_RELEASE);
2192 #endif
2193 
2194   return result;
2195 }
2196 
2197 
2198 /**
2199  * @ingroup dhcp4
2200  * Release a DHCP lease (usually called before @ref dhcp_stop).
2201  *
2202  * @param netif network interface which must release its lease
2203  */
2204 err_t
dhcp_release(struct netif * netif)2205 dhcp_release(struct netif *netif)
2206 {
2207   err_t result;
2208   struct dhcp *netif_dhcp = NULL;
2209   struct dhcp_state *dhcp_state = NULL;
2210   u8_t hwaddr_len;
2211   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
2212   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
2213   netif_dhcp = netif_dhcp_data(netif);
2214   if (netif_dhcp == NULL) {
2215     return ERR_ARG;
2216   }
2217 
2218   netif_dhcp->client.cli_idx = LWIP_DHCP_NATIVE_IDX;
2219   dhcp_state = &((netif_dhcp->client.states)[LWIP_DHCP_NATIVE_IDX]);
2220   if (dhcp_state->state == DHCP_STATE_OFF) {
2221     return ERR_ARG;
2222   }
2223 
2224   if (dhcp_idx_to_mac(netif, LWIP_DHCP_NATIVE_IDX, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
2225     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release():get mac failed\n"));
2226     return ERR_VAL;
2227   }
2228   dhcp_state->hwaddr_len = hwaddr_len;
2229 
2230 #if LWIP_DHCP_BOOTP_FILE
2231   ip4_addr_set_zero(&netif_dhcp->offered_si_addr);
2232 #endif /* LWIP_DHCP_BOOTP_FILE */
2233 
2234   result = dhcp_release_client(netif, &(netif_dhcp->client));
2235 
2236   /* remove IP address from interface (prevents routing from selecting this interface) */
2237   (void)netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
2238 
2239   return result;
2240 }
2241 
2242 static void
dhcp_stop_client(struct netif * netif,struct dhcp_client * dhcp)2243 dhcp_stop_client(struct netif *netif, struct dhcp_client *dhcp)
2244 {
2245   struct dhcp *netif_dhcp = NULL;
2246   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2247 
2248   netif_dhcp = netif_dhcp_data(netif);
2249 
2250   LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
2251 #if (LWIP_DHCP_SUBSTITUTE && LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS)
2252   dhcp_concurrent_stop_client(dhcp);
2253 #endif
2254   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
2255     (void)dhcp_release(netif);
2256     if (netif_dhcp->pcb_allocated != 0) {
2257       dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */
2258       netif_dhcp->pcb_allocated = 0;
2259     }
2260   } else {
2261 #if LWIP_DHCP_SUBSTITUTE
2262     (void)dhcp_release_client(netif, dhcp);
2263     dhcp_dec_pcb_refcount();
2264 #endif /* LWIP_DHCP_SUBSTITUTE */
2265   }
2266   dhcp_set_state(dhcp, DHCP_STATE_OFF);
2267   (void)memset_s(dhcp_state, sizeof(struct dhcp_state), 0, sizeof(struct dhcp_state));
2268   dhcp_clients_count_update(dhcp);
2269 }
2270 
2271 /**
2272  * @ingroup dhcp4
2273  * Remove the DHCP client from the interface.
2274  *
2275  * @param netif The network interface to stop DHCP on
2276  */
2277 void
dhcp_stop(struct netif * netif)2278 dhcp_stop(struct netif *netif)
2279 {
2280   struct dhcp *netif_dhcp = NULL;
2281   struct dhcp_state *dhcp_state = NULL;
2282   u8_t hwaddr_len;
2283   LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return);
2284   netif_dhcp = netif_dhcp_data(netif);
2285   netif->flags = netif->flags & (~NETIF_FLAG_DHCP);
2286   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
2287   if (netif_dhcp != NULL) {
2288 #if LWIP_DHCP_AUTOIP_COOP
2289     if (netif_dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
2290       autoip_stop(netif);
2291       netif_dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
2292     }
2293 #endif /* LWIP_DHCP_AUTOIP_COOP */
2294     netif_dhcp->client.cli_idx = LWIP_DHCP_NATIVE_IDX;
2295     dhcp_state = &((netif_dhcp->client.states)[LWIP_DHCP_NATIVE_IDX]);
2296     if (dhcp_idx_to_mac(netif, LWIP_DHCP_NATIVE_IDX, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
2297       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop():get mac failed\n"));
2298       return;
2299     }
2300     dhcp_state->hwaddr_len = hwaddr_len;
2301     dhcp_stop_client(netif, &(netif_dhcp->client));
2302   }
2303 }
2304 
2305 /*
2306  * Set the DHCP state of a DHCP client.
2307  *
2308  * If the state changed, reset the number of tries.
2309  */
2310 static void
dhcp_set_state(struct dhcp_client * dhcp,u8_t new_state)2311 dhcp_set_state(struct dhcp_client *dhcp, u8_t new_state)
2312 {
2313   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2314   if (new_state != dhcp_state->state) {
2315     LWIP_DEBUGF_LOG2(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_set_state:%hhu to %hhu\n", dhcp_state->state, new_state);
2316     dhcp_state->state = new_state;
2317     dhcp_state->tries = 0;
2318     dhcp_state->request_timeout = 0;
2319   }
2320 }
2321 
2322 /*
2323  * Concatenate an option type and length field to the outgoing
2324  * DHCP message.
2325  *
2326  */
2327 static u16_t
dhcp_option(u16_t options_out_len,u8_t * options,u8_t option_type,u8_t option_len)2328 dhcp_option(u16_t options_out_len, u8_t *options, u8_t option_type, u8_t option_len)
2329 {
2330   LWIP_ASSERT("dhcp_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
2331   options[options_out_len++] = option_type;
2332   options[options_out_len++] = option_len;
2333   return options_out_len;
2334 }
2335 /*
2336  * Concatenate a single byte to the outgoing DHCP message.
2337  *
2338  */
2339 static u16_t
dhcp_option_byte(u16_t options_out_len,u8_t * options,u8_t value)2340 dhcp_option_byte(u16_t options_out_len, u8_t *options, u8_t value)
2341 {
2342   LWIP_ASSERT("dhcp_option_byte: options_out_len < DHCP_OPTIONS_LEN", options_out_len < DHCP_OPTIONS_LEN);
2343   options[options_out_len++] = value;
2344   return options_out_len;
2345 }
2346 
2347 static u16_t
dhcp_option_short(u16_t options_out_len,u8_t * options,u16_t value)2348 dhcp_option_short(u16_t options_out_len, u8_t *options, u16_t value)
2349 {
2350   LWIP_ASSERT("dhcp_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN", options_out_len + 2U <= DHCP_OPTIONS_LEN);
2351   options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
2352   options[options_out_len++] = (u8_t) (value & 0x00ffU);
2353   return options_out_len;
2354 }
2355 
2356 static u16_t
dhcp_option_long(u16_t options_out_len,u8_t * options,u32_t value)2357 dhcp_option_long(u16_t options_out_len, u8_t *options, u32_t value)
2358 {
2359   LWIP_ASSERT("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN", options_out_len + 4U <= DHCP_OPTIONS_LEN);
2360   options[options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
2361   options[options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
2362   options[options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
2363   options[options_out_len++] = (u8_t)((value & 0x000000ffUL));
2364   return options_out_len;
2365 }
2366 
2367 #if LWIP_NETIF_HOSTNAME
2368 static u16_t
dhcp_option_hostname(u16_t options_out_len,u8_t * options,struct netif * netif)2369 dhcp_option_hostname(u16_t options_out_len, u8_t *options, struct netif *netif)
2370 {
2371   const char *p = NULL;
2372   char dhcp_hostname[NETIF_HOSTNAME_MAX_LEN];
2373   size_t namelen = strlen(netif->hostname);
2374   if (namelen > 0) {
2375     p = netif->hostname;
2376   }
2377 
2378   if (p == NULL) {
2379     if (snprintf_s(dhcp_hostname, NETIF_HOSTNAME_MAX_LEN,
2380                    NETIF_HOSTNAME_MAX_LEN - 1, "%02x%02x%02x%02x%02x%02x",
2381                    netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2],
2382                    netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]) <= 0) {
2383       return options_out_len;
2384     }
2385     dhcp_hostname[NETIF_HOSTNAME_MAX_LEN - 1] = '\0';
2386     p = dhcp_hostname;
2387   }
2388 
2389   namelen = strlen(p);
2390   /* Validate length against available bytes (need 2 bytes for OPTION_HOSTNAME
2391      and 1 byte for trailer) */
2392   LWIP_ASSERT("DHCP: hostname is too long!", namelen + 3 + options_out_len <= DHCP_OPTIONS_LEN);
2393   options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_HOSTNAME, (u8_t)namelen);
2394   while (namelen--) {
2395     options_out_len = dhcp_option_byte(options_out_len, options, (u8_t)(*p++));
2396   }
2397 
2398   return options_out_len;
2399 }
2400 #endif /* LWIP_NETIF_HOSTNAME */
2401 
2402 #if LWIP_DHCP_VENDOR_CLASS_IDENTIFIER
2403 static u16_t
dhcp_option_vci(u16_t options_out_len,u8_t * options,const struct netif * netif)2404 dhcp_option_vci(u16_t options_out_len, u8_t *options, const struct netif *netif)
2405 {
2406   const char *p = NULL;
2407   u8_t len;
2408   size_t vci_len;
2409   size_t available;
2410 
2411   LWIP_UNUSED_ARG(netif);
2412 
2413   vci_len = g_vci_info.vci_len;
2414   if (vci_len > 0) {
2415     p = g_vci_info.vci;
2416   } else {
2417     return options_out_len;
2418   }
2419 
2420   /* Shrink len to available bytes (need 2 bytes for DHCP_OPTION_VCI
2421      and 1 byte for trailer) */
2422   available = DHCP_OPTIONS_LEN - options_out_len - 3;
2423   LWIP_ASSERT("DHCP: vci is too long!", vci_len <= available);
2424   len = (u8_t)LWIP_MIN(vci_len, available);
2425   options_out_len = dhcp_option(options_out_len, options, DHCP_OPTION_VCI, (u8_t)len);
2426   while (len--) {
2427     options_out_len = dhcp_option_byte(options_out_len, options, *p++);
2428   }
2429   return options_out_len;
2430 }
2431 
2432 err_t
dhcp_set_vci(const char * vci,u8_t vci_len)2433 dhcp_set_vci(const char *vci, u8_t vci_len)
2434 {
2435   if (memcpy_s(g_vci_info.vci, DHCP_VCI_MAX_LEN, vci, vci_len) == EOK) {
2436     g_vci_info.vci_len = vci_len;
2437     return ERR_OK;
2438   }
2439   return ERR_MEM;
2440 }
2441 
2442 err_t
dhcp_get_vci(char * vci,u8_t * vci_len)2443 dhcp_get_vci(char *vci, u8_t *vci_len)
2444 {
2445   if (g_vci_info.vci_len == 0) {
2446     *vci_len = 0;
2447     return ERR_VAL;
2448   } else {
2449     if (memcpy_s(vci, *vci_len, g_vci_info.vci, g_vci_info.vci_len) == EOK) {
2450       *vci_len = g_vci_info.vci_len;
2451       return ERR_OK;
2452     } else {
2453       *vci_len = 0;
2454       return ERR_VAL;
2455     }
2456   }
2457 }
2458 #endif /* LWIP_DHCP_VENDOR_CLASS_IDENTIFIER */
2459 
2460 /**
2461  * Extract the DHCP message and the DHCP options.
2462  *
2463  * Extract the DHCP message and the DHCP options, each into a contiguous
2464  * piece of memory. As a DHCP message is variable sized by its options,
2465  * and also allows overriding some fields for options, the easy approach
2466  * is to first unfold the options into a contiguous piece of memory, and
2467  * use that further on.
2468  *
2469  */
2470 static err_t
dhcp_parse_reply(struct dhcp * netif_dhcp,struct dhcp_client * dhcp,struct pbuf * p)2471 dhcp_parse_reply(struct dhcp *netif_dhcp, struct dhcp_client *dhcp, struct pbuf *p)
2472 {
2473   u8_t *options = NULL;
2474   u16_t offset;
2475   u16_t offset_max;
2476   u16_t options_offset;
2477   u16_t options_idx;
2478   u16_t options_idx_max;
2479   struct pbuf *q = NULL;
2480   int parse_file_as_options = 0;
2481   int parse_sname_as_options = 0;
2482 #if LWIP_DHCP_BOOTP_FILE
2483   int file_overloaded = 0;
2484 #endif
2485   (void)netif_dhcp;
2486 
2487   /* clear received options */
2488   dhcp_clear_all_options(dhcp);
2489   /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
2490   if (p->len < DHCP_SNAME_OFS) {
2491     return ERR_BUF;
2492   }
2493   dhcp->msg_in = (struct dhcp_msg *)p->payload;
2494 #if LWIP_DHCP_BOOTP_FILE
2495   /* clear boot file name */
2496   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
2497     netif_dhcp->boot_file_name[0] = 0;
2498   }
2499 #endif /* LWIP_DHCP_BOOTP_FILE */
2500 
2501   /* parse options */
2502 
2503   /* start with options field */
2504   options_idx = DHCP_OPTIONS_OFS;
2505   /* parse options to the end of the received packet */
2506   options_idx_max = p->tot_len;
2507 again:
2508   q = p;
2509   options_offset = options_idx;
2510   while ((q != NULL) && (options_idx >= q->len)) {
2511     options_idx = (u16_t)(options_idx - q->len);
2512     options_idx_max = (u16_t)(options_idx_max - q->len);
2513     q = q->next;
2514   }
2515   if (q == NULL) {
2516     return ERR_BUF;
2517   }
2518   offset = options_idx;
2519   offset_max = options_idx_max;
2520   options = (u8_t *)q->payload;
2521   /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
2522   while ((q != NULL) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) {
2523     u8_t op = options[offset];
2524     u8_t len;
2525     u8_t decode_len = 0;
2526     int decode_idx = 0;
2527     u16_t val_offset = (u16_t)(offset + 2);
2528     if (val_offset < offset) {
2529       /* overflow */
2530       return ERR_BUF;
2531     }
2532     /* len byte might be in the next pbuf */
2533     if ((offset + 1) < q->len) {
2534       len = options[offset + 1];
2535     } else {
2536       len = (q->next != NULL ? ((u8_t *)q->next->payload)[0] : 0);
2537     }
2538     /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
2539     decode_len = len;
2540     switch (op) {
2541       /* case(DHCP_OPTION_END): handled above */
2542       case (DHCP_OPTION_PAD):
2543         /* special option: no len encoded */
2544         decode_len = len = 0;
2545         /* will be increased below */
2546         break;
2547       case (DHCP_OPTION_SUBNET_MASK):
2548         LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;);
2549         decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
2550         break;
2551       case (DHCP_OPTION_ROUTER):
2552         decode_len = 4; /* only copy the first given router */
2553         LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
2554         decode_idx = DHCP_OPTION_IDX_ROUTER;
2555         break;
2556 #if LWIP_DHCP_PROVIDE_DNS_SERVERS
2557       case (DHCP_OPTION_DNS_SERVER):
2558         /* special case: there might be more than one server */
2559         LWIP_DHCP_INPUT_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
2560         /* limit number of DNS servers */
2561 #if DNS_MAX_SERVERS > 64
2562 #error "Max number of servers can not be greater than 64"
2563 #endif
2564         decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
2565         LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
2566         decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
2567         break;
2568 #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
2569       case (DHCP_OPTION_LEASE_TIME):
2570         LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;);
2571         decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
2572         break;
2573 #if LWIP_DHCP_GET_NTP_SRV
2574       case (DHCP_OPTION_NTP):
2575         /* special case: there might be more than one server */
2576         LWIP_DHCP_INPUT_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
2577         /* limit number of NTP servers */
2578         decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS);
2579         LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
2580         decode_idx = DHCP_OPTION_IDX_NTP_SERVER;
2581         break;
2582 #endif /* LWIP_DHCP_GET_NTP_SRV*/
2583       case (DHCP_OPTION_OVERLOAD):
2584         LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL;);
2585         /* decode overload only in options, not in file/sname: invalid packet */
2586         LWIP_DHCP_INPUT_ERROR("overload in file/sname", options_offset == DHCP_OPTIONS_OFS, return ERR_VAL;);
2587         decode_idx = DHCP_OPTION_IDX_OVERLOAD;
2588         break;
2589       case (DHCP_OPTION_MESSAGE_TYPE):
2590         LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL;);
2591         decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
2592         break;
2593       case (DHCP_OPTION_SERVER_ID):
2594         LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;);
2595         decode_idx = DHCP_OPTION_IDX_SERVER_ID;
2596         break;
2597       case (DHCP_OPTION_T1):
2598         LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;);
2599         decode_idx = DHCP_OPTION_IDX_T1;
2600         break;
2601       case (DHCP_OPTION_T2):
2602         LWIP_DHCP_INPUT_ERROR("len == 4", len == 4, return ERR_VAL;);
2603         decode_idx = DHCP_OPTION_IDX_T2;
2604         break;
2605       default:
2606         decode_len = 0;
2607         LWIP_DEBUGF_LOG1(DHCP_DEBUG, "skipping option %"U16_F" in options\n", (u16_t)op);
2608         LWIP_HOOK_DHCP_PARSE_OPTION(ip_current_netif(), dhcp, dhcp->state, dhcp->msg_in,
2609                                     dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) ? (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) : 0,
2610                                     op, len, q, val_offset);
2611         break;
2612     }
2613     if (op == DHCP_OPTION_PAD) {
2614       offset++;
2615     } else {
2616       if (offset + len + 2 > 0xFFFF) {
2617         /* overflow */
2618         return ERR_BUF;
2619       }
2620       offset = (u16_t)(offset + len + 2);
2621       if (decode_len > 0) {
2622         u32_t value = 0;
2623         u16_t copy_len;
2624 decode_next:
2625         LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
2626         if (!dhcp_option_given(dhcp, decode_idx)) {
2627           copy_len = LWIP_MIN(decode_len, 4);
2628           if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) {
2629             return ERR_BUF;
2630           }
2631           if (decode_len > 4) {
2632             /* decode more than one u32_t */
2633             u16_t next_val_offset;
2634             LWIP_DHCP_INPUT_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
2635             dhcp_got_option(dhcp, decode_idx);
2636             dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value));
2637             decode_len = (u8_t)(decode_len - 4);
2638             next_val_offset = (u16_t)(val_offset + 4);
2639             if (next_val_offset < val_offset) {
2640               /* overflow */
2641               return ERR_BUF;
2642             }
2643             val_offset = next_val_offset;
2644             decode_idx++;
2645             goto decode_next;
2646           } else if (decode_len == 4) {
2647             value = lwip_ntohl(value);
2648           } else {
2649             LWIP_DHCP_INPUT_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
2650             value = ((u8_t *)&value)[0];
2651           }
2652           dhcp_got_option(dhcp, decode_idx);
2653           dhcp_set_option_value(dhcp, decode_idx, value);
2654         }
2655       }
2656     }
2657     if (offset >= q->len) {
2658       offset = (u16_t)(offset - q->len);
2659       offset_max = (u16_t)(offset_max - q->len);
2660       if (offset < offset_max) {
2661         q = q->next;
2662         LWIP_DHCP_INPUT_ERROR("next pbuf was null", q != NULL, return ERR_VAL;);
2663         options = (u8_t *)q->payload;
2664       } else {
2665         /* We've run out of bytes, probably no end marker. Don't proceed. */
2666         return ERR_BUF;
2667       }
2668     }
2669   }
2670   /* is this an overloaded message? */
2671   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
2672     u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
2673     dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
2674     if (overload == DHCP_OVERLOAD_FILE) {
2675       parse_file_as_options = 1;
2676       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
2677     } else if (overload == DHCP_OVERLOAD_SNAME) {
2678       parse_sname_as_options = 1;
2679       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
2680     } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
2681       parse_sname_as_options = 1;
2682       parse_file_as_options = 1;
2683       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
2684     } else {
2685       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
2686     }
2687   }
2688   if (parse_file_as_options) {
2689     /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
2690     parse_file_as_options = 0;
2691     options_idx = DHCP_FILE_OFS;
2692     options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
2693 #if LWIP_DHCP_BOOTP_FILE
2694     file_overloaded = 1;
2695 #endif
2696     goto again;
2697   } else if (parse_sname_as_options) {
2698     parse_sname_as_options = 0;
2699     options_idx = DHCP_SNAME_OFS;
2700     options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
2701     goto again;
2702   }
2703 #if LWIP_DHCP_BOOTP_FILE
2704   if (!file_overloaded) {
2705     /* only do this for ACK messages */
2706     if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
2707         (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) {
2708       /* copy bootp file name, don't care for sname (server hostname) */
2709       if (pbuf_copy_partial(p, netif_dhcp->boot_file_name, DHCP_FILE_LEN - 1, DHCP_FILE_OFS) != (DHCP_FILE_LEN - 1)) {
2710         return ERR_BUF;
2711       }
2712     }
2713     /* make sure the string is really NULL-terminated */
2714     netif_dhcp->boot_file_name[DHCP_FILE_LEN - 1] = 0;
2715   }
2716 #endif /* LWIP_DHCP_BOOTP_FILE */
2717   return ERR_OK;
2718 }
2719 
2720 /**
2721  * If an incoming DHCP message is in response to us, then trigger the state machine
2722  */
2723 static void
dhcp_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)2724 dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2725 {
2726   struct netif *netif = ip_current_input_netif();
2727   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
2728   struct dhcp_client *dhcp = NULL;
2729   struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
2730   u8_t msg_type;
2731   dhcp_num_t mac_idx;
2732   struct dhcp_state *dhcp_state = NULL;
2733   u8_t hwaddr_len;
2734   u32_t xid;
2735 #if LWIP_DHCP_SUBSTITUTE
2736   ip_addr_t server_id;
2737 #endif /* LWIP_DHCP_SUBSTITUTE */
2738 
2739   LWIP_UNUSED_ARG(arg);
2740 
2741   /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */
2742   if ((netif_dhcp == NULL) || (dhcp_pcb_refcount == 0)) {
2743     goto free_pbuf_and_return;
2744   }
2745 
2746   LWIP_ASSERT("invalid server address type", IP_IS_V4(addr));
2747 
2748   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,
2749               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));
2750   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
2751   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
2752   /* prevent warnings about unused arguments */
2753   LWIP_UNUSED_ARG(pcb);
2754   LWIP_UNUSED_ARG(addr);
2755   LWIP_UNUSED_ARG(port);
2756 
2757   if (p->len < DHCP_MIN_REPLY_LEN) {
2758     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
2759     goto free_pbuf_and_return;
2760   }
2761 
2762   if (reply_msg->op != DHCP_BOOTREPLY) {
2763     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
2764                      "not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op);
2765     goto free_pbuf_and_return;
2766   }
2767 
2768   dhcp = &(netif_dhcp->client);
2769 
2770   if (dhcp_mac_to_idx(netif, reply_msg->chaddr, reply_msg->hlen, &mac_idx) != ERR_OK) {
2771     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(): mac idx failed\n"));
2772     goto free_pbuf_and_return;
2773   }
2774   if (dhcp_client_find_by_mac_idx(dhcp, mac_idx, &(dhcp->cli_idx)) != ERR_OK) {
2775     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(): no client\n"));
2776     goto free_pbuf_and_return;
2777   }
2778   dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2779   if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
2780     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(): get mac failed\n"));
2781     goto free_pbuf_and_return;
2782   }
2783   dhcp_state->hwaddr_len = hwaddr_len;
2784 
2785   LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
2786 
2787   /* match transaction ID against what we expected */
2788   DHCP_XID(xid, dhcp->hwaddr, dhcp_state->hwaddr_len, dhcp_state->xid);
2789   if (lwip_ntohl(reply_msg->xid) != xid) {
2790     LWIP_DEBUGF_LOG2(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
2791                      "transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",
2792                      lwip_ntohl(reply_msg->xid), xid);
2793     goto free_pbuf_and_return;
2794   }
2795   /* option fields could be unfold? */
2796   if (dhcp_parse_reply(netif_dhcp, dhcp, p) != ERR_OK) {
2797     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
2798                      ("problem unfolding DHCP message - too short on memory?\n"));
2799     goto free_pbuf_and_return;
2800   }
2801 
2802 #if LWIP_DHCP_SUBSTITUTE
2803   /* to check if the server changed */
2804   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
2805     ip_addr_set_ip4_u32_val(server_id, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
2806     if (!(ip4_addr_isany_val(dhcp->server_ip_addr.u_addr.ip4)) &&
2807         !(ip4_addr_cmp(ip_2_ip4(&server_id), ip_2_ip4(&(dhcp->server_ip_addr))))) {
2808       LWIP_DEBUGF_LOG2(DHCP_DEBUG | LWIP_DBG_TRACE,
2809                        "%u diff serv_id %u\n", dhcp->cli_idx, ip_2_ip4(&server_id)->addr);
2810       if (dhcp->cli_idx != LWIP_DHCP_NATIVE_IDX) {
2811         goto free_pbuf_and_return;
2812       }
2813       dhcp_substitute_clients_restart(netif, dhcp);
2814       dhcp->cli_idx = LWIP_DHCP_NATIVE_IDX;
2815       if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
2816         LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(): get mac failed\n"));
2817         goto free_pbuf_and_return;
2818       }
2819       dhcp_state->hwaddr_len = hwaddr_len;
2820     }
2821   } else {
2822     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
2823                      "dhcp_recv(netif=%p) did not get server ID!\n", (void *)netif);
2824     goto free_pbuf_and_return;
2825   }
2826 #endif /* LWIP_DHCP_SUBSTITUTE */
2827   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
2828   /* obtain pointer to DHCP message type */
2829   if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
2830     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
2831                      ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
2832     goto free_pbuf_and_return;
2833   }
2834 
2835   /* read DHCP message type */
2836   msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
2837   /* message type is DHCP ACK? */
2838   if (msg_type == DHCP_ACK) {
2839     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
2840     /* in requesting state or just reconnected to the network? */
2841     if ((dhcp_state->state == DHCP_STATE_REQUESTING) ||
2842         (dhcp_state->state == DHCP_STATE_REBOOTING)) {
2843       dhcp_handle_ack(netif, dhcp);
2844 #if LWIP_DHCP_SUBSTITUTE
2845       ip4_addr_t cli_ip;
2846       dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
2847       if (dhcp_addr_clients_check(netif_dhcp, &cli_ip) == lwIP_TRUE) {
2848         LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
2849                          ("addr been used by substitute client\n"));
2850         (void)dhcp_decline(netif, dhcp);
2851         goto free_pbuf_and_return;
2852       }
2853 #endif /* LWIP_DHCP_SUBSTITUTE */
2854 #if DHCP_DOES_ARP_CHECK
2855       if (
2856 #if LWIP_DHCP_SUBSTITUTE_MMBR
2857           (dhcp_state->addr_not_dup_check == lwIP_FALSE) &&
2858 #endif
2859           ((netif->flags & NETIF_FLAG_ETHARP) != 0)) {
2860         /* check if the acknowledged lease address is already in use */
2861         dhcp_check(netif, dhcp);
2862       } else {
2863         /* bind interface to the acknowledged lease address */
2864         dhcp_bind(netif, dhcp);
2865       }
2866 #else
2867       /* bind interface to the acknowledged lease address */
2868       dhcp_bind(netif, dhcp);
2869 #endif
2870 #if LWIP_DHCP_SUBSTITUTE_MMBR
2871       dhcp_state->addr_not_dup_check = lwIP_FALSE;
2872 #endif /* LWIP_DHCP_SUBSTITUTE_MMBR */
2873     }
2874     /* already bound to the given lease address? */
2875     else if ((dhcp_state->state == DHCP_STATE_REBINDING) ||
2876              (dhcp_state->state == DHCP_STATE_RENEWING)) {
2877       dhcp_handle_ack(netif, dhcp);
2878       dhcp_bind(netif, dhcp);
2879     }
2880   }
2881   /* received a DHCP_NAK in appropriate state? */
2882   else if ((msg_type == DHCP_NAK) &&
2883            ((dhcp_state->state == DHCP_STATE_REBOOTING) || (dhcp_state->state == DHCP_STATE_REQUESTING) ||
2884             (dhcp_state->state == DHCP_STATE_REBINDING) || (dhcp_state->state == DHCP_STATE_RENEWING))) {
2885     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
2886 #if LWIP_DHCP_SUBSTITUTE_MMBR
2887     /* ignore the preferred IP if receive NAK */
2888     dhcp_state->addr_not_dup_check = lwIP_FALSE;
2889 #endif /* LWIP_DHCP_SUBSTITUTE_MMBR */
2890     dhcp_handle_nak(netif, dhcp);
2891   }
2892   /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */
2893   else if ((msg_type == DHCP_OFFER) && (dhcp_state->state == DHCP_STATE_SELECTING)) {
2894     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n"));
2895     /* remember offered lease */
2896     dhcp_handle_offer(netif, dhcp);
2897   }
2898 
2899 free_pbuf_and_return:
2900   if (dhcp != NULL) {
2901     dhcp->msg_in = NULL;
2902   }
2903   pbuf_free(p);
2904 }
2905 
2906 /**
2907  * Create a DHCP request, fill in common headers
2908  *
2909  * @param netif the netif under DHCP control
2910  * @param dhcp dhcp control struct
2911  * @param message_type message type of the request
2912  */
2913 static err_t
dhcp_create_msg(struct netif * netif,struct dhcp_client * dhcp,u8_t message_type,u16_t * options_out_len)2914 dhcp_create_msg(struct netif *netif, struct dhcp_client *dhcp, u8_t message_type, u16_t *options_out_len)
2915 {
2916   u16_t i;
2917   ip4_addr_t cli_ip;
2918   u16_t options_out_len_loc;
2919   struct dhcp_state *dhcp_state = NULL;
2920 
2921 #ifndef DHCP_GLOBAL_XID
2922   /** default global transaction identifier starting value (easy to match
2923    *  with a packet analyser). We simply increment for each new request.
2924    *  Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
2925    *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
2926 #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
2927   static u32_t xid;
2928 #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
2929   static u32_t xid = 0xABCD0000;
2930 #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
2931 #else
2932   if (!xid_initialised) {
2933     xid = DHCP_GLOBAL_XID;
2934     xid_initialised = !xid_initialised;
2935   }
2936 #endif
2937   LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG);
2938   LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL);
2939   LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL);
2940   LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
2941   dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
2942   dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
2943   if (dhcp->p_out == NULL) {
2944     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
2945                      ("dhcp_create_msg(): could not allocate pbuf\n"));
2946     return ERR_MEM;
2947   }
2948   LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
2949               (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
2950 
2951 #if DRIVER_STATUS_CHECK
2952   dhcp->p_out->flags |= PBUF_FLAG_DHCP_BUF;
2953 #endif
2954 
2955   /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */
2956   if ((message_type != DHCP_REQUEST) || (dhcp_state->state == DHCP_STATE_REBOOTING)) {
2957     /* reuse transaction identifier in retransmissions */
2958     if (dhcp_state->tries == 0) {
2959 #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
2960       xid = (u32_t)LWIP_RAND();
2961 #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
2962       xid++;
2963 #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
2964       dhcp_state->xid = (u8_t)xid;
2965     }
2966   }
2967   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE,
2968                    "transaction id xid(%"X32_F")\n", xid);
2969 
2970   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
2971   memset(dhcp->msg_out, 0, sizeof(struct dhcp_msg));
2972 
2973   dhcp->msg_out->op = DHCP_BOOTREQUEST;
2974 #if LWIP_ALWAYS_SEND_HWTYPE_AS_ETHER_IN_DHCP
2975   dhcp->msg_out->htype = LWIP_IANA_HWTYPE_ETHERNET;
2976 #else
2977   dhcp->msg_out->htype = (u8_t)(netif->link_layer_type & 0xFF);
2978 #endif
2979   dhcp->msg_out->hlen = dhcp_state->hwaddr_len;
2980   dhcp->msg_out->hops = 0;
2981   DHCP_XID(dhcp->msg_out->xid, dhcp->hwaddr, dhcp_state->hwaddr_len, dhcp_state->xid);
2982   dhcp->msg_out->xid = lwip_htonl(dhcp->msg_out->xid);
2983   dhcp->msg_out->secs = 0;
2984   /* we don't need the broadcast flag since we can receive unicast traffic
2985      before being fully configured! */
2986   dhcp->msg_out->flags = 0;
2987 #if LWIP_DHCP_SUBSTITUTE
2988   if (dhcp->cli_idx != LWIP_DHCP_NATIVE_IDX) {
2989     dhcp->msg_out->flags |= lwip_htons(DHCP_BROADCAST_FLAG);
2990   }
2991 #endif /* LWIP_DHCP_SUBSTITUTE */
2992   ip4_addr_set_zero(&dhcp->msg_out->ciaddr);
2993   /* set ciaddr to dhcp->offered_ip_addr based on message_type and state */
2994   if (message_type == DHCP_INFORM) {
2995     ip4_addr_copy(dhcp->msg_out->ciaddr, *netif_ip4_addr(netif));
2996   }
2997   if (((message_type == DHCP_DECLINE) &&
2998        ((dhcp_state->state == DHCP_STATE_BOUND) ||
2999         (dhcp_state->state == DHCP_STATE_RENEWING) ||
3000         (dhcp_state->state == DHCP_STATE_REBINDING))) ||
3001       (message_type == DHCP_RELEASE) ||
3002       ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */
3003        ((dhcp_state->state == DHCP_STATE_RENEWING) ||
3004         dhcp_state->state == DHCP_STATE_REBINDING))) {
3005     dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
3006     ip4_addr_copy(dhcp->msg_out->ciaddr, cli_ip);
3007   }
3008   ip4_addr_set_zero(&dhcp->msg_out->yiaddr);
3009   ip4_addr_set_zero(&dhcp->msg_out->siaddr);
3010   ip4_addr_set_zero(&dhcp->msg_out->giaddr);
3011   for (i = 0; i < LWIP_MIN(DHCP_CHADDR_LEN, NETIF_MAX_HWADDR_LEN); i++) {
3012     /* copy netif hardware address (padded with zeroes through memset already) */
3013     dhcp->msg_out->chaddr[i] = (u8_t)((i < dhcp_state->hwaddr_len &&
3014                                        i < NETIF_MAX_HWADDR_LEN) ? dhcp->hwaddr[i] : 0); /* pad byte */
3015   }
3016   for (i = 0; i < DHCP_SNAME_LEN; i++) {
3017     dhcp->msg_out->sname[i] = 0;
3018   }
3019   for (i = 0; i < DHCP_FILE_LEN; i++) {
3020     dhcp->msg_out->file[i] = 0;
3021   }
3022   dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
3023   dhcp->options_out_len = 0;
3024   /* fill options field with an incrementing array (for debugging purposes) */
3025   for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
3026     dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
3027   }
3028   /* Add option MESSAGE_TYPE */
3029   options_out_len_loc = dhcp_option(0, dhcp->msg_out->options, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
3030   options_out_len_loc = dhcp_option_byte(options_out_len_loc, dhcp->msg_out->options, message_type);
3031   if (options_out_len) {
3032     *options_out_len = options_out_len_loc;
3033   }
3034   return ERR_OK;
3035 }
3036 
3037 /**
3038  * Free previously allocated memory used to send a DHCP request.
3039  *
3040  * @param dhcp the dhcp struct to free the request from
3041  */
3042 static void
dhcp_delete_msg(struct dhcp_client * dhcp)3043 dhcp_delete_msg(struct dhcp_client *dhcp)
3044 {
3045   LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return);
3046   LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
3047   LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
3048   if (dhcp->p_out != NULL) {
3049     (void)pbuf_free(dhcp->p_out);
3050   }
3051   dhcp->p_out = NULL;
3052   dhcp->msg_out = NULL;
3053 }
3054 
3055 /**
3056  * Add a DHCP message trailer
3057  *
3058  * Adds the END option to the DHCP message, and if
3059  * necessary, up to three padding bytes.
3060  */
3061 static void
dhcp_option_trailer(u16_t options_out_len,u8_t * options,struct pbuf * p_out)3062 dhcp_option_trailer(u16_t options_out_len, u8_t *options, struct pbuf *p_out)
3063 {
3064   options[options_out_len++] = DHCP_OPTION_END;
3065   /* packet is too small, or not 4 byte aligned? */
3066   while (((options_out_len < DHCP_MIN_OPTIONS_LEN) || (options_out_len & 3)) &&
3067          (options_out_len < DHCP_OPTIONS_LEN)) {
3068     /* add a fill/padding byte */
3069     options[options_out_len++] = 0;
3070   }
3071   /* shrink the pbuf to the actual content length */
3072   pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + options_out_len));
3073 }
3074 
3075 /** check if DHCP supplied netif->ip_addr
3076  *
3077  * @param netif the netif to check
3078  * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING),
3079  *         0 otherwise
3080  */
3081 u8_t
dhcp_supplied_address(const struct netif * netif)3082 dhcp_supplied_address(const struct netif *netif)
3083 {
3084   struct dhcp *netif_dhcp = NULL;
3085   struct dhcp_state *dhcp_state = NULL;
3086   if (netif != NULL) {
3087     netif_dhcp = netif_dhcp_data(netif);
3088     if (netif_dhcp == NULL) {
3089       return 0;
3090     }
3091     dhcp_state = &((netif_dhcp->client.states)[LWIP_DHCP_NATIVE_IDX]);
3092     return (u8_t)((dhcp_state->state == DHCP_STATE_BOUND) ||
3093                   (dhcp_state->state == DHCP_STATE_RENEWING) ||
3094                   (dhcp_state->state == DHCP_STATE_REBINDING));
3095   }
3096   return 0;
3097 }
3098 
3099 #if LWIP_DHCP_SUBSTITUTE
3100 #if LWIP_ARP
3101 void
dhcp_events_record(struct netif * netif,u8_t flags)3102 dhcp_events_record(struct netif *netif, u8_t flags)
3103 {
3104   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
3105 
3106   if (netif_dhcp == NULL) {
3107     return;
3108   }
3109   netif_dhcp->flags |= flags;
3110 }
3111 
3112 static void
dhcp_clients_announce(struct netif * netif)3113 dhcp_clients_announce(struct netif *netif)
3114 {
3115   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
3116   struct dhcp_client *dhcp = &(netif_dhcp->client);
3117   struct dhcp_state *dhcp_state = NULL;
3118   dhcp_num_t i;
3119   u8_t hwaddr_len;
3120 
3121   /*
3122    * when hwaddr of netif is changed, for netif's dhcp client, it may keep use its IP
3123    * or restart dhcp client by APP to obtain a new IP
3124    */
3125   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
3126     dhcp_state = &((dhcp->states)[i]);
3127     if ((dhcp_state->state != DHCP_STATE_BOUND) && (dhcp_state->state != DHCP_STATE_RENEWING) &&
3128         (dhcp_state->state != DHCP_STATE_REBINDING)) {
3129       continue;
3130     }
3131     if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
3132       continue;
3133     }
3134     dhcp->cli_idx = (dhcp_num_t)i;
3135     dhcp_state->hwaddr_len = hwaddr_len;
3136     /*
3137      * set state to be DHCP_STATE_BOUND to send ARP Announce
3138      * states DHCP_STATE_RENEWING or DHCP_STATE_REBINDING can recover later
3139      */
3140     dhcp_set_state(dhcp, DHCP_STATE_BOUND);
3141     /* maybe old state was DHCP_STATE_BOUND, so try times need to reset here */
3142     dhcp_state->tries = 0;
3143     dhcp_announce(netif, dhcp);
3144   }
3145 }
3146 
3147 void
dhcp_events_trigger(struct netif * netif)3148 dhcp_events_trigger(struct netif *netif)
3149 {
3150   struct dhcp *netif_dhcp = NULL;
3151 
3152   if (!(netif_is_up(netif) && netif_is_link_up(netif))) {
3153     return;
3154   }
3155   netif_dhcp = netif_dhcp_data(netif);
3156   if (netif_dhcp == NULL) {
3157     return;
3158   }
3159   /* currently just support event DHCP_EVENT_HW */
3160   if ((netif_dhcp->flags & DHCP_EVENT_HW) == 0) {
3161     return;
3162   }
3163   if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
3164     /* hwaddr has been modified, must send ARP Announce */
3165     dhcp_clients_announce(netif);
3166   }
3167 
3168   /* clear flag DHCP_EVENT_HW */
3169   netif_dhcp->flags &= ~DHCP_EVENT_HW;
3170 }
3171 #endif /* LWIP_ARP */
3172 
3173 static void
dhcp_substitute_clients_restart(struct netif * netif,struct dhcp_client * dhcp)3174 dhcp_substitute_clients_restart(struct netif *netif, struct dhcp_client *dhcp)
3175 {
3176   int i;
3177   u8_t hwaddr_len;
3178   struct dhcp_state *dhcp_state = NULL;
3179 
3180   for (i = 1; i < DHCP_CLIENT_NUM; i++) {
3181     dhcp_state = &((dhcp->states)[i]);
3182     if ((dhcp_state->idx == 0)) {
3183       continue;
3184     }
3185     dhcp->cli_idx = (dhcp_num_t)i;
3186     if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
3187       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE,
3188                        "dhcp_substitute_clients_restart(): %u get mac failed\n", dhcp_state->idx);
3189       continue;
3190     }
3191     dhcp_state->hwaddr_len = hwaddr_len;
3192     (void)dhcp_release_client(netif, dhcp);
3193     (void)dhcp_discover(netif, dhcp);
3194   }
3195 
3196   return;
3197 }
3198 
3199 static s32_t
dhcp_addr_clients_check(struct dhcp * netif_dhcp,const ip4_addr_t * ipaddr)3200 dhcp_addr_clients_check(struct dhcp *netif_dhcp, const ip4_addr_t *ipaddr)
3201 {
3202   struct dhcp_client *dhcp = NULL;
3203   dhcp_num_t offered_ip_addr;
3204   struct dhcp_state *dhcp_state = NULL;
3205   int i;
3206 
3207   dhcp = &(netif_dhcp->client);
3208 
3209   DHCP_IP_TO_HOST(offered_ip_addr, ipaddr->addr, dhcp->offered_sn_mask.addr);
3210   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
3211     dhcp_state = &((dhcp->states)[i]);
3212     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
3213       continue;
3214     }
3215     if ((dhcp_state->state != DHCP_STATE_BOUND) && (dhcp_state->state != DHCP_STATE_RENEWING) &&
3216         (dhcp_state->state != DHCP_STATE_REBINDING)) {
3217       continue;
3218     }
3219     if (dhcp_state->offered_ip_addr == offered_ip_addr) {
3220       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_addr_clients_check(): %u used by substitute\n", ipaddr->addr);
3221       return lwIP_TRUE;
3222     }
3223   }
3224 
3225   return lwIP_FALSE;
3226 }
3227 
3228 err_t
dhcp_substitute_start(struct netif * netif,dhcp_num_t mac_idx,u32_t pref_ipv4)3229 dhcp_substitute_start(struct netif *netif, dhcp_num_t mac_idx, u32_t pref_ipv4)
3230 {
3231   err_t err;
3232   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
3233   LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG);
3234   LWIP_ERROR("mac_idx != LWIP_DHCP_NATIVE_IDX", (mac_idx != LWIP_DHCP_NATIVE_IDX), return ERR_ARG);
3235   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_substitute_start:%u\n", mac_idx);
3236 
3237   err = dhcp_start_client(netif, mac_idx, pref_ipv4);
3238   if (err == ERR_OK) {
3239     dhcp_clients_count_update(&(netif_dhcp_data(netif)->client));
3240   }
3241   return err;
3242 }
3243 
3244 #if LWIP_DHCP_SUBSTITUTE_MMBR
3245 /*
3246  * send ARP Request to check if there is an another MBR using this IP.
3247  * If receive the ARP Reply, then just think there is a MBR using this IP and should not send the Release message.
3248  * If we send the Release message, it may lead to that MBR renew IP failed and that MBR may get a different IP
3249  * from DHCP server.
3250  */
3251 static void
dhcp_release_check(struct netif * netif,struct dhcp_client * dhcp)3252 dhcp_release_check(struct netif *netif, struct dhcp_client *dhcp)
3253 {
3254   err_t result;
3255   u16_t msecs;
3256   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3257   ip4_addr_t cli_ip;
3258   dhcp_set_state(dhcp, DHCP_STATE_RELEASING);
3259   dhcp_get_client_ip(&cli_ip.addr, dhcp, dhcp_state);
3260   result = etharp_request(netif, &cli_ip);
3261   if (result != ERR_OK) {
3262     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
3263                      ("dhcp_release_check: could not perform ARP query\n"));
3264   }
3265   if (dhcp_state->tries < 255) {
3266     dhcp_state->tries++;
3267   }
3268   msecs = DHCP_FINE_TIMER_MSECS;
3269   dhcp_state->request_timeout = (u16_t)((msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS);
3270   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
3271                    "dhcp_release_check(): set request timeout %"U16_F" msecs\n", msecs);
3272 }
3273 #endif /* LWIP_DHCP_SUBSTITUTE_MMBR */
3274 
3275 void
dhcp_substitute_stop(struct netif * netif,dhcp_num_t mac_idx,u8_t now)3276 dhcp_substitute_stop(struct netif *netif, dhcp_num_t mac_idx, u8_t now)
3277 {
3278   struct dhcp_client *dhcp = NULL;
3279   struct dhcp *netif_dhcp = NULL;
3280   struct dhcp_state *dhcp_state = NULL;
3281   u8_t hwaddr_len;
3282   (void)now;
3283   LWIP_ERROR("netif != NULL", (netif != NULL), return);
3284   LWIP_ERROR("mac_idx != LWIP_DHCP_NATIVE_IDX", (mac_idx != LWIP_DHCP_NATIVE_IDX), return);
3285   LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_substitute_stop:%u\n", mac_idx);
3286 
3287   netif_dhcp = netif_dhcp_data(netif);
3288   if (netif_dhcp == NULL) {
3289     return;
3290   }
3291 
3292   dhcp = &(netif_dhcp->client);
3293   if (dhcp_client_find_by_mac_idx(dhcp, mac_idx, &(dhcp->cli_idx)) != ERR_OK) {
3294     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_substitute_stop(): client state not find for %u\n", mac_idx);
3295     return;
3296   }
3297 
3298   dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3299   if (dhcp_idx_to_mac(netif, dhcp_state->idx, dhcp->hwaddr, &hwaddr_len) != ERR_OK) {
3300     LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE, "dhcp_substitute_stop(): no client state for %u\n", mac_idx);
3301     return;
3302   }
3303   dhcp_state->hwaddr_len = hwaddr_len;
3304 
3305 #if LWIP_DHCP_SUBSTITUTE_MMBR
3306   if (now == lwIP_FALSE) {
3307     if ((dhcp_state->state == DHCP_STATE_BOUND) ||
3308         (dhcp_state->state == DHCP_STATE_RENEWING) ||
3309         (dhcp_state->state == DHCP_STATE_REBINDING)) {
3310       dhcp_release_check(netif, dhcp);
3311     } else if (dhcp_state->state == DHCP_STATE_RELEASING) {
3312       /* do nothing */
3313     } else {
3314       dhcp_stop_client(netif, dhcp);
3315     }
3316   } else
3317 #endif /* LWIP_DHCP_SUBSTITUTE_MMBR */
3318   {
3319     dhcp_stop_client(netif, dhcp);
3320   }
3321 
3322   return;
3323 }
3324 
3325 err_t
dhcp_substitute_idx_to_ip(struct netif * netif,dhcp_num_t idx,ip4_addr_t * ip)3326 dhcp_substitute_idx_to_ip(struct netif *netif, dhcp_num_t idx, ip4_addr_t *ip)
3327 {
3328   struct dhcp_client *dhcp = NULL;
3329   struct dhcp *netif_dhcp = NULL;
3330   struct dhcp_state *dhcp_state = NULL;
3331   int i;
3332 
3333   LWIP_ERROR("dhcp_substitute_idx_to_ip:netif != NULL", (netif != NULL), return ERR_ARG);
3334   LWIP_ERROR("dhcp_substitute_idx_to_ip:ip != NULL", (ip != NULL), return ERR_ARG);
3335 
3336   netif_dhcp = netif_dhcp_data(netif);
3337   if (netif_dhcp == NULL) {
3338     return ERR_VAL;
3339   }
3340   dhcp = &(netif_dhcp->client);
3341 
3342   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
3343     dhcp_state = &((dhcp->states)[i]);
3344     if ((dhcp_state->idx != idx)) {
3345       continue;
3346     }
3347     if ((dhcp_state->state != DHCP_STATE_BOUND) && (dhcp_state->state != DHCP_STATE_RENEWING) &&
3348         (dhcp_state->state != DHCP_STATE_REBINDING)) {
3349       return ERR_INPROGRESS;
3350     }
3351     dhcp_get_client_ip(&(ip->addr), dhcp, dhcp_state);
3352     return ERR_OK;
3353   }
3354 
3355   return ERR_VAL;
3356 }
3357 
3358 static struct dhcp_clients_info *
dhcp_clients_info_fill(struct netif * netif,dhcp_num_t cnt)3359 dhcp_clients_info_fill(struct netif *netif, dhcp_num_t cnt)
3360 {
3361   mem_size_t clis_info_size = sizeof(struct dhcp_clients_info) + cnt * sizeof(struct dhcp_client_mac_info);
3362   struct dhcp_clients_info *clis_info = (struct dhcp_clients_info *)mem_malloc(clis_info_size);
3363   struct dhcp_client_mac_info *cli = NULL;
3364   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
3365   struct dhcp_client *dhcp = &(netif_dhcp->client);
3366   struct dhcp_state *dhcp_state = NULL;
3367   dhcp_num_t i;
3368   dhcp_num_t fill_cnt = 0;
3369   u8_t hwaddr_len;
3370   LWIP_ERROR("dhcp_clients_info_fill:malloc fail\n", (clis_info != NULL), return NULL);
3371 
3372   (void)memset_s(clis_info, clis_info_size, 0, clis_info_size);
3373 
3374   for (i = 0; (i < DHCP_CLIENT_NUM) && (fill_cnt < cnt); i++) {
3375     dhcp_state = &((dhcp->states)[i]);
3376     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
3377       continue;
3378     }
3379     cli = &(clis_info->clis[fill_cnt]);
3380     if (dhcp_idx_to_mac(netif, dhcp_state->idx, cli->mac, &hwaddr_len) != ERR_OK) {
3381       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
3382                        "dhcp_clients_info_fill:idx %"DHCP_NUM_F" to mac failed\n", dhcp_state->idx);
3383       goto failure;
3384     }
3385     cli->mac_len = hwaddr_len;
3386     fill_cnt++;
3387   }
3388   clis_info->num = fill_cnt;
3389   return clis_info;
3390 failure:
3391   mem_free(clis_info);
3392   return NULL;
3393 }
3394 
3395 err_t
dhcp_clients_info_get(struct netif * netif,void * arg)3396 dhcp_clients_info_get(struct netif *netif, void *arg)
3397 {
3398   struct dhcp_clients_info **clis_info = (struct dhcp_clients_info **)arg;
3399   struct dhcp *netif_dhcp = NULL;
3400 
3401   LWIP_ERROR("dhcp_clients_info_get:netif != NULL\n", (netif != NULL), return ERR_ARG);
3402   LWIP_ERROR("dhcp_clients_info_get:clis_info != NULL\n", (clis_info != NULL), return ERR_ARG);
3403   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_clients_info_get:%s%hhu\n", netif->name, netif->num));
3404   netif_dhcp = netif_dhcp_data(netif);
3405   if (netif_dhcp == NULL) {
3406     return ERR_VAL;
3407   }
3408   if (netif_dhcp->clis_info != NULL) {
3409     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_clients_info_get:last not free\n"));
3410     return ERR_INPROGRESS;
3411   }
3412 
3413   if (netif_dhcp->client.cli_cnt == 0) {
3414     return ERR_VAL;
3415   }
3416   *clis_info = dhcp_clients_info_fill(netif, netif_dhcp->client.cli_cnt);
3417   if (*clis_info == NULL) {
3418     return ERR_MEM;
3419   }
3420   netif_dhcp->clis_info = *clis_info;
3421   return ERR_OK;
3422 }
3423 
3424 err_t
dhcp_clients_info_free(struct netif * netif,void * arg)3425 dhcp_clients_info_free(struct netif *netif, void *arg)
3426 {
3427   struct dhcp_clients_info **clis_info = (struct dhcp_clients_info **)arg;
3428   struct dhcp *netif_dhcp = NULL;
3429   LWIP_ERROR("dhcp_clients_info_free:netif != NULL\n", (netif != NULL), return ERR_ARG);
3430   LWIP_ERROR("dhcp_clients_info_free:clis_info != NULL\n", (clis_info != NULL), return ERR_ARG);
3431   LWIP_ERROR("dhcp_clients_info_free:*clis_info != NULL\n", (*clis_info != NULL), return ERR_ARG);
3432   netif_dhcp = netif_dhcp_data(netif);
3433   if (netif_dhcp == NULL) {
3434     return ERR_VAL;
3435   }
3436   if (netif_dhcp->clis_info != (*clis_info)) {
3437     return ERR_VAL;
3438   }
3439   mem_free(*clis_info);
3440   *clis_info = NULL;
3441   netif_dhcp->clis_info = NULL;
3442 
3443   return ERR_OK;
3444 }
3445 
3446 static void
dhcp_client_info_fill_ip4(struct dhcp_client_info * cli_info,struct dhcp_client * dhcp)3447 dhcp_client_info_fill_ip4(struct dhcp_client_info *cli_info, struct dhcp_client *dhcp)
3448 {
3449   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3450 
3451   if ((dhcp_state->state == DHCP_STATE_BOUND) || (dhcp_state->state == DHCP_STATE_RENEWING) ||
3452       (dhcp_state->state == DHCP_STATE_REBINDING)) {
3453     dhcp_get_client_ip(&(cli_info->ip4addr.addr), dhcp, dhcp_state);
3454   } else {
3455     ip4_addr_set_any(&(cli_info->ip4addr));
3456   }
3457 }
3458 
3459 static err_t
dhcp_native_ip6addr_get(struct dhcp_client_info * cli_info)3460 dhcp_native_ip6addr_get(struct dhcp_client_info *cli_info)
3461 {
3462 #if LWIP_RIPPLE
3463   struct netif *netif = (struct netif *)rpl_platform_get_dev();
3464   u8_t i;
3465   if (netif == NULL) {
3466     return ERR_VAL;
3467   }
3468   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
3469     if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
3470       continue;
3471     }
3472     if (ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
3473       continue;
3474     }
3475     (void)memcpy_s(&(cli_info->ip6addr), sizeof(ip6_addr_t), netif_ip6_addr(netif, i), sizeof(ip6_addr_t));
3476     return ERR_OK;
3477   }
3478   return ERR_VAL;
3479 #else
3480   (void)cli_info;
3481   return ERR_VAL;
3482 #endif
3483 }
3484 
3485 static err_t
dhcp_client_info_fill_ip6(struct dhcp_client_info * cli_info,struct dhcp_client * dhcp)3486 dhcp_client_info_fill_ip6(struct dhcp_client_info *cli_info, struct dhcp_client *dhcp)
3487 {
3488   if (dhcp->cli_idx == LWIP_DHCP_NATIVE_IDX) {
3489     return dhcp_native_ip6addr_get(cli_info);
3490   } else {
3491 #if LWIP_NAT64
3492     struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3493     if (nat64_entry_idx_to_ip6addr(dhcp_state->idx, &(cli_info->ip6addr))) {
3494       LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
3495                        "dhcp_client_info_fill_ip6:get ip6addr failed\n");
3496       return ERR_VAL;
3497     }
3498 #else
3499     return ERR_VAL;
3500 #endif
3501   }
3502   return ERR_OK;
3503 }
3504 
3505 static err_t
dhcp_client_info_fill(struct dhcp_client_info * cli_info,struct dhcp_client * dhcp)3506 dhcp_client_info_fill(struct dhcp_client_info *cli_info, struct dhcp_client *dhcp)
3507 {
3508   dhcp_client_info_fill_ip4(cli_info, dhcp);
3509 
3510   return dhcp_client_info_fill_ip6(cli_info, dhcp);
3511 }
3512 
3513 err_t
dhcp_client_info_find(struct netif * netif,void * cli_info)3514 dhcp_client_info_find(struct netif *netif, void *cli_info)
3515 {
3516   struct dhcp_client_info *cli_info_p = (struct dhcp_client_info *)cli_info;
3517   err_t err;
3518   struct dhcp *netif_dhcp = NULL;
3519   dhcp_num_t mac_idx;
3520 
3521   LWIP_ERROR("dhcp_client_info_find:netif != NULL\n", (netif != NULL), return ERR_ARG);
3522   LWIP_ERROR("dhcp_client_info_find:cli_info_p != NULL\n", (cli_info_p != NULL), return ERR_ARG);
3523   netif_dhcp = netif_dhcp_data(netif);
3524   if (netif_dhcp == NULL) {
3525     return ERR_VAL;
3526   }
3527 
3528   err = dhcp_mac_to_idx(netif, cli_info_p->mac, cli_info_p->mac_len, &mac_idx);
3529   if (err != ERR_OK) {
3530     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_client_info_find(): mac idx failed\n"));
3531     return ERR_VAL;
3532   }
3533 
3534   if (dhcp_client_find_by_mac_idx(&(netif_dhcp->client), mac_idx, &(netif_dhcp->client.cli_idx)) != ERR_OK) {
3535     LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(): no client\n"));
3536     return ERR_VAL;
3537   }
3538 
3539   return dhcp_client_info_fill(cli_info_p, &(netif_dhcp->client));
3540 }
3541 
3542 #if LWIP_ENABLE_BASIC_SHELL_CMD
3543 s32_t
dhcp_netif_addr_clients_check(const struct netif * netif,const ip4_addr_t * ipaddr)3544 dhcp_netif_addr_clients_check(const struct netif *netif, const ip4_addr_t *ipaddr)
3545 {
3546   struct dhcp *netif_dhcp = NULL;
3547 
3548   if ((netif == NULL) || (ipaddr == NULL)) {
3549     return lwIP_FALSE;
3550   }
3551 
3552   netif_dhcp = netif_dhcp_data(netif);
3553   if (netif_dhcp == NULL) {
3554     return lwIP_FALSE;
3555   }
3556 
3557   return dhcp_addr_clients_check(netif_dhcp, ipaddr);
3558 }
3559 #endif /* LWIP_ENABLE_BASIC_SHELL_CMD */
3560 
3561 #if LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS
3562 static void
dhcp_concurrent_limit_wait_timeout(struct netif * netif,struct dhcp_client * dhcp)3563 dhcp_concurrent_limit_wait_timeout(struct netif *netif, struct dhcp_client *dhcp)
3564 {
3565   if (dhcp_concurrent_start_client(dhcp) != ERR_OK) {
3566     return;
3567   }
3568   if (!netif_is_link_up(netif)) {
3569     /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */
3570     dhcp_set_state(dhcp, DHCP_STATE_INIT);
3571     return;
3572   }
3573 
3574   (void)dhcp_discover(netif, dhcp);
3575 
3576   return;
3577 }
3578 
3579 static u8_t
dhcp_client_request_processing(u8_t state)3580 dhcp_client_request_processing(u8_t state)
3581 {
3582   u8_t is_processing;
3583 
3584   switch (state) {
3585     case DHCP_STATE_REQUESTING:
3586     case DHCP_STATE_INIT:
3587     case DHCP_STATE_REBOOTING:
3588     case DHCP_STATE_SELECTING:
3589     case DHCP_STATE_CHECKING:
3590     case DHCP_STATE_BACKING_OFF:
3591       is_processing = lwIP_TRUE;
3592       break;
3593     default:
3594       is_processing = lwIP_FALSE;
3595       break;
3596   }
3597 
3598   return is_processing;
3599 }
3600 
3601 static err_t
dhcp_concurrent_start_client(struct dhcp_client * dhcp)3602 dhcp_concurrent_start_client(struct dhcp_client *dhcp)
3603 {
3604   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3605   if (g_dhcp_max_concurrent_num != 0) {
3606     if (dhcp->rqst_cli_cnt >= g_dhcp_max_concurrent_num) {
3607       dhcp_set_state(dhcp, DHCP_STATE_LIMIT_WAIT);
3608       dhcp_state->request_timeout = 1;
3609       return ERR_INPROGRESS;
3610     }
3611     dhcp->rqst_cli_cnt++;
3612   }
3613   return ERR_OK;
3614 }
3615 
3616 static void
dhcp_concurrent_stop_client(struct dhcp_client * dhcp)3617 dhcp_concurrent_stop_client(struct dhcp_client *dhcp)
3618 {
3619   struct dhcp_state *dhcp_state = &((dhcp->states)[dhcp->cli_idx]);
3620 
3621   if (g_dhcp_max_concurrent_num == 0) {
3622     return;
3623   }
3624 
3625   if (dhcp_client_request_processing(dhcp_state->state) == lwIP_TRUE) {
3626     dhcp->rqst_cli_cnt--;
3627   }
3628 
3629   return;
3630 }
3631 
3632 static void
dhcp_concurrent_start_next_client(struct netif * netif,u8_t all)3633 dhcp_concurrent_start_next_client(struct netif *netif, u8_t all)
3634 {
3635   struct dhcp *netif_dhcp = netif_dhcp_data(netif);
3636   struct dhcp_state *dhcp_state = NULL;
3637   int i;
3638   u8_t hwaddr_len;
3639 
3640   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
3641     netif_dhcp->client.cli_idx = (dhcp_num_t)i;
3642     dhcp_state = &((netif_dhcp->client.states)[i]);
3643     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
3644       continue;
3645     }
3646     if (dhcp_state->state != DHCP_STATE_LIMIT_WAIT) {
3647       continue;
3648     }
3649     if (dhcp_idx_to_mac(netif, dhcp_state->idx, netif_dhcp->client.hwaddr, &hwaddr_len) != ERR_OK) {
3650       LWIP_DEBUGF_LOG1(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
3651                        "dhcp_concurrent_start_next_client:idx %u to mac failed\n", dhcp_state->idx);
3652       continue;
3653     }
3654     dhcp_state->hwaddr_len = hwaddr_len;
3655     (void)dhcp_discover(netif, &(netif_dhcp->client));
3656     if (all == lwIP_FALSE) {
3657       (netif_dhcp->client.rqst_cli_cnt)++;
3658       break;
3659     }
3660   }
3661 
3662   return;
3663 }
3664 
3665 static void
dhcp_concurrent_num_update(struct dhcp_client * dhcp)3666 dhcp_concurrent_num_update(struct dhcp_client *dhcp)
3667 {
3668   struct dhcp_state *dhcp_state = NULL;
3669   int i;
3670 
3671   dhcp->rqst_cli_cnt = 0;
3672   for (i = 0; i < DHCP_CLIENT_NUM; i++) {
3673     dhcp->cli_idx = (dhcp_num_t)i;
3674     dhcp_state = &((dhcp->states)[i]);
3675     if ((i != LWIP_DHCP_NATIVE_IDX) && (dhcp_state->idx == 0)) {
3676       continue;
3677     }
3678     if (dhcp_client_request_processing(dhcp_state->state) == lwIP_FALSE) {
3679       continue;
3680     }
3681     if (dhcp->rqst_cli_cnt < g_dhcp_max_concurrent_num) {
3682       dhcp->rqst_cli_cnt++;
3683     } else {
3684       dhcp_set_state(dhcp, DHCP_STATE_LIMIT_WAIT);
3685       dhcp_state->request_timeout = 1;
3686     }
3687   }
3688 
3689   return;
3690 }
3691 
3692 err_t
dhcp_set_max_concurrent_num(struct netif * netif,u16_t dhcp_max_concurrent_num)3693 dhcp_set_max_concurrent_num(struct netif *netif, u16_t dhcp_max_concurrent_num)
3694 {
3695   struct dhcp *netif_dhcp = NULL;
3696   struct dhcp_client *dhcp = NULL;
3697 
3698   LWIP_DEBUGF_LOG0(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_set_max_concurrent_num()\n"));
3699   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
3700   netif_dhcp = netif_dhcp_data(netif);
3701   LWIP_ERROR("netif_dhcp != NULL", (netif_dhcp != NULL), return ERR_VAL);
3702 
3703   dhcp = &(netif_dhcp->client);
3704   if (dhcp_max_concurrent_num == 0) {
3705     g_dhcp_max_concurrent_num = 0;
3706     dhcp->rqst_cli_cnt = 0;
3707     dhcp_concurrent_start_next_client(netif, lwIP_TRUE);
3708   } else {
3709     g_dhcp_max_concurrent_num = dhcp_max_concurrent_num;
3710     dhcp_concurrent_num_update(dhcp);
3711   }
3712 
3713   return ERR_OK;
3714 }
3715 #endif /* LWIP_DHCP_LIMIT_CONCURRENT_REQUESTS */
3716 #endif /* LWIP_DHCP_SUBSTITUTE */
3717 
3718 #endif /* LWIP_IPV4 && LWIP_DHCP */
3719