• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: implementation for IPv4 DHCP server
15  * Author: none
16  * Create: 2020
17  */
18 
19 #include "lwip/opt.h"
20 
21 #if (LWIP_DHCP) && (LWIP_DHCPS) /* don't build if not configured for use in lwipopts.h */
22 #include <string.h>
23 
24 #include "lwip/stats.h"
25 #include "lwip/mem.h"
26 #include "lwip/udp.h"
27 #include "lwip/ip_addr.h"
28 #include "lwip/netif.h"
29 #include "lwip/def.h"
30 #include "lwip/prot/dhcp.h"
31 #include "lwip/prot/iana.h"
32 #include "lwip/dhcp.h"
33 #include "lwip/dhcps.h"
34 #include "lwip/sys.h"
35 #include "netif/etharp.h"
36 #if LWIP_DHCPS_DNS_OPTION
37 #include "lwip/dns.h"
38 #endif /* LWIP_DHCPS_DNS_OPTION */
39 
40 #define DHCPS_ADDRESS_FREE 0x0
41 #define DHCPS_ADDRESS_OFFERRED 0x1
42 #define DHCPS_ADDRESS_BOUND 0x2
43 #define DHCPS_ADDRESS_DECLINED 0x3
44 
45 u32_t dhcps_rx_options_val[DHCP_OPTION_IDX_MAX];
46 u8_t  dhcps_rx_options_given[DHCP_OPTION_IDX_MAX];
47 #if LWIP_DHCPS_AGENT_INFO
48 static u16_t g_dhcp_op_agent_info_len = 0;
49 #endif
50 
51 #define dhcps_option_given(dhcp, idx)          (dhcps_rx_options_given[idx] != 0)
52 #define dhcps_got_option(dhcp, idx)            (dhcps_rx_options_given[idx] = 1)
53 #define dhcps_clear_option(dhcp, idx)          (dhcps_rx_options_given[idx] = 0)
54 #define dhcps_get_option_value(dhcp, idx)      (dhcps_rx_options_val[idx])
55 #define dhcps_set_option_value(dhcp, idx, val) (dhcps_rx_options_val[idx] = (val))
56 
57 static struct pbuf *dhcps_create_base_msg(const struct dhcp_msg *client_msg);
58 static void remove_stale_entries(struct dhcps *dhcps);
59 static void add_client_entry(struct dhcps *dhcps, unsigned int idx, const struct dhcp_msg *client_msg);
60 static int find_free_slot(const struct dhcps *dhcps);
61 static struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, const struct dhcp_msg *client_msg);
62 static ip4_addr_t validate_discover(struct dhcps *dhcps, const struct dhcp_msg *client_msg,
63                                     struct dyn_lease_addr **client_lease);
64 static void handle_discover(struct netif *netif, struct dhcps *dhcps, const struct dhcp_msg *client_msg,
65                             struct dyn_lease_addr *client_lease);
66 static ip4_addr_t validate_request_message(const struct netif *netif, const struct dhcp_msg *client_msg,
67                                            const struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
68 static void handle_request(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
69                            struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
70 static void handle_decline(const struct dhcp_msg *client_msg, struct dyn_lease_addr *client_lease);
71 static void handle_inform(struct netif *netif, struct dhcps *dhcps, const struct dhcp_msg *client_msg);
72 static void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
73                                    struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type);
74 static void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
75                        const ip_addr_t *ip_addr, u16_t port);
76 
dhcps_create_base_msg(const struct dhcp_msg * client_msg)77 static struct pbuf *dhcps_create_base_msg(const struct dhcp_msg *client_msg)
78 {
79   struct pbuf *srvr_msg_pbuf = NULL;
80   struct dhcp_msg *srvr_msg = NULL;
81 #if LWIP_DHCPS_AGENT_INFO
82   u16_t append_len = 0;
83 
84   if (dhcps_option_given(NULL, DHCP_OPTION_IDX_AGENT_INFO)) {
85     append_len = g_dhcp_op_agent_info_len;
86   }
87 
88   srvr_msg_pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg) + append_len, PBUF_RAM);
89 #else
90   srvr_msg_pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
91 #endif /* LWIP_DHCPS_AGENT_INFO */
92   if (srvr_msg_pbuf == NULL) {
93     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
94                 ("dhcps_create_base_msg(): could not allocate pbuf\n"));
95     return NULL;
96   }
97 
98   LWIP_ASSERT("dhcps_create_base_msg: check that first pbuf can hold struct dhcp_msg",
99               (srvr_msg_pbuf->len >= sizeof(struct dhcp_msg)));
100 #if DRIVER_STATUS_CHECK
101   srvr_msg_pbuf->flags |= PBUF_FLAG_DHCP_BUF;
102 #endif
103   srvr_msg = (struct dhcp_msg *)srvr_msg_pbuf->payload;
104   srvr_msg->op = DHCP_BOOTREPLY;
105   srvr_msg->htype = client_msg->htype;
106   srvr_msg->hlen = client_msg->hlen;
107   srvr_msg->hops = client_msg->hops;
108   srvr_msg->xid = client_msg->xid;
109   srvr_msg->secs = 0;
110   srvr_msg->flags = client_msg->flags;
111   ip4_addr_set_zero(&srvr_msg->ciaddr);
112   ip4_addr_set_zero(&srvr_msg->yiaddr);
113   ip4_addr_set_zero(&srvr_msg->siaddr);
114   ip4_addr_copy(srvr_msg->giaddr, client_msg->giaddr);
115 
116   if (memcpy_s(srvr_msg->chaddr, sizeof(srvr_msg->chaddr), client_msg->chaddr, DHCP_CHADDR_LEN) != EOK) {
117     (void)pbuf_free(srvr_msg_pbuf);
118     return NULL;
119   }
120   (void)memset_s(srvr_msg->sname, DHCP_SNAME_LEN, 0, DHCP_SNAME_LEN);
121   (void)memset_s(srvr_msg->file, DHCP_FILE_LEN, 0, DHCP_FILE_LEN);
122   srvr_msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
123 
124   return srvr_msg_pbuf;
125 }
126 
remove_stale_entries(struct dhcps * dhcps)127 static void remove_stale_entries(struct dhcps *dhcps)
128 {
129   uint32_t i = 0;
130   u32_t curr_time = sys_now();
131 
132   for (i = 0; i < dhcps->lease_num; i++) {
133     /* Slot should not be free or have infinite lease time */
134     if ((dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) && (dhcps->leasearr[i].leasetime != (u32_t)~0)) {
135       if (dhcps->leasearr[i].leasetime < curr_time) {
136         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
137                     ("remove_stale_entries: Removing Client Entry at Index = %"U32_F"\n", i));
138         (void)memset_s(&(dhcps->leasearr[i]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
139         dhcps->leasearr[i].flags = DHCPS_ADDRESS_FREE;
140       }
141     }
142   }
143 }
144 
add_client_entry(struct dhcps * dhcps,unsigned int idx,const struct dhcp_msg * client_msg)145 static void add_client_entry(struct dhcps *dhcps, unsigned int idx, const struct dhcp_msg *client_msg)
146 {
147   u32_t client_lease_time = (u32_t)(LWIP_DHCPS_LEASE_TIME);
148 
149   if ((dhcps_option_given(NULL, DHCP_OPTION_IDX_LEASE_TIME))
150 #if (LWIP_DHCPS_LEASE_TIME != ~0)
151     && (dhcps_get_option_value(NULL, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
152 #endif
153     ) {
154     client_lease_time = (u32_t)dhcps_get_option_value(NULL, DHCP_OPTION_IDX_LEASE_TIME);
155   }
156 
157   (void)memset_s(&(dhcps->leasearr[idx]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
158   if (memcpy_s(dhcps->leasearr[idx].cli_hwaddr, DHCP_CHADDR_LEN,
159                client_msg->chaddr, sizeof(client_msg->chaddr)) != EOK) {
160     return;
161   }
162   /* This is called only during offer message, so adding offer time.
163     This is later updated to lease time when request message is handled */
164   dhcps->leasearr[idx].leasetime = sys_now() + (LWIP_DHCPS_OFFER_TIME * MS_PER_SECOND);
165   dhcps->leasearr[idx].cli_addr.addr = dhcps->start_addr.addr + idx;
166   dhcps->leasearr[idx].flags = DHCPS_ADDRESS_OFFERRED;
167   dhcps->leasearr[idx].proposed_leasetime = client_lease_time;
168   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("add_client_entry: Adding Client Entry at Index = %"U32_F"\n", idx));
169 }
170 
find_free_slot(const struct dhcps * dhcps)171 static int find_free_slot(const struct dhcps *dhcps)
172 {
173   int i;
174   for (i = 0; i < (int)dhcps->lease_num; i++) {
175     if ((dhcps->leasearr[i].flags == DHCPS_ADDRESS_FREE) &&
176       (htonl(dhcps->start_addr.addr + (u32_t)i) != ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
177       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("find_free_slot: Found Free Slot at Index = %"U32_F"\n", i));
178       return i;
179     }
180   }
181 
182   return -1;
183 }
184 
find_client_lease(struct dhcps * dhcps,const struct dhcp_msg * client_msg)185 static struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, const struct dhcp_msg *client_msg)
186 {
187   uint8_t i;
188   for (i = 0; i < dhcps->lease_num; i++) {
189     if (dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) {
190       if (memcmp(dhcps->leasearr[i].cli_hwaddr, client_msg->chaddr, client_msg->hlen) == 0) {
191         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("find_client_lease: Found Client Lease at Index = %"U32_F"\n", i));
192         return &(dhcps->leasearr[i]);
193       }
194     }
195   }
196 
197   return NULL;
198 }
199 
dhcps_find_client_lease(struct netif * netif,const u8_t * mac,u8_t maclen,ip_addr_t * ip)200 err_t dhcps_find_client_lease(struct netif *netif, const u8_t *mac, u8_t maclen, ip_addr_t *ip)
201 {
202   struct dhcps *dhcps = NULL;
203   u8_t i;
204 
205   if ((netif == NULL) || (netif->dhcps == NULL) || (ip == NULL) ||
206       (mac == NULL) || (maclen < ETH_HWADDR_LEN) || (maclen > DHCP_CHADDR_LEN)) {
207     return ERR_ARG;
208   }
209 
210   dhcps = netif->dhcps;
211 
212   for (i = 0; i < dhcps->lease_num; i++) {
213     if (dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) {
214       if (memcmp(dhcps->leasearr[i].cli_hwaddr, mac, maclen) == 0) {
215         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("find_client_lease: Found Client Lease at Index = %"U32_F"\n", i));
216         ip_addr_copy_from_ip4(*ip, dhcps->leasearr[i].cli_addr);
217         return ERR_OK;
218       }
219     }
220   }
221 
222   return ERR_ARG;
223 }
224 
validate_discover(struct dhcps * dhcps,const struct dhcp_msg * client_msg,struct dyn_lease_addr ** client_lease)225 static ip4_addr_t validate_discover(struct dhcps *dhcps, const struct dhcp_msg *client_msg,
226                                     struct dyn_lease_addr **client_lease)
227 {
228   ip4_addr_t client_ip;
229   int idx = -1;
230 
231   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Validating Discover Message\n"));
232 
233   client_ip.addr = 0;
234   if (*client_lease == NULL) {
235     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Existing Client Lease not Found\n"));
236     if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
237       client_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
238 #ifdef  LWIP_DEV_DEBUG
239       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
240                   ("validate_discover function: Requested IP from client = %"U32_F"\n", client_ip.addr));
241 #endif
242 
243       if ((client_ip.addr >= dhcps->start_addr.addr) && (client_ip.addr <= dhcps->end_addr.addr)) {
244         idx = (int)(client_ip.addr - dhcps->start_addr.addr);
245         if ((dhcps->leasearr[idx].flags != DHCPS_ADDRESS_FREE) ||
246             (ntohl(client_ip.addr) == ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
247           /* Requested IP is not available */
248 #ifdef  LWIP_DEV_DEBUG
249           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
250             ("validate_discover function: Requested IP from client = %"U32_F" Not available \n", client_ip.addr));
251 #endif
252           idx = -1;
253         }
254       }
255     }
256 
257     if (idx == -1) {
258       idx = find_free_slot(dhcps);
259       if (idx == -1) {
260         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
261                     ("validate_discover function: No Free Slot available for Storing addresses\n"));
262         client_ip.addr = 0;
263         return client_ip;
264       }
265       client_ip.addr =  dhcps->start_addr.addr + (u32_t)idx;
266 #ifdef  LWIP_DEV_DEBUG
267       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
268                   ("validate_discover function: New IP = %"U32_F" is being assigned\n", client_ip.addr));
269 #endif
270     }
271 
272     add_client_entry(dhcps, (unsigned int)idx, client_msg);
273     (*client_lease) = &(dhcps->leasearr[idx]);
274   } else {
275     client_ip.addr = (*client_lease)->cli_addr.addr;
276 #ifdef  LWIP_DEV_DEBUG
277     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
278                 ("validate_discover: Existing Client Lease Found. Existing IP =%"U32_F"\n", client_ip.addr));
279 #endif
280 
281     if ((dhcps_option_given(NULL, DHCP_OPTION_IDX_LEASE_TIME))
282 #if (~0 != LWIP_DHCPS_LEASE_TIME)
283       && (dhcps_get_option_value(NULL, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
284 #endif
285       ) {
286       /* Assign the newly requested time or else use the existing lease time as-is */
287       (*client_lease)->proposed_leasetime = (u32_t)dhcps_get_option_value(NULL, DHCP_OPTION_IDX_LEASE_TIME);
288     }
289   }
290 
291   return client_ip;
292 }
293 
dhcp_common_option(struct dhcp_msg * msg_out,u8_t option_type,u8_t option_len,u16_t * options_out_len)294 void dhcp_common_option(struct dhcp_msg *msg_out, u8_t option_type, u8_t option_len, u16_t *options_out_len)
295 {
296   LWIP_DHCP_INPUT_ERROR("dhcps_option: options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN",
297                         (*options_out_len) + 2U + option_len <= DHCP_OPTIONS_LEN, return);
298   msg_out->options[(*options_out_len)++] = option_type;
299   msg_out->options[(*options_out_len)++] = option_len;
300 }
301 /*
302  * Concatenate a single byte to the outgoing DHCP message.
303  *
304  */
dhcp_common_option_byte(struct dhcp_msg * msg_out,u8_t value,u16_t * options_out_len)305 void dhcp_common_option_byte(struct dhcp_msg *msg_out, u8_t value, u16_t *options_out_len)
306 {
307   LWIP_DHCP_INPUT_ERROR("dhcps_option_byte: options_out_len < DHCP_OPTIONS_LEN",
308                         (*options_out_len) < DHCP_OPTIONS_LEN, return);
309   msg_out->options[(*options_out_len)++] = value;
310 }
311 
dhcp_common_option_short(struct dhcp_msg * msg_out,u16_t value,u16_t * options_out_len)312 void dhcp_common_option_short(struct dhcp_msg *msg_out, u16_t value, u16_t *options_out_len)
313 {
314   LWIP_DHCP_INPUT_ERROR("dhcps_option_short: options_out_len + 2 <= DHCP_OPTIONS_LEN",
315                         (*options_out_len) + 2U <= DHCP_OPTIONS_LEN, return);
316   msg_out->options[(*options_out_len)++] = (u8_t)((value & 0xff00U) >> 8);
317   msg_out->options[(*options_out_len)++] = (u8_t)(value & 0x00ffU);
318 }
319 
dhcp_common_option_long(struct dhcp_msg * msg_out,u32_t value,u16_t * options_out_len)320 void dhcp_common_option_long(struct dhcp_msg *msg_out, u32_t value, u16_t *options_out_len)
321 {
322   LWIP_DHCP_INPUT_ERROR("dhcp_option_long: options_out_len + 4 <= DHCP_OPTIONS_LEN",
323                         (*options_out_len) + 4U <= DHCP_OPTIONS_LEN, return);
324   msg_out->options[(*options_out_len)++] = (u8_t)((value & 0xff000000UL) >> 24);
325   msg_out->options[(*options_out_len)++] = (u8_t)((value & 0x00ff0000UL) >> 16);
326   msg_out->options[(*options_out_len)++] = (u8_t)((value & 0x0000ff00UL) >> 8);
327   msg_out->options[(*options_out_len)++] = (u8_t)((value & 0x000000ffUL));
328 }
329 
dhcp_common_option_trailer(struct dhcp_msg * msg_out,u16_t * options_out_len)330 void dhcp_common_option_trailer(struct dhcp_msg *msg_out, u16_t *options_out_len)
331 {
332   LWIP_DHCP_INPUT_ERROR("dhcp_common_option_trailer: options_out_len < DHCP_OPTIONS_LEN",
333                         (*options_out_len) < DHCP_OPTIONS_LEN, return);
334   msg_out->options[(*options_out_len)++] = DHCP_OPTION_END;
335   /* packet is too small, or not 4 byte aligned? */
336   while ((((*options_out_len) < DHCP_MIN_OPTIONS_LEN) || ((*options_out_len) & 3)) &&
337          ((*options_out_len) < DHCP_OPTIONS_LEN)) {
338     /* add a fill/padding byte */
339     msg_out->options[(*options_out_len)++] = 0;
340   }
341 }
342 
343 #if LWIP_DHCPS_DNS_OPTION
344 static void
dhcp_option_dns_server(struct dhcp_msg * msg_out,struct netif * netif,u16_t * options_out_len)345 dhcp_option_dns_server(struct dhcp_msg *msg_out, struct netif *netif, u16_t *options_out_len)
346 {
347   u8_t dns_option_len = 0;
348   u8_t i;
349   const ip_addr_t *dns_addr = NULL;
350 
351   for (i = 0; i < DNS_MAX_SERVERS; i++) {
352     dns_addr = dns_getserver(i);
353     if (IP_IS_V4(dns_addr) && !(ip4_addr_isany(ip_2_ip4(dns_addr)))) {
354       /* 4 :four byte ipv4 address */
355       dns_option_len = (u8_t)(dns_option_len + 4);
356     }
357   }
358 
359   if (dns_option_len > 0) {
360     LWIP_DHCP_INPUT_ERROR("dhcp_option_dns_server: options_out_len + dns_option_len <= DHCP_OPTIONS_LEN",
361                           (*options_out_len) + dns_option_len <= DHCP_OPTIONS_LEN, return);
362     dhcp_common_option(msg_out, DHCP_OPTION_DNS_SERVER, dns_option_len, options_out_len);
363     for (i = 0; i < DNS_MAX_SERVERS; i++) {
364       dns_addr = dns_getserver(i);
365       if (IP_IS_V4(dns_addr) && !(ip4_addr_isany(ip_2_ip4(dns_addr)))) {
366         dhcp_common_option_long(msg_out, ntohl(ip4_addr_get_u32(ip_2_ip4(dns_addr))), options_out_len);
367       }
368     }
369   } else {
370     LWIP_DHCP_INPUT_ERROR("dhcp_option_dns_server: options_out_len + 4 <= DHCP_OPTIONS_LEN",
371                           (*options_out_len) + 4U <= DHCP_OPTIONS_LEN, return);
372     dhcp_common_option(msg_out, DHCP_OPTION_DNS_SERVER, 4, options_out_len);
373     dhcp_common_option_long(msg_out, ntohl(ip4_addr_get_u32(ip_2_ip4(&netif->ip_addr))), options_out_len);
374   }
375 
376   return;
377 }
378 #endif /* LWIP_DHCPS_DNS_OPTION */
379 
handle_discover(struct netif * netif,struct dhcps * dhcps,const struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease)380 static void handle_discover(struct netif *netif, struct dhcps *dhcps,
381                             const struct dhcp_msg *client_msg, struct dyn_lease_addr *client_lease)
382 {
383 #if !LWIP_DHCPS_DISCOVER_BROADCAST
384   ip_addr_t client_ipaddr;
385 #endif
386 
387   ip4_addr_t client_ip;
388   ip_addr_t dst_addr;
389   struct pbuf *out_msg = NULL;
390   struct dhcp_msg *srvr_msg = NULL;
391   u16_t options_len = 0;
392 #if !LWIP_DHCPS_DISCOVER_BROADCAST
393 #if ETHARP_SUPPORT_STATIC_ENTRIES
394   struct eth_addr ethaddr;
395 #endif
396 #endif
397   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Processing Discover Message\n"));
398 
399   client_ip = validate_discover(dhcps, client_msg, &client_lease);
400   if (client_ip.addr == 0) {
401     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
402                 ("handle_discover: Returning as unable to get a proper address for client\n"));
403     return;
404   }
405 
406   out_msg = dhcps_create_base_msg(client_msg);
407   if (out_msg == NULL) {
408     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
409                 ("handle_discover function: Memory allocation for base message failed\n"));
410     return;
411   }
412 
413   srvr_msg = (struct dhcp_msg *)out_msg->payload;
414   // no need check msg pointer from payload here
415   srvr_msg->yiaddr.addr = htonl(client_ip.addr);
416 
417   dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
418   dhcp_common_option_byte(srvr_msg, DHCP_OFFER, &options_len);
419 
420   /* netif already holds the Server ID in network order. so, no need to convert it again */
421   dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
422   dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
423 
424   dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
425   dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
426 
427   dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
428   dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
429 
430   dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
431   /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
432   dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
433 
434   /* No need to convert netmask into network order as it is already stored in network order */
435   dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
436   dhcp_common_option_long(srvr_msg, ntohl(ip4_addr_get_u32(ip_2_ip4(&netif->netmask))), &options_len);
437 #if LWIP_DHCPS_GW
438   dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_LEN, &options_len);
439   if (ip4_addr_isany_val(netif->gw.u_addr.ip4)) {
440     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
441   } else {
442     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->gw)->addr), &options_len);
443   }
444 #endif
445 
446 #if LWIP_DHCPS_DNS_OPTION
447   dhcp_option_dns_server(srvr_msg, netif, &options_len);
448 #endif /* LWIP_DHCPS_DNS_OPTION */
449 
450 #if LWIP_DHCPS_AGENT_INFO
451   if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_AGENT_INFO)) {
452     (void)pbuf_copy_partial(dhcps->p_in, srvr_msg->options + options_len, g_dhcp_op_agent_info_len,
453                             dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_AGENT_INFO));
454     options_len = (u16_t)(options_len + g_dhcp_op_agent_info_len);
455   }
456 #else
457   (void)dhcps;
458 #endif /* LWIP_DHCPS_AGENT_INFO */
459 
460   dhcp_common_option_trailer(srvr_msg, &options_len);
461 
462   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: realloc()ing\n"));
463   pbuf_realloc(out_msg, (u16_t)((sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN) + options_len));
464 
465   if (client_msg->ciaddr.addr != 0) {
466     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: sendto(OFFER, ciaddr, LWIP_IANA_PORT_DHCP_CLIENT)\n"));
467     ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
468     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
469   }
470 #if LWIP_DHCPS_AGENT_INFO
471   else if (client_msg->giaddr.addr != 0) {
472 	LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: sendto(OFFER, giaddr, DHCP_RELAY_PORT)\n"));
473 	ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->giaddr.addr));
474 	(void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_RELAY_PORT, netif, &(netif->ip_addr));
475   }
476 #endif /* LWIP_DHCPS_AGENT_INFO */
477 #if !LWIP_DHCPS_DISCOVER_BROADCAST
478   else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
479     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
480                 ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_CLIENT)\n"));
481     (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
482   } else {
483     client_ip.addr = htonl(client_ip.addr);
484 
485 #if ETHARP_SUPPORT_STATIC_ENTRIES
486     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Updating ARP Static Entry for unicast reply\n"));
487     if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
488       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("memcpy_s failed\n"));
489       (void)pbuf_free(out_msg);
490       return;
491     }
492     if (etharp_add_static_entry(&client_ip, &ethaddr) != ERR_OK) {
493       (void)pbuf_free(out_msg);
494       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Adding static entry to arp cache failed\n"));
495       return;
496     }
497 #endif
498 
499     /* Need to check and add an arp entry to make this pass through smoothly */
500     ip_addr_copy_from_ip4(client_ipaddr, client_ip);
501     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &client_ipaddr, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
502 #if ETHARP_SUPPORT_STATIC_ENTRIES
503     /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
504     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Removing ARP Static Entry added for unicast reply\n"));
505     (void)etharp_remove_static_entry(&client_ip);
506 #endif
507   }
508 #else
509   else {
510     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
511                 ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_CLIENT)\n"));
512     (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
513   }
514 #endif
515 
516   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: deleting()ing\n"));
517   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Sending Reply has been successful\n"));
518 
519   (void)pbuf_free(out_msg);
520   return;
521 }
522 
validate_request_message(const struct netif * netif,const struct dhcp_msg * client_msg,const struct dyn_lease_addr * client_lease,ip4_addr_t serverid)523 static ip4_addr_t validate_request_message(const struct netif *netif, const struct dhcp_msg *client_msg,
524                                            const struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
525 {
526   ip4_addr_t requested_ip;
527   requested_ip.addr = 0;
528 
529   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Processing Request Message\n"));
530 
531   if ((client_lease != NULL) && (client_lease->flags == DHCPS_ADDRESS_OFFERRED)) {
532     /* Now, we are in selecting state */
533     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: In Selecting State\n"));
534 
535     if ((serverid.addr == 0) || (client_msg->ciaddr.addr != 0) ||
536         (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP))) {
537       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
538                   ("Server ID or ciaddr or requested ip option is not present\n"));
539       return requested_ip;
540     }
541 
542     if (serverid.addr != ip_2_ip4(&netif->ip_addr)->addr) {
543       /* This message is not meant for us. The client intends to talk to some other server */
544       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
545                   ("validate_request_message: Server id doesn't match with ours. Message not for us\n"));
546       requested_ip.addr = 1;
547       return requested_ip;
548     }
549 
550     requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
551   } else {
552     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
553                 ("validate_request_message: In Init-Reboot, Renew or Rebinding State\n"));
554 
555     /* Now, we can be either in Init-reboot state or renew state or rebinding state */
556     if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
557       /* Requested IP option is filled in. Indicates we are mostly in Init-Reboot State */
558       if (client_lease == NULL) {
559       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
560                   ("validate_request_message: No Configuration found corresponding to request message\n"));
561         requested_ip.addr = 1;
562         return requested_ip;
563       }
564 
565       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
566                   ("validate_request_message: Requested IP Option is present. So, considering as Init-Reboot State\n"));
567 
568       if (client_msg->ciaddr.addr != 0) {
569         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
570                     ("validate_request_message: Error: ciaddr is filled in the Init-Reboot state. \n"));
571         return requested_ip;
572       }
573 
574       requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
575     } else {
576       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: \
577                   Requested IP Option is not present. So, considering as Renewing or Rebinding State\n"));
578 
579       if (client_msg->ciaddr.addr == 0) {
580         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
581                     ("validate_request_message: Error: ciaddr is not filled in the Renewing or Rebinding state. \n"));
582         return requested_ip;
583       }
584 
585       requested_ip.addr = ntohl(client_msg->ciaddr.addr);
586     }
587   }
588 
589   /* requested_ip is in host order and DHCP Server IP is in network order,
590     so converting the former to network order for check */
591   if (htonl(requested_ip.addr) == ip_2_ip4(&netif->ip_addr)->addr) {
592     /* This requested_ip is the dhcp server is using, it is invalid */
593     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Requested IP addr is invalid\n"));
594     requested_ip.addr = 1;
595   }
596 
597   return requested_ip;
598 }
599 
handle_request(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease,ip4_addr_t serverid)600 static void handle_request(struct netif *netif, struct dhcps *dhcps,  struct dhcp_msg *client_msg,
601                            struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
602 {
603   ip4_addr_t requested_ip;
604   struct pbuf *out_msg = NULL;
605   struct dhcp_msg *srvr_msg = NULL;
606   u16_t options_len = 0;
607   ip_addr_t dst_addr;
608   ip_addr_t ip_send;
609 #if ETHARP_SUPPORT_STATIC_ENTRIES
610   struct eth_addr ethaddr;
611 #endif
612 
613   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Processing Request Message\n"));
614 
615   requested_ip = validate_request_message(netif, client_msg, client_lease, serverid);
616   if (requested_ip.addr == 1) {
617     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
618                 ("handle_request: Validation of request message failed. Dropping the packet.\n"));
619     if ((client_lease == NULL) && (client_msg->ciaddr.addr == 0) &&
620         (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) &&
621         ((serverid.addr == 0) || (serverid.addr == ip_2_ip4(&netif->ip_addr)->addr))) {
622       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: NACK for init\n"));
623       requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
624     } else {
625       return;
626     }
627   }
628 
629   out_msg = dhcps_create_base_msg(client_msg);
630   if (out_msg == NULL) {
631     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Creating base message failed\n"));
632     return;
633   }
634 
635   srvr_msg = (struct dhcp_msg *)out_msg->payload;
636   dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
637   dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
638 
639   if ((client_lease != NULL) && (client_lease->cli_addr.addr == requested_ip.addr)) {
640     if (client_lease->proposed_leasetime != (u32_t)(~0)) {
641       u32_t max;
642       max = ((u32_t)(~0) - sys_now()) / MS_PER_SECOND;
643       if (client_lease->proposed_leasetime > max) {
644         client_lease->proposed_leasetime = max;
645       }
646       client_lease->leasetime = sys_now() + (client_lease->proposed_leasetime * MS_PER_SECOND);
647     } else {
648       client_lease->leasetime = client_lease->proposed_leasetime;
649     }
650 
651     client_lease->flags = DHCPS_ADDRESS_BOUND;
652     srvr_msg->yiaddr.addr = htonl(client_lease->cli_addr.addr);
653 
654     dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
655     dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
656 
657     dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
658     dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
659 
660     dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
661     dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
662 
663     dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
664     /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
665     dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
666 
667     dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
668     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->netmask)->addr), &options_len);
669 
670 #if LWIP_DHCPS_GW
671     dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_LEN, &options_len);
672     if (ip4_addr_isany_val(netif->gw.u_addr.ip4)) {
673       dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
674     } else {
675       dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->gw)->addr), &options_len);
676     }
677 #endif
678 
679 #if LWIP_DHCPS_DNS_OPTION
680     dhcp_option_dns_server(srvr_msg, netif, &options_len);
681 #endif /* LWIP_DHCPS_DNS_OPTION */
682 #ifdef  LWIP_DEV_DEBUG
683     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
684                 ("handle_request: Send ACK. to=%"U32_F" lease time=%"U32_F"\n",
685                 requested_ip.addr, client_lease->proposed_leasetime));
686 #endif
687   } else {
688     dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
689     dhcp_common_option_byte(srvr_msg, DHCP_NAK, &options_len);
690 
691     /* Just set this here, so that the NAK message is brcasted.
692     The correct flags has already been added in the respose message during base message creation */
693     client_msg->flags |= htons(DHCP_BROADCAST_FLAG);
694     client_msg->ciaddr.addr = 0; /* This is done so that NAK Gets brcasted */
695 #ifdef  LWIP_DEV_DEBUG
696     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
697                 ("handle_request: Send NAK. Requested from=%"U32_F"\n", requested_ip.addr));
698 #endif
699   }
700 
701 #if LWIP_DHCPS_AGENT_INFO
702   if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_AGENT_INFO)) {
703     (void)pbuf_copy_partial(dhcps->p_in, srvr_msg->options + options_len, g_dhcp_op_agent_info_len,
704                             dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_AGENT_INFO));
705     options_len = (u16_t)(options_len + g_dhcp_op_agent_info_len);
706   }
707 #else
708   (void)dhcps;
709 #endif /* LWIP_DHCPS_AGENT_INFO */
710 
711   requested_ip.addr = htonl(requested_ip.addr);
712   dhcp_common_option_trailer(srvr_msg, &options_len);
713 
714   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: realloc()ing\n"));
715   pbuf_realloc(out_msg, (u16_t)((sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN) + options_len));
716   if (client_msg->ciaddr.addr != 0) {
717     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sendto(ACK, ciaddr, LWIP_IANA_PORT_DHCP_CLIENT)\n"));
718     ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
719     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
720   }
721 #if LWIP_DHCPS_AGENT_INFO
722   else if (client_msg->giaddr.addr != 0) {
723     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sendto(ACK, giaddr, DHCP_RELAY_PORT)\n"));
724     ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->giaddr.addr));
725     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_RELAY_PORT, netif, &(netif->ip_addr));
726   }
727 #endif /* LWIP_DHCPS_AGENT_INFO */
728   else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
729     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sending reply using brdcast \n"));
730     (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
731   } else {
732 #if ETHARP_SUPPORT_STATIC_ENTRIES
733     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Updating ARP Static Entry for unicast reply\n"));
734     if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
735       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Copy chaddr failed\n"));
736       (void)pbuf_free(out_msg);
737       return;
738     }
739     if (ERR_OK != etharp_add_static_entry(&requested_ip, &ethaddr)) {
740       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Adding static entry to arp cache failed\n"));
741       (void)pbuf_free(out_msg);
742       return;
743     }
744 #endif
745     /* Need to check and add an arp entry to make this pass through smoothly */
746 #ifdef  LWIP_DEV_DEBUG
747     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
748                 ("handle_request: sending reply using unicast Client IP =%"U32_F"\n", requested_ip.addr));
749 #endif
750 
751     ip_2_ip4(&ip_send)->addr = requested_ip.addr;
752 #if LWIP_IPV4 && LWIP_IPV6
753     ip_send.type = IPADDR_TYPE_V4;
754 #endif
755 
756     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &ip_send, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
757 
758 #if ETHARP_SUPPORT_STATIC_ENTRIES
759     /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
760     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
761                 ("handle_request: Removing ARP Static Entry added for unicast reply\n"));
762     (void)etharp_remove_static_entry(&requested_ip);
763 #endif
764   }
765   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: deleting\n"));
766 
767   (void)pbuf_free(out_msg);
768   return;
769 }
770 
handle_decline(const struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease)771 static void handle_decline(const struct dhcp_msg *client_msg, struct dyn_lease_addr *client_lease)
772 {
773   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_decline: Processing Decline Message\n"));
774 
775   if ((client_lease != NULL) && (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) &&
776       (client_msg->ciaddr.addr == 0)) {
777     if (client_lease->cli_addr.addr == (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
778 #ifdef  LWIP_DEV_DEBUG
779       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
780                   ("handle_decline: Marking Client Entry as declined. Client IP =%"U32_F"\n",
781                   client_lease->cli_addr.addr));
782 #endif
783       (void)memset_s(client_lease->cli_hwaddr, DHCP_CHADDR_LEN, 0, DHCP_CHADDR_LEN);
784       client_lease->proposed_leasetime = 0;
785       client_lease->leasetime = sys_now() + (LWIP_DHCPS_DECLINE_TIME * MS_PER_SECOND);
786       client_lease->flags = DHCPS_ADDRESS_DECLINED;
787     }
788   }
789 }
790 
handle_inform(struct netif * netif,struct dhcps * dhcps,const struct dhcp_msg * client_msg)791 static void handle_inform(struct netif *netif, struct dhcps *dhcps, const struct dhcp_msg *client_msg)
792 {
793   struct pbuf *out_msg = NULL;
794   struct dhcp_msg *srvr_msg = NULL;
795   u16_t options_len = 0;
796   ip_addr_t dst_addr;
797 
798   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Processing Inform Message\n"));
799 
800   if (client_msg->ciaddr.addr == 0) {
801     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: ciaddr is empty. Can't send back a response\n"));
802     return;
803   }
804 
805   out_msg = dhcps_create_base_msg(client_msg);
806   if (out_msg == NULL) {
807     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Creating base message failed\n"));
808     return;
809   }
810 
811   srvr_msg = (struct dhcp_msg *)out_msg->payload;
812   dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
813   dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
814 
815 #if LWIP_DHCPS_AGENT_INFO
816   if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_AGENT_INFO)) {
817     (void)pbuf_copy_partial(dhcps->p_in, srvr_msg->options + options_len, g_dhcp_op_agent_info_len,
818                             dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_AGENT_INFO));
819     options_len = (u16_t)(options_len + g_dhcp_op_agent_info_len);
820   }
821 #endif /* LWIP_DHCPS_AGENT_INFO */
822 
823   dhcp_common_option_trailer(srvr_msg, &options_len);
824 
825   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: realloc()ing\n"));
826   pbuf_realloc(out_msg, (u16_t)((sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN) + options_len));
827 #ifdef  LWIP_DEV_DEBUG
828   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
829              ("handle_inform: Send ACK to Client. Client is=%"U32_F"\n", client_msg->ciaddr.addr));
830 #endif
831   ip_addr_set_ip4_u32_val(dst_addr, client_msg->ciaddr.addr);
832   (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, LWIP_IANA_PORT_DHCP_CLIENT, netif, &(netif->ip_addr));
833 
834   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: deleting pbuf\n"));
835   (void)pbuf_free(out_msg);
836 
837   return;
838 }
839 
handle_client_messages(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,ip4_addr_t serverid,u8_t msg_type)840 static void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
841                                    struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type)
842 {
843   struct dyn_lease_addr *client_lease = NULL;
844 
845   client_lease = find_client_lease(dhcps, client_msg);
846   switch (msg_type) {
847     case DHCP_DISCOVER:
848       handle_discover(netif, dhcps, client_msg, client_lease);
849       break;
850     case DHCP_REQUEST:
851       handle_request(netif, dhcps, client_msg, client_lease, serverid);
852       break;
853     case DHCP_DECLINE:
854       handle_decline(client_msg, client_lease);
855       break;
856     case DHCP_RELEASE:
857       if ((client_lease != NULL) && (client_lease->cli_addr.addr == ntohl(client_msg->ciaddr.addr))) {
858 #ifdef  LWIP_DEV_DEBUG
859         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP Release: Client IPAdd =%"U32_F"\n", client_msg->ciaddr.addr));
860 #endif
861         (void)memset_s(client_lease, sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
862         client_lease->flags = DHCPS_ADDRESS_FREE;
863       }
864       break;
865     case DHCP_INFORM:
866       handle_inform(netif, dhcps, client_msg);
867       break;
868     default:
869       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
870                   ("DHCP Server. Invalid message type received %d\n", msg_type));
871   }
872 }
873 
874 #if LWIP_DHCP_BOOTP_FILE
dhcps_parse_options(struct pbuf * p,char * boot_file_name)875 err_t dhcps_parse_options(struct pbuf *p, char *boot_file_name)
876 #else
877 err_t dhcps_parse_options(struct pbuf *p)
878 #endif
879 {
880   u8_t *options = NULL;
881   u16_t offset;
882   u16_t offset_max;
883   u16_t options_idx;
884   u16_t options_idx_max;
885   struct pbuf *q = NULL;
886   int parse_file_as_options = 0;
887   int parse_sname_as_options = 0;
888 
889   if (p == NULL) {
890     return ERR_BUF;
891   }
892   /* clear received options */
893   (void)memset_s(dhcps_rx_options_given, sizeof(dhcps_rx_options_given), 0, sizeof(dhcps_rx_options_given));
894   /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
895   if (p->len < DHCP_SNAME_OFS) {
896     return ERR_BUF;
897   }
898 
899   /* parse options */
900   /* start with options field */
901   options_idx = DHCP_OPTIONS_OFS;
902   /* parse options to the end of the received packet */
903   options_idx_max = p->tot_len;
904 again:
905   q = p;
906   while ((q != NULL) && (options_idx >= q->len)) {
907     options_idx = (u16_t)(options_idx - q->len);
908     options_idx_max = (u16_t)(options_idx_max - q->len);
909     q = q->next;
910   }
911   if (q == NULL) {
912     return ERR_BUF;
913   }
914   offset = options_idx;
915   offset_max = options_idx_max;
916   options = (u8_t*)q->payload;
917   /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
918   while ((q != NULL) && (offset < offset_max) && (options[offset] != DHCP_OPTION_END)) {
919     u8_t op = options[offset];
920     u8_t len;
921     u8_t decode_len = 0;
922     int decode_idx = -1;
923     /* add 2 to skip op and len */
924     u16_t val_offset = (u16_t)(offset + 2);
925     /* len byte might be in the next pbuf */
926     if ((offset + 1) < q->len) {
927       len = options[offset + 1];
928     } else {
929       len = (u8_t)(q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0);
930     }
931 
932     decode_len = len;
933     switch (op) {
934       /* case(DHCP_OPTION_END): handled above */
935       case (DHCP_OPTION_PAD):
936         /* special option: no len encoded */
937         decode_len = len = 0;
938         /* will be increased below */
939         offset--;
940         break;
941       case (DHCP_OPTION_SUBNET_MASK):
942         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
943         decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
944         break;
945       case (DHCP_OPTION_ROUTER):
946         decode_len = sizeof(u32_t); /* only copy the first given router */
947         LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL);
948         decode_idx = DHCP_OPTION_IDX_ROUTER;
949         break;
950 #if LWIP_DHCP_PROVIDE_DNS_SERVERS
951       case (DHCP_OPTION_DNS_SERVER):
952         /* special case: there might be more than one server */
953         LWIP_DHCP_INPUT_ERROR("len %% sizeof(u32_t) == 0", len % sizeof(u32_t) == 0, return ERR_VAL);
954         /* limit number of DNS servers */
955         decode_len = (u8_t)LWIP_MIN(len, sizeof(u32_t) * DNS_MAX_SERVERS);
956         LWIP_DHCP_INPUT_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL);
957         decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
958         break;
959 #endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
960       case (DHCP_OPTION_LEASE_TIME):
961         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
962         decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
963         break;
964       case (DHCP_OPTION_OVERLOAD):
965         LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL);
966         decode_idx = DHCP_OPTION_IDX_OVERLOAD;
967         break;
968       case (DHCP_OPTION_MESSAGE_TYPE):
969         LWIP_DHCP_INPUT_ERROR("len == 1", len == 1, return ERR_VAL);
970         decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
971         break;
972       case (DHCP_OPTION_SERVER_ID):
973         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
974         decode_idx = DHCP_OPTION_IDX_SERVER_ID;
975         break;
976       case (DHCP_OPTION_T1):
977         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
978         decode_idx = DHCP_OPTION_IDX_T1;
979         break;
980       case (DHCP_OPTION_T2):
981         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
982         decode_idx = DHCP_OPTION_IDX_T2;
983         break;
984       case (DHCP_OPTION_REQUESTED_IP):
985         LWIP_DHCP_INPUT_ERROR("len == sizeof(u32_t)", len == sizeof(u32_t), return ERR_VAL);
986         decode_idx = DHCP_OPTION_IDX_REQUESTED_IP;
987         break;
988 #if LWIP_DHCPS_AGENT_INFO
989       case (DHCP_OPTION_AGENT_INFO):
990         decode_idx = DHCP_OPTION_IDX_AGENT_INFO;
991         decode_len = 0;
992         dhcps_got_option(NULL, decode_idx);
993         dhcps_set_option_value(NULL, decode_idx, offset);
994         /* 2 : set two byte offset */
995         g_dhcp_op_agent_info_len = (u16_t)(len + 2);
996         break;
997 #endif /* LWIP_DHCPS_AGENT_INFO */
998       default:
999         decode_len = 0;
1000         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op));
1001         break;
1002     }
1003     /* add 2 to skip op and len */
1004     offset = (u16_t)(offset + len + 2);
1005     if ((decode_len > 0) && (decode_idx >= 0) && (decode_idx < DHCP_OPTION_IDX_MAX)) {
1006       u32_t value = 0;
1007       u16_t copy_len;
1008 decode_next:
1009       /* decode_idx is assigned with non-negative value in switch case, for negative we will not come here,
1010          So this should be OK. */
1011       if (!dhcps_option_given(dhcp, decode_idx)) {
1012         copy_len = (u16_t)LWIP_MIN(decode_len, sizeof(u32_t));
1013         (void)pbuf_copy_partial(q, &value, copy_len, val_offset);
1014         if (decode_len > sizeof(u32_t)) {
1015           /* decode more than one u32_t */
1016           LWIP_DHCP_INPUT_ERROR("decode_len %% sizeof(u32_t) == 0", decode_len % sizeof(u32_t) == 0, return ERR_VAL);
1017           dhcps_got_option(NULL, decode_idx);
1018           dhcps_set_option_value(NULL, decode_idx, htonl(value));
1019           decode_len = (u8_t)(decode_len - sizeof(u32_t));
1020           val_offset = (u16_t)(val_offset + sizeof(u32_t));
1021           decode_idx++;
1022           goto decode_next;
1023         } else if (decode_len == sizeof(u32_t)) {
1024           value = ntohl(value);
1025         } else {
1026           LWIP_DHCP_INPUT_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL);
1027           value = ((u8_t*)&value)[0];
1028         }
1029         dhcps_got_option(NULL, decode_idx);
1030         dhcps_set_option_value(NULL, decode_idx, value);
1031       }
1032     }
1033     if (offset >= q->len) {
1034       offset = (u16_t)(offset - q->len);
1035       offset_max = (u16_t)(offset_max - q->len);
1036       if ((offset < offset_max) && offset_max) {
1037         q = q->next;
1038         if (q == NULL) {
1039             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("next pbuf was null"));
1040             break;
1041         }
1042         options = (u8_t*)q->payload;
1043       } else {
1044         // We've run out of bytes, probably no end marker. Don't proceed.
1045         break;
1046       }
1047     }
1048   }
1049   /* is this an overloaded message? */
1050   if (dhcps_option_given(NULL, DHCP_OPTION_IDX_OVERLOAD)) {
1051     u32_t overload = dhcps_get_option_value(NULL, DHCP_OPTION_IDX_OVERLOAD);
1052     dhcps_clear_option(NULL, DHCP_OPTION_IDX_OVERLOAD);
1053     if (overload == DHCP_OVERLOAD_FILE) {
1054       parse_file_as_options = lwIP_TRUE;
1055       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
1056     } else if (overload == DHCP_OVERLOAD_SNAME) {
1057       parse_sname_as_options = lwIP_TRUE;
1058       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
1059     } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
1060       parse_sname_as_options = lwIP_TRUE;
1061       parse_file_as_options = lwIP_TRUE;
1062       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
1063     } else {
1064       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
1065     }
1066 
1067 #if LWIP_DHCP_BOOTP_FILE
1068     if ((boot_file_name != NULL) && (parse_file_as_options == lwIP_FALSE)) {
1069       /* only do this for ACK messages */
1070       if (dhcps_option_given(NULL, DHCP_OPTION_IDX_MSG_TYPE) &&
1071         (dhcps_get_option_value(NULL, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) {
1072         /* copy bootp file name, don't care for sname (server hostname) */
1073         (void)pbuf_copy_partial(p, boot_file_name, DHCP_FILE_LEN - 1, DHCP_FILE_OFS);
1074       }
1075       /* make sure the string is really NULL-terminated */
1076       boot_file_name[DHCP_FILE_LEN - 1] = 0;
1077     }
1078 #endif /* LWIP_DHCP_BOOTP_FILE */
1079   }
1080   if (parse_file_as_options == lwIP_TRUE) {
1081     /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
1082     parse_file_as_options = lwIP_FALSE;
1083     options_idx = DHCP_FILE_OFS;
1084     options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
1085     goto again;
1086   } else if (parse_sname_as_options == lwIP_TRUE) {
1087     parse_sname_as_options = lwIP_FALSE;
1088     options_idx = DHCP_SNAME_OFS;
1089     options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
1090     goto again;
1091   }
1092   return ERR_OK;
1093 }
1094 
dhcps_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * ip_addr,u16_t port)1095 static void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *ip_addr, u16_t port)
1096 {
1097   struct netif *netif = (struct netif *)arg;
1098   struct dhcps *dhcps = netif->dhcps;
1099   struct dhcp_msg *client_msg = (struct dhcp_msg *)p->payload;
1100   u8_t msg_type;
1101   ip4_addr_t serverid;
1102   ip4_addr_t addr;
1103 
1104 #if LWIP_DHCPS_AGENT_INFO
1105   if ((port != LWIP_IANA_PORT_DHCP_CLIENT) && (port != DHCP_RELAY_PORT)) {
1106     goto free_pbuf_and_return;
1107   }
1108 #endif /* LWIP_DHCPS_AGENT_INFO */
1109 
1110   addr.addr = ip4_addr_get_u32(ip_2_ip4(ip_addr));
1111   serverid.addr = 0;
1112 #ifdef  LWIP_DEV_DEBUG
1113   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
1114               ("dhcps_recv(pbuf = %p) from DHCP Client %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
1115               ip4_addr1_16(&addr), ip4_addr2_16(&addr), ip4_addr3_16(&addr), ip4_addr4_16(&addr), port));
1116 #endif
1117   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
1118   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
1119   /* prevent warnings about unused arguments */
1120   LWIP_UNUSED_ARG(pcb);
1121   LWIP_UNUSED_ARG(addr);
1122   LWIP_UNUSED_ARG(port);
1123 
1124   (void)memset_s(dhcps_rx_options_given, sizeof(dhcps_rx_options_given), 0, sizeof(dhcps_rx_options_given));
1125 
1126   /* Check and remove old entries on each call to dhcp_recv. This way, we don't need to maintain timers */
1127   remove_stale_entries(dhcps);
1128 
1129   if (p->len < DHCP_OPTIONS_OFS) {
1130     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1131                 ("DHCP client message or pbuf too short. pbuf len =%"U16_F" DHCP MIN Reply Len = %"U32_F"\n",
1132                 p->len, DHCP_MIN_REPLY_LEN));
1133     goto free_pbuf_and_return;
1134   }
1135 
1136   if (client_msg->op != DHCP_BOOTREQUEST) {
1137     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1138                 ("Not a DHCP reply message, Type %"U16_F"\n", (u16_t)client_msg->op));
1139     goto free_pbuf_and_return;
1140   }
1141 
1142   if (client_msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)) {
1143     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1144                 ("DHCP Server. Cookie Value is incorrect. %"U32_F"\n", (u32_t)client_msg->cookie));
1145     goto free_pbuf_and_return;
1146   }
1147 
1148   if (client_msg->hlen != ETHARP_HWADDR_LEN) {
1149     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1150                 ("DHCP Server. Invalid hardware address length %"U16_F"\n", (u16_t)client_msg->hlen));
1151     goto free_pbuf_and_return;
1152   }
1153 
1154 #if LWIP_DHCP_BOOTP_FILE
1155   if (dhcps_parse_options(p, NULL) != ERR_OK) {
1156 #else
1157   if (dhcps_parse_options(p) != ERR_OK) {
1158 #endif
1159     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1160                 ("Parsing of Options failed in DHCP Client Message\n"));
1161     goto free_pbuf_and_return;
1162   }
1163 
1164   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("Searching DHCP_OPTION_MESSAGE_TYPE\n"));
1165   /* obtain pointer to DHCP message type */
1166   if (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_MSG_TYPE)) {
1167     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1168                 ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
1169     goto free_pbuf_and_return;
1170   }
1171 
1172   /* read DHCP message type */
1173   msg_type = (u8_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_MSG_TYPE);
1174 
1175   if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_SERVER_ID)) {
1176     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1177                 ("DHCP_OPTION_SERVER_ID option found\n"));
1178     /* Parse options would have changed it to host order. But, we have our IP stored in netif in network order */
1179     serverid.addr = htonl((u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_SERVER_ID));
1180   }
1181 
1182   if ((serverid.addr != 0) && ((msg_type == DHCP_DISCOVER) || (msg_type == DHCP_INFORM))) {
1183       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1184                   ("Serverid present in DHCP_DISCOVER and DHCP_INFORM messages\n"));
1185     goto free_pbuf_and_return;
1186   }
1187 
1188   if ((!ip4_addr_cmp(&serverid, ip_2_ip4(&netif->ip_addr))) &&
1189     ((msg_type == DHCP_DECLINE) || (msg_type == DHCP_RELEASE))) {
1190     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
1191                 ("Serverid not present in DHCP_RELEASE and DHCP_DECLINE messages\n"));
1192     goto free_pbuf_and_return;
1193   }
1194 
1195 #if LWIP_DHCPS_AGENT_INFO
1196   dhcps->p_in = p;
1197 #endif /* LWIP_DHCPS_AGENT_INFO */
1198 
1199   handle_client_messages(netif, dhcps, client_msg, serverid, msg_type);
1200 
1201   free_pbuf_and_return:
1202   (void)pbuf_free(p);
1203 }
1204 
1205 err_t dhcps_start(struct netif *netif, const char *start_ip, u16_t ip_num)
1206 {
1207   struct dhcps *dhcps = NULL;
1208   ip4_addr_t address_in_hton;
1209   int err;
1210 
1211   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
1212   dhcps = netif->dhcps;
1213 
1214   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
1215               ("dhcps_start(netif=%p) %s%"U16_F"\n", (void*)netif, netif->name, (u16_t)netif->num));
1216 
1217   if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
1218     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
1219                 ("MTU =%"U16_F",DHCP Msg Len Required =%"U32_F"\n", netif->mtu, DHCP_MAX_MSG_LEN_MIN_REQUIRED));
1220     return ERR_MEM;
1221   }
1222 
1223   if (dhcps != NULL) {
1224     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): DHCP Server is already started\n"));
1225     return ERR_MEM;
1226   }
1227 
1228   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting new DHCP Server\n"));
1229   dhcps = (struct dhcps *)mem_malloc(sizeof(struct dhcps));
1230   if (dhcps == NULL) {
1231     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): could not allocate dhcp\n"));
1232     return ERR_MEM;
1233   }
1234 
1235   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): allocated dhcp"));
1236 
1237   (void)memset_s(dhcps, sizeof(struct dhcps), 0, sizeof(struct dhcps));
1238 
1239   dhcps->pcb = udp_new();
1240   if (dhcps->pcb == NULL) {
1241     LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate pcb\n"));
1242     mem_free((void *)dhcps);
1243     return ERR_MEM;
1244   }
1245 
1246 #if LWIP_SO_PRIORITY
1247   dhcps->pcb->priority = LWIP_PKT_PRIORITY_DHCPS;
1248 #endif /* LWIP_SO_PRIORITY */
1249 
1250   /* bind dhcp udp_pcb to specific netif, this could make dhcp server start on multiple netif */
1251   dhcps->pcb->netif_idx = netif->ifindex;
1252 
1253   if ((start_ip == NULL) || (ip_num == 0)) {
1254     /* use default ip lease configuration. */
1255     /* 2: The range of the default dhcp address pool is start with two */
1256     dhcps->start_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr) + LWIP_DHCPS_START_ADDR_OFFSET;
1257     dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
1258     dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
1259     if (dhcps->lease_num > LWIP_DHCPS_MAX_LEASE) {
1260       dhcps->lease_num = LWIP_DHCPS_MAX_LEASE;
1261       dhcps->end_addr.addr = dhcps->start_addr.addr + LWIP_DHCPS_MAX_LEASE - 1;
1262     }
1263   } else {
1264     dhcps->start_addr.addr = ntohl(ipaddr_addr(start_ip));
1265     dhcps->end_addr.addr = (u32_t)(dhcps->start_addr.addr + (u32_t)(LWIP_MIN(ip_num - 1, LWIP_DHCPS_MAX_LEASE - 1)));
1266 
1267     ip4_addr_set_hton(&address_in_hton, &dhcps->start_addr);
1268 
1269     if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
1270       ip4_addr_isbroadcast((&address_in_hton), netif)) {
1271       LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): %s in not a valid ip lease\n", start_ip));
1272       udp_remove(dhcps->pcb);
1273       mem_free((void *)dhcps);
1274       return ERR_ARG;
1275     }
1276 
1277     ip4_addr_set_hton(&address_in_hton, &dhcps->end_addr);
1278 
1279     if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
1280       ip4_addr_isbroadcast((&address_in_hton), netif)) {
1281       dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
1282     }
1283     dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
1284   }
1285 
1286   dhcps->netif = netif;
1287   dhcps->pcb->so_options |= SOF_BROADCAST;
1288   err = udp_bind(dhcps->pcb, IP_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
1289   if (err != ERR_OK) {
1290     udp_remove(dhcps->pcb);
1291     mem_free((void *)dhcps);
1292     return ERR_MEM;
1293   }
1294 
1295 #if (LWIP_DHCPS_AGENT_INFO == 0)
1296   err = udp_connect(dhcps->pcb, IP_ADDR_ANY, LWIP_IANA_PORT_DHCP_CLIENT);
1297   if (err != ERR_OK) {
1298     udp_remove(dhcps->pcb);
1299     mem_free((void *)dhcps);
1300     return ERR_MEM;
1301   }
1302 #endif /* LWIP_DHCPS_AGENT_INFO == 0 */
1303 
1304   udp_recv(dhcps->pcb, dhcps_recv, netif);
1305   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting DHCPS Successfully\n"));
1306 #ifdef  LWIP_DEV_DEBUG
1307   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
1308               ("dhcps_start(): DHCPS Conf:: netif addr = %"U32_F" dhcps start addr%"U32_F" dhcp end addr%"U32_F"\n",
1309               ip_2_ip4(&netif->ip_addr)->addr, dhcps->start_addr.addr, dhcps->end_addr.addr));
1310 #endif
1311   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
1312               ("dhcps_start(): DHCPS Lease Conf:: Lease Time = %"U32_F" Offer Time = %"U32_F"\n",
1313               LWIP_DHCPS_LEASE_TIME, LWIP_DHCPS_OFFER_TIME));
1314   netif->dhcps = dhcps;
1315 
1316 #if defined(LWIP_DENY_DNS_SERVER) && (LWIP_DENY_DNS_SERVER)
1317   dns_server_init();
1318 #endif
1319 
1320   return ERR_OK;
1321 }
1322 
1323 void dhcps_stop(struct netif *netif)
1324 {
1325   LWIP_ERROR("dhcps_stop: netif != NULL", (netif != NULL), return);
1326 
1327   if (netif->dhcps != NULL) {
1328     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Stopping DHCP Server\n"));
1329     if (netif->dhcps->pcb != NULL) {
1330       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Removing UDP PCB\n"));
1331       udp_remove(netif->dhcps->pcb);
1332       netif->dhcps->pcb = NULL;
1333     }
1334 
1335     mem_free(netif->dhcps);
1336     netif->dhcps = NULL;
1337   }
1338 #if defined(LWIP_DENY_DNS_SERVER) && (LWIP_DENY_DNS_SERVER)
1339   dns_server_deinit();
1340 #endif
1341 }
1342 
1343 void
1344 dhcps_client_disconnect(struct netif *netif, const u8_t *mac, u8_t maclen)
1345 {
1346   struct dhcps *dhcps = NULL;
1347   struct dyn_lease_addr *lease = NULL;
1348   u8_t i;
1349 
1350   if ((netif == NULL) || (mac == NULL)) {
1351     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_client_disconnect(): null netif or mac\n"));
1352     return;
1353   }
1354   dhcps = netif->dhcps;
1355   if ((dhcps == NULL) || (dhcps->pcb == NULL)) {
1356     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_client_disconnect(): dhcps of %s%hhu not start\n",
1357                                               netif->name, netif->num));
1358     return;
1359   }
1360   for (i = 0; i < dhcps->lease_num; i++) {
1361     if (dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) {
1362       lease = &(dhcps->leasearr[i]);
1363       if (memcmp(lease->cli_hwaddr, mac, maclen) == 0) {
1364         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_client_disconnect(): clear %02x%02x%02x%02x%02x%02x\n",
1365                                                   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
1366         (void)memset_s(lease, sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
1367         lease->flags = DHCPS_ADDRESS_FREE;
1368         break;
1369       }
1370     }
1371   }
1372 
1373   return;
1374 }
1375 #endif
1376 
1377