• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /**
33  * @file
34  * Dynamic Host Configuration Protocol Server
35  *
36  */
37 
38 #include "../core/ipv4/dhcp.c"  /* for enum dhcp_option_idx/dhcp_option_xx/dhcp_parse_reply etc. */
39 
40 #include "lwip/opt.h"
41 
42 #if (LWIP_DHCP) && (LWIP_DHCPS) /* don't build if not configured for use in lwipopts.h */
43 #include <string.h>
44 
45 #include "lwip/stats.h"
46 #include "lwip/mem.h"
47 #include "lwip/udp.h"
48 #include "lwip/ip_addr.h"
49 #include "lwip/netif.h"
50 #include "lwip/def.h"
51 #include "lwip/prot/dhcp.h"
52 #include "lwip/dhcp.h"
53 #include "lwip/dhcps.h"
54 #include "lwip/sys.h"
55 #include "netif/etharp.h"
56 
57 #define DHCPS_ADDRESS_FREE 0x0
58 #define DHCPS_ADDRESS_OFFERRED 0x1
59 #define DHCPS_ADDRESS_BOUND 0x2
60 #define DHCPS_ADDRESS_DECLINED 0x3
61 
62 #define LWIP_STATIC static
63 #define DHCP_OPTION_ROUTER_SIZE     4
64 #define DHCP_OPTION_SUBNET_MASK_SIZE 4
65 #define DHCP_OPTION_LEASE_TIME_SIZE 4
66 #define DHCP_OPTION_SERVER_ID_LEN   4
67 #define DHCP_OPTION_T1_LEN          4
68 #define DHCP_OPTION_T2_LEN          4
69 
70 #define DHCP_CLIENT_PORT  68
71 #define DHCP_SERVER_PORT  67
72 
73 #define DHCP_BROADCAST_FLAG             0x8000
74 
75 struct dyn_lease_addr {
76     u8_t cli_hwaddr[DHCP_CHADDR_LEN];
77     u32_t flags;
78     u32_t leasetime;
79     u32_t proposed_leasetime;
80     ip4_addr_t cli_addr;
81 };
82 
83 struct dhcps {
84     struct dhcp dhcp;
85     struct udp_pcb *pcb;
86     struct dyn_lease_addr leasearr[LWIP_DHCPS_MAX_LEASE];
87     u8_t pcb_allocated;
88     u8_t lease_num;
89     struct netif *netif;
90     ip4_addr_t start_addr;
91     ip4_addr_t end_addr;
92 };
93 
94 #define dhcps_option_given(dhcps, idx)          dhcp_option_given(&(dhcps)->dhcp, idx)
95 #define dhcps_got_option(dhcps, idx)            dhcp_got_option(&(dhcps)->dhcp, idx)
96 #define dhcps_clear_option(dhcps, idx)          dhcp_clear_option(&(dhcps)->dhcp, idx)
97 #define dhcps_clear_all_options(dhcps)          dhcp_clear_all_options(&(dhcps)->dhcp)
98 #define dhcps_get_option_value(dhcps, idx)      dhcp_get_option_value(&(dhcps)->dhcp, idx)
99 #define dhcps_set_option_value(dhcps, idx, val) dhcp_set_option_value(&(dhcps)->dhcp, idx, val)
100 
101 #define netif_get_dhcps(netif) ((struct dhcps*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCPS))
102 #define netif_set_dhcps(netif, dhcps) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCPS, dhcps)
103 
104 LWIP_STATIC void dhcp_common_option(struct dhcp_msg *msg_out, u8_t option_type, u8_t option_len, u16_t *options_out_len);
105 LWIP_STATIC void dhcp_common_option_byte(struct dhcp_msg *msg_out, u8_t value, u16_t *options_out_len);
106 LWIP_STATIC void dhcp_common_option_long(struct dhcp_msg *msg_out, u32_t value, u16_t *options_out_len);
107 LWIP_STATIC void dhcp_common_option_trailer(struct dhcp_msg *msg_out, u16_t options_out_len, struct pbuf *p_out);
108 LWIP_STATIC err_t dhcps_parse_options(struct pbuf *p, struct dhcps *dhcps);
109 
110 LWIP_STATIC struct pbuf *dhcps_create_base_msg(struct dhcp_msg *client_msg);
111 LWIP_STATIC void remove_stale_entries(struct dhcps *dhcps);
112 LWIP_STATIC void add_client_entry(struct dhcps *dhcps, unsigned int idx, struct dhcp_msg *client_msg);
113 LWIP_STATIC int find_free_slot(struct dhcps *dhcps);
114 LWIP_STATIC struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, struct dhcp_msg *client_msg);
115 LWIP_STATIC ip4_addr_t validate_discover(struct dhcps *dhcps, struct dhcp_msg *client_msg,
116                                          struct dyn_lease_addr **client_lease);
117 LWIP_STATIC void handle_discover(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
118                                  struct dyn_lease_addr *client_lease);
119 LWIP_STATIC ip4_addr_t validate_request_message(struct netif *netif, struct dhcp_msg *client_msg,
120                                                 struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
121 LWIP_STATIC void handle_request(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
122                                 struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
123 LWIP_STATIC void handle_decline(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
124                                 struct dyn_lease_addr *client_lease);
125 LWIP_STATIC void handle_inform(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg);
126 LWIP_STATIC void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
127                                         struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type);
128 LWIP_STATIC void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
129                             const ip_addr_t *ip_addr, u16_t port);
130 
dhcps_create_base_msg(struct dhcp_msg * client_msg)131 LWIP_STATIC struct pbuf *dhcps_create_base_msg(struct dhcp_msg *client_msg)
132 {
133     struct pbuf *srvr_msg_pbuf = NULL;
134     struct dhcp_msg *srvr_msg = NULL;
135 
136     srvr_msg_pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
137     if (srvr_msg_pbuf == NULL) {
138         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
139                     ("dhcps_create_base_msg(): could not allocate pbuf\n"));
140         return NULL;
141     }
142 
143     LWIP_ASSERT("dhcps_create_base_msg: check that first pbuf can hold struct dhcp_msg",
144                 (srvr_msg_pbuf->len >= sizeof(struct dhcp_msg)));
145 #if DRIVER_STATUS_CHECK
146     srvr_msg_pbuf->flags |= PBUF_FLAG_DHCP_BUF;
147 #endif
148 
149     srvr_msg = (struct dhcp_msg *)srvr_msg_pbuf->payload;
150     srvr_msg->op = DHCP_BOOTREPLY;
151     srvr_msg->htype = client_msg->htype;
152     srvr_msg->hlen = client_msg->hlen;
153     srvr_msg->hops = 0;
154     srvr_msg->xid = client_msg->xid;
155     srvr_msg->secs = 0;
156     srvr_msg->flags = client_msg->flags;
157     ip4_addr_set_zero(&srvr_msg->ciaddr);
158     ip4_addr_set_zero(&srvr_msg->yiaddr);
159     ip4_addr_set_zero(&srvr_msg->siaddr);
160     ip4_addr_copy(srvr_msg->giaddr, client_msg->giaddr);
161     if (memcpy_s(srvr_msg->chaddr, sizeof(srvr_msg->chaddr), client_msg->chaddr, DHCP_CHADDR_LEN) != EOK) {
162         (void)pbuf_free(srvr_msg_pbuf);
163         return NULL;
164     }
165     (void)memset_s(srvr_msg->sname, sizeof(srvr_msg->sname), 0, DHCP_SNAME_LEN);
166     (void)memset_s(srvr_msg->file, sizeof(srvr_msg->file), 0, DHCP_FILE_LEN);
167     srvr_msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
168 
169     return srvr_msg_pbuf;
170 }
171 
remove_stale_entries(struct dhcps * dhcps)172 LWIP_STATIC void remove_stale_entries(struct dhcps *dhcps)
173 {
174     int i = 0;
175     u32_t curr_time = sys_now();
176 
177     for (i = 0; i < dhcps->lease_num; i++) {
178         /* Slot should not be free or have infinite lease time */
179         if ((dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) && (dhcps->leasearr[i].leasetime != (u32_t)~0)) {
180             if (dhcps->leasearr[i].leasetime < curr_time) {
181                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
182                             ("remove_stale_entries: Removing Client Entry at Index = %"U32_F"\n", i));
183                 (void)memset_s(&(dhcps->leasearr[i]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
184                 dhcps->leasearr[i].flags = DHCPS_ADDRESS_FREE;
185             }
186         }
187     }
188 }
189 
add_client_entry(struct dhcps * dhcps,unsigned int idx,struct dhcp_msg * client_msg)190 LWIP_STATIC void add_client_entry(struct dhcps *dhcps, unsigned int idx, struct dhcp_msg *client_msg)
191 {
192     u32_t client_lease_time = (u32_t)(LWIP_DHCPS_LEASE_TIME);
193 
194     if ((dhcps_option_given(dhcps, DHCP_OPTION_IDX_LEASE_TIME))
195 #if (LWIP_DHCPS_LEASE_TIME != ~0)
196         && (dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
197 #endif
198         ) {
199         client_lease_time = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME);
200     }
201 
202     (void)memset_s(&(dhcps->leasearr[idx]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
203     if (memcpy_s(dhcps->leasearr[idx].cli_hwaddr, DHCP_CHADDR_LEN,
204                  client_msg->chaddr, sizeof(client_msg->chaddr)) != EOK) {
205         return;
206     }
207     /* This is called only during offer message, so adding offer time.
208       This is later updated to lease time when request message is handled */
209     dhcps->leasearr[idx].leasetime = sys_now() + (LWIP_DHCPS_OFFER_TIME * 1000);
210     dhcps->leasearr[idx].cli_addr.addr = dhcps->start_addr.addr + idx;
211     dhcps->leasearr[idx].flags = DHCPS_ADDRESS_OFFERRED;
212     dhcps->leasearr[idx].proposed_leasetime = client_lease_time;
213     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("add_client_entry: Adding Client Entry at Index = %"U32_F"\n", idx));
214 }
215 
find_free_slot(struct dhcps * dhcps)216 LWIP_STATIC int find_free_slot(struct dhcps *dhcps)
217 {
218     int i;
219     for (i = 0; i < dhcps->lease_num; i++) {
220         if ((dhcps->leasearr[i].flags == DHCPS_ADDRESS_FREE) &&
221             (htonl(dhcps->start_addr.addr + (u32_t)i) != ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
222             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("find_free_slot: Found Free Slot at Index = %"U32_F"\n", i));
223             return i;
224         }
225     }
226 
227     return -1;
228 }
229 
find_client_lease(struct dhcps * dhcps,struct dhcp_msg * client_msg)230 LWIP_STATIC struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, struct dhcp_msg *client_msg)
231 {
232     int i;
233     for (i = 0; i < dhcps->lease_num; i++) {
234         if (dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) {
235             if (memcmp(dhcps->leasearr[i].cli_hwaddr, client_msg->chaddr, client_msg->hlen) == 0) {
236                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
237                             ("find_client_lease: Found Client Lease at Index = %"U32_F"\n", i));
238                 return &(dhcps->leasearr[i]);
239             }
240         }
241     }
242 
243     return NULL;
244 }
245 
validate_discover(struct dhcps * dhcps,struct dhcp_msg * client_msg,struct dyn_lease_addr ** client_lease)246 LWIP_STATIC ip4_addr_t validate_discover(struct dhcps *dhcps, struct dhcp_msg *client_msg,
247                                          struct dyn_lease_addr **client_lease)
248 {
249     ip4_addr_t client_ip;
250     int idx = -1;
251 
252     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Validating Discover Message\n"));
253 
254     client_ip.addr = 0;
255     if (*client_lease == NULL) {
256         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Existing Client Lease not Found\n"));
257         if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
258             client_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
259 #ifdef  LWIP_DEV_DEBUG
260             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
261                         ("validate_discover function: Requested IP from client = %"U32_F"\n", client_ip.addr));
262 #endif
263 
264             if ((client_ip.addr >= dhcps->start_addr.addr) && (client_ip.addr <= dhcps->end_addr.addr)) {
265                 idx = (int)(client_ip.addr - dhcps->start_addr.addr);
266                 if ((dhcps->leasearr[idx].flags != DHCPS_ADDRESS_FREE) ||
267                     (ntohl(client_ip.addr) == ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
268                     /* Requested IP is not available */
269 #ifdef  LWIP_DEV_DEBUG
270                     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
271                       ("validate_discover function: Requested IP from client = %"U32_F" Not available \n", client_ip.addr));
272 #endif
273                     idx = -1;
274                 }
275             }
276         }
277 
278         if (idx == -1) {
279             idx = find_free_slot(dhcps);
280             if (idx == -1) {
281                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
282                             ("validate_discover function: No Free Slot available for Storing addresses\n"));
283                 client_ip.addr = 0;
284                 return client_ip;
285             }
286             client_ip.addr = dhcps->start_addr.addr + (u32_t)idx;
287 #ifdef  LWIP_DEV_DEBUG
288             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
289                         ("validate_discover function: New IP = %"U32_F" is being assigned\n", client_ip.addr));
290 #endif
291         }
292 
293         add_client_entry(dhcps, (unsigned int)idx, client_msg);
294         (*client_lease) = &(dhcps->leasearr[idx]);
295     } else {
296         client_ip.addr = (*client_lease)->cli_addr.addr;
297 #ifdef  LWIP_DEV_DEBUG
298         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
299                     ("validate_discover: Existing Client Lease Found. Existing IP =%"U32_F"\n", client_ip.addr));
300 #endif
301 
302         if ((dhcps_option_given(dhcps, DHCP_OPTION_IDX_LEASE_TIME))
303 #if (~0 != LWIP_DHCPS_LEASE_TIME)
304             && (dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
305 #endif
306             ) {
307             /* Assign the newly requested time or else use the existing lease time as-is */
308             (*client_lease)->proposed_leasetime = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME);
309         }
310     }
311 
312     return client_ip;
313 }
314 
dhcp_common_option(struct dhcp_msg * msg_out,u8_t option_type,u8_t option_len,u16_t * options_out_len)315 void dhcp_common_option(struct dhcp_msg *msg_out, u8_t option_type, u8_t option_len, u16_t *options_out_len)
316 {
317     *options_out_len = dhcp_option(*options_out_len, msg_out->options, option_type, option_len);
318 }
319 
dhcp_common_option_byte(struct dhcp_msg * msg_out,u8_t value,u16_t * options_out_len)320 void dhcp_common_option_byte(struct dhcp_msg *msg_out, u8_t value, u16_t *options_out_len)
321 {
322     *options_out_len = dhcp_option_byte(*options_out_len, msg_out->options, value);
323 }
324 
dhcp_common_option_long(struct dhcp_msg * msg_out,u32_t value,u16_t * options_out_len)325 void dhcp_common_option_long(struct dhcp_msg *msg_out, u32_t value, u16_t *options_out_len)
326 {
327     *options_out_len = dhcp_option_long(*options_out_len, msg_out->options, value);
328 }
329 
dhcp_common_option_trailer(struct dhcp_msg * msg_out,u16_t options_out_len,struct pbuf * p_out)330 void dhcp_common_option_trailer(struct dhcp_msg *msg_out, u16_t options_out_len, struct pbuf *p_out)
331 {
332     dhcp_option_trailer(options_out_len, msg_out->options, p_out);
333 }
334 
handle_discover(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease)335 LWIP_STATIC void handle_discover(struct netif *netif, struct dhcps *dhcps,
336                                  struct dhcp_msg *client_msg, struct dyn_lease_addr *client_lease)
337 {
338 #if !LWIP_DHCPS_DISCOVER_BROADCAST
339     ip_addr_t client_ipaddr;
340 #endif
341 
342     ip4_addr_t client_ip;
343     ip_addr_t dst_addr;
344     struct pbuf *out_msg = NULL;
345     struct dhcp_msg *srvr_msg = NULL;
346     u16_t options_len = 0;
347 #if !LWIP_DHCPS_DISCOVER_BROADCAST
348 #if ETHARP_SUPPORT_STATIC_ENTRIES
349     struct eth_addr ethaddr;
350 #endif
351 #endif
352     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Processing Discover Message\n"));
353 
354     client_ip = validate_discover(dhcps, client_msg, &client_lease);
355     if (client_ip.addr == 0) {
356         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
357                     ("handle_discover: Returning as unable to get a proper address for client\n"));
358         return;
359     }
360 
361     out_msg = dhcps_create_base_msg(client_msg);
362     if (out_msg == NULL) {
363         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
364                     ("handle_discover function: Memory allocation for base message failed\n"));
365         return;
366     }
367 
368     srvr_msg = (struct dhcp_msg *)out_msg->payload;
369     // no need check msg pointer from payload here
370     srvr_msg->yiaddr.addr = htonl(client_ip.addr);
371 
372     dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
373     dhcp_common_option_byte(srvr_msg, DHCP_OFFER, &options_len);
374 
375     /* hilink need this router option */
376     dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_SIZE, &options_len);
377     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
378 
379     /* netif already holds the Server ID in network order. so, no need to convert it again */
380     dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
381     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
382 
383     dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
384     dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
385 
386     dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
387     dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
388 
389     dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
390     /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
391     dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
392 
393     /* No need to convert netmask into network order as it is already stored in network order */
394     dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
395     dhcp_common_option_long(srvr_msg, ntohl(ip4_addr_get_u32(ip_2_ip4(&netif->netmask))), &options_len);
396 
397     dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
398 
399     if (client_msg->ciaddr.addr != 0) {
400         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: sendto(OFFER, ciaddr, DHCP_CLIENT_PORT)\n"));
401         ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
402         (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
403     }
404 #if !LWIP_DHCPS_DISCOVER_BROADCAST
405     else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
406         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
407                     ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT)\n"));
408         (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
409     } else {
410         client_ip.addr = htonl(client_ip.addr);
411 
412 #if ETHARP_SUPPORT_STATIC_ENTRIES
413         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Updating ARP Static Entry for unicast reply\n"));
414         if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
415             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("memcpy_s failed\n"));
416             (void)pbuf_free(out_msg);
417             return;
418         }
419         if (etharp_add_static_entry(&client_ip, &ethaddr) != ERR_OK) {
420             (void)pbuf_free(out_msg);
421             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Adding static entry to arp cache failed\n"));
422             return;
423         }
424 #endif
425 
426         /* Need to check and add an arp entry to make this pass through smoothly */
427         ip_addr_copy_from_ip4(client_ipaddr, client_ip);
428         (void)udp_sendto_if_src(dhcps->pcb, out_msg, &client_ipaddr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
429 #if ETHARP_SUPPORT_STATIC_ENTRIES
430         /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
431         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
432                     ("handle_discover: Removing ARP Static Entry added for unicast reply\n"));
433         (void)etharp_remove_static_entry(&client_ip);
434 #endif
435     }
436 #else
437     else {
438         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
439                     ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT)\n"));
440         (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
441     }
442 #endif
443 
444     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: deleting()ing\n"));
445     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Sending Reply has been successful\n"));
446 
447     (void)pbuf_free(out_msg);
448     return;
449 }
450 
validate_request_message(struct netif * netif,struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease,ip4_addr_t serverid)451 LWIP_STATIC ip4_addr_t validate_request_message(struct netif *netif, struct dhcp_msg *client_msg,
452                                                 struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
453 {
454     struct dhcps *dhcps = netif_get_dhcps(netif);
455     ip4_addr_t requested_ip;
456     requested_ip.addr = 0;
457 
458     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Processing Request Message\n"));
459 
460     if ((client_lease != NULL) && (client_lease->flags == DHCPS_ADDRESS_OFFERRED)) {
461         /* Now, we are in selecting state */
462         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: In Selecting State\n"));
463 
464         if ((serverid.addr == 0) || (client_msg->ciaddr.addr != 0) ||
465             (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP))) {
466             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
467                         ("Server ID or ciaddr or requested ip option is not present\n"));
468             return requested_ip;
469         }
470 
471         if (serverid.addr != ip_2_ip4(&netif->ip_addr)->addr) {
472             /* This message is not meant for us. The client intends to talk to some other server */
473             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
474                         ("validate_request_message: Server id doesn't match with ours. Message not for us\n"));
475             requested_ip.addr = 1;
476             return requested_ip;
477         }
478 
479         requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
480     } else {
481         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
482                     ("validate_request_message: In Init-Reboot, Renew or Rebinding State\n"));
483 
484         /* Now, we can be either in Init-reboot state or renew state or rebinding state */
485         if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
486             /* Requested IP option is filled in. Indicates we are mostly in Init-Reboot State */
487             if (client_lease == NULL) {
488                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
489                             ("validate_request_message: No Configuration found corresponding to request message\n"));
490                 return requested_ip;
491             }
492 
493             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
494                         ("validate_request_message: Requested IP Option is present. So, considering as Init-Reboot State\n"));
495 
496             if (client_msg->ciaddr.addr != 0) {
497                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
498                             ("validate_request_message: Error: ciaddr is filled in the Init-Reboot state. \n"));
499                 return requested_ip;
500             }
501 
502             requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
503         } else {
504             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: \
505                   Requested IP Option is not present. So, considering as Renewing or Rebinding State\n"));
506 
507             if (client_msg->ciaddr.addr == 0) {
508                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
509                             ("validate_request_message: Error: ciaddr is not filled in the Renewing or Rebinding state. \n"));
510                 return requested_ip;
511             }
512 
513             requested_ip.addr = ntohl(client_msg->ciaddr.addr);
514         }
515     }
516 
517     /* requested_ip is in host order and DHCP Server IP is in network order,
518       so converting the former to network order for check */
519     if (htonl(requested_ip.addr) == ip_2_ip4(&netif->ip_addr)->addr) {
520         /* This requested_ip is the dhcp server is using, it is invalid */
521         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Requested IP addr is invalid\n"));
522         requested_ip.addr = 1;
523     }
524 
525     return requested_ip;
526 }
527 
handle_request(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease,ip4_addr_t serverid)528 LWIP_STATIC void handle_request(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
529                                 struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
530 {
531     ip4_addr_t requested_ip;
532     struct pbuf *out_msg = NULL;
533     struct dhcp_msg *srvr_msg = NULL;
534     u16_t options_len = 0;
535     ip_addr_t dst_addr;
536     ip_addr_t ip_send;
537 #if ETHARP_SUPPORT_STATIC_ENTRIES
538     struct eth_addr ethaddr;
539 #endif
540 
541     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Processing Request Message\n"));
542 
543     requested_ip = validate_request_message(netif, client_msg, client_lease, serverid);
544     if (requested_ip.addr == 1) {
545         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
546                     ("handle_request: Validation of request message failed. Dropping the packet.\n"));
547         return;
548     }
549 
550     out_msg = dhcps_create_base_msg(client_msg);
551     if (out_msg == NULL) {
552         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Creating base message failed\n"));
553         return;
554     }
555 
556     srvr_msg = (struct dhcp_msg *)out_msg->payload;
557     dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
558     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
559 
560     /* hilink need this router option */
561     dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_SIZE, &options_len);
562     dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
563 
564     if ((client_lease != NULL) && (client_lease->cli_addr.addr == requested_ip.addr)) {
565         if (client_lease->proposed_leasetime != (u32_t)(~0)) {
566             if (client_lease->flags == DHCPS_ADDRESS_OFFERRED) {
567                 client_lease->leasetime = sys_now() + (client_lease->proposed_leasetime * 1000);
568             } else {
569                 client_lease->leasetime += (client_lease->proposed_leasetime * 1000);
570             }
571         } else {
572             client_lease->leasetime = client_lease->proposed_leasetime;
573         }
574 
575         client_lease->flags = DHCPS_ADDRESS_BOUND;
576         srvr_msg->yiaddr.addr = htonl(client_lease->cli_addr.addr);
577 
578         dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
579         dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
580 
581         dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
582         dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
583 
584         dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
585         dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
586 
587         dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
588         /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
589         dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
590 
591         dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
592         dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->netmask)->addr), &options_len);
593 
594 #ifdef  LWIP_DEV_DEBUG
595         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
596                     ("handle_request: Send ACK. to=%"U32_F" lease time=%"U32_F"\n",
597                     requested_ip.addr, client_lease->proposed_leasetime));
598 #endif
599     } else {
600         dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
601         dhcp_common_option_byte(srvr_msg, DHCP_NAK, &options_len);
602 
603         /* Just set this here, so that the NAK message is brcasted.
604         The correct flags has already been added in the response message during base message creation */
605         client_msg->flags |= htons(DHCP_BROADCAST_FLAG);
606         client_msg->ciaddr.addr = 0; /* This is done so that NAK Gets brcasted */
607 #ifdef  LWIP_DEV_DEBUG
608         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
609                     ("handle_request: Send NAK. Requested from=%"U32_F"\n", requested_ip.addr));
610 #endif
611     }
612 
613     requested_ip.addr = htonl(requested_ip.addr);
614     dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
615 
616     if (client_msg->ciaddr.addr != 0) {
617         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sendto(ACK, ciaddr, DHCP_CLIENT_PORT)\n"));
618         ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
619         (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
620     } else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
621         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sending reply using brdcast \n"));
622         (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
623     } else {
624 #if ETHARP_SUPPORT_STATIC_ENTRIES
625         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Updating ARP Static Entry for unicast reply\n"));
626         if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
627             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Copy chaddr failed\n"));
628             (void)pbuf_free(out_msg);
629             return;
630         }
631         if (ERR_OK != etharp_add_static_entry(&requested_ip, &ethaddr)) {
632             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Adding static entry to arp cache failed\n"));
633             (void)pbuf_free(out_msg);
634             return;
635         }
636 #endif
637         /* Need to check and add an arp entry to make this pass through smoothly */
638 #ifdef  LWIP_DEV_DEBUG
639         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
640                     ("handle_request: sending reply using unicast Client IP =%"U32_F"\n", requested_ip.addr));
641 #endif
642         ip_send.u_addr.ip4.addr = requested_ip.addr;
643         ip_send.type = IPADDR_TYPE_V4;
644         (void)udp_sendto_if_src(dhcps->pcb, out_msg, &ip_send, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
645 
646 #if ETHARP_SUPPORT_STATIC_ENTRIES
647         /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
648         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
649                     ("handle_request: Removing ARP Static Entry added for unicast reply\n"));
650         (void)etharp_remove_static_entry(&requested_ip);
651 #endif
652     }
653     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: deleting\n"));
654 
655     (void)pbuf_free(out_msg);
656     return;
657 }
658 
handle_decline(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,struct dyn_lease_addr * client_lease)659 LWIP_STATIC void handle_decline(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
660                                 struct dyn_lease_addr *client_lease)
661 {
662     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_decline: Processing Decline Message\n"));
663 
664     if ((client_lease != NULL) && (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) &&
665         (client_msg->ciaddr.addr == 0)) {
666         if (client_lease->cli_addr.addr == (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
667 #ifdef  LWIP_DEV_DEBUG
668             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
669                         ("handle_decline: Marking Client Entry as declined. Client IP =%"U32_F"\n",
670                         client_lease->cli_addr.addr));
671 #endif
672             (void)memset_s(client_lease->cli_hwaddr, sizeof(client_lease->cli_hwaddr), 0, DHCP_CHADDR_LEN);
673             client_lease->proposed_leasetime = 0;
674             client_lease->leasetime = sys_now() + (LWIP_DHCPS_DECLINE_TIME * 1000);
675             client_lease->flags = DHCPS_ADDRESS_DECLINED;
676         }
677     }
678 }
679 
handle_inform(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg)680 LWIP_STATIC void handle_inform(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg)
681 {
682     struct pbuf *out_msg = NULL;
683     struct dhcp_msg *srvr_msg = NULL;
684     u16_t options_len = 0;
685     ip_addr_t dst_addr;
686 
687     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Processing Inform Message\n"));
688 
689     if (client_msg->ciaddr.addr == 0) {
690         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: ciaddr is empty. Can't send back a response\n"));
691         return;
692     }
693 
694     out_msg = dhcps_create_base_msg(client_msg);
695     if (out_msg == NULL) {
696         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Creating base message failed\n"));
697         return;
698     }
699 
700     srvr_msg = (struct dhcp_msg *)out_msg->payload;
701     dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
702     dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
703 
704     dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
705 
706 #ifdef  LWIP_DEV_DEBUG
707     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
708                ("handle_inform: Send ACK to Client. Client is=%"U32_F"\n", client_msg->ciaddr.addr));
709 #endif
710     ip_addr_set_ip4_u32_val(dst_addr, client_msg->ciaddr.addr);
711     (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
712 
713     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: deleting pbuf\n"));
714     (void)pbuf_free(out_msg);
715 
716     return;
717 }
718 
handle_client_messages(struct netif * netif,struct dhcps * dhcps,struct dhcp_msg * client_msg,ip4_addr_t serverid,u8_t msg_type)719 LWIP_STATIC void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
720                                         struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type)
721 {
722     struct dyn_lease_addr *client_lease = NULL;
723 
724     client_lease = find_client_lease(dhcps, client_msg);
725     switch (msg_type) {
726         case DHCP_DISCOVER:
727             handle_discover(netif, dhcps, client_msg, client_lease);
728             break;
729         case DHCP_REQUEST:
730             handle_request(netif, dhcps, client_msg, client_lease, serverid);
731             break;
732         case DHCP_DECLINE:
733             handle_decline(netif, dhcps, client_msg, client_lease);
734             break;
735         case DHCP_RELEASE:
736             if ((client_lease != NULL) && (client_lease->cli_addr.addr == ntohl(client_msg->ciaddr.addr))) {
737 #ifdef  LWIP_DEV_DEBUG
738                 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP Release: Client IPAdd =%"U32_F"\n", client_msg->ciaddr.addr));
739 #endif
740                 (void)memset_s(client_lease, sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
741                 client_lease->flags = DHCPS_ADDRESS_FREE;
742             }
743             break;
744         case DHCP_INFORM:
745             handle_inform(netif, dhcps, client_msg);
746             break;
747         default:
748             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
749                         ("DHCP Server. Invalid message type received %d\n", msg_type));
750     }
751 }
752 
dhcps_parse_options(struct pbuf * p,struct dhcps * dhcps)753 err_t dhcps_parse_options(struct pbuf *p, struct dhcps *dhcps)
754 {
755     return dhcp_parse_reply(p, &dhcps->dhcp);
756 }
757 
dhcps_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * ip_addr,u16_t port)758 LWIP_STATIC void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *ip_addr, u16_t port)
759 {
760     struct netif *netif = (struct netif *)arg;
761     struct dhcps *dhcps = netif_get_dhcps(netif);
762     struct dhcp_msg *client_msg = (struct dhcp_msg *)p->payload;
763     u8_t msg_type;
764     ip4_addr_t serverid;
765     ip4_addr_t addr;
766 
767     if (client_msg == NULL) {
768         return;
769     }
770     addr.addr = ip_addr->u_addr.ip4.addr;
771     serverid.addr = 0;
772 #ifdef  LWIP_DEV_DEBUG
773     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
774                 ("dhcps_recv(pbuf = %p) from DHCP Client %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
775                 ip4_addr1_16(&addr), ip4_addr2_16(&addr), ip4_addr3_16(&addr), ip4_addr4_16(&addr), port));
776 #endif
777     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
778     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
779     /* prevent warnings about unused arguments */
780     LWIP_UNUSED_ARG(pcb);
781     LWIP_UNUSED_ARG(addr);
782     LWIP_UNUSED_ARG(port);
783 
784     dhcps_clear_all_options(dhcps);
785 
786     /* Check and remove old entries on each call to dhcp_recv. This way, we don't need to maintain timers */
787     remove_stale_entries(dhcps);
788 
789     if (p->len < DHCP_OPTIONS_OFS) {
790         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
791                     ("DHCP client message or pbuf too short. pbuf len =%"U16_F" DHCP MIN Reply Len = %"U32_F"\n",
792                         p->len, DHCP_MIN_REPLY_LEN));
793         goto free_pbuf_and_return;
794     }
795 
796     if (client_msg->op != DHCP_BOOTREQUEST) {
797         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
798                     ("Not a DHCP reply message, Type %"U16_F"\n", (u16_t)client_msg->op));
799         goto free_pbuf_and_return;
800     }
801 
802     if (client_msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)) {
803         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
804                     ("DHCP Server. Cookie Value is incorrect. %"U32_F"\n", (u32_t)client_msg->cookie));
805         goto free_pbuf_and_return;
806     }
807 
808     if (client_msg->hlen != ETHARP_HWADDR_LEN) {
809         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
810                     ("DHCP Server. Invalid hardware address length %"U16_F"\n", (u16_t)client_msg->hlen));
811         goto free_pbuf_and_return;
812     }
813 
814     if (dhcps_parse_options(p, dhcps) != ERR_OK) {
815         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
816                     ("Parsing of Options failed in DHCP Client Message\n"));
817         goto free_pbuf_and_return;
818     }
819 
820     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("Searching DHCP_OPTION_MESSAGE_TYPE\n"));
821     /* obtain pointer to DHCP message type */
822     if (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_MSG_TYPE)) {
823         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
824                     ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
825         goto free_pbuf_and_return;
826     }
827 
828     /* read DHCP message type */
829     msg_type = (u8_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_MSG_TYPE);
830 
831     if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_SERVER_ID)) {
832         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
833                     ("DHCP_OPTION_SERVER_ID option found\n"));
834         /* Parse options would have changed it to host order. But, we have our IP stored in netif in network order */
835         serverid.addr = htonl((u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_SERVER_ID));
836     }
837 
838     if ((serverid.addr != 0) && ((msg_type == DHCP_DISCOVER) || (msg_type == DHCP_INFORM))) {
839         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
840                     ("Serverid present in DHCP_DISCOVER and DHCP_INFORM messages\n"));
841         goto free_pbuf_and_return;
842     }
843 
844     if ((!ip4_addr_cmp(&serverid, ip_2_ip4(&netif->ip_addr))) &&
845         ((msg_type == DHCP_DECLINE) || (msg_type == DHCP_RELEASE))) {
846         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
847                     ("Serverid not present in DHCP_RELEASE and DHCP_DECLINE messages\n"));
848         goto free_pbuf_and_return;
849     }
850 
851     handle_client_messages(netif, dhcps, client_msg, serverid, msg_type);
852 
853 free_pbuf_and_return:
854     (void)pbuf_free(p);
855 }
856 
dhcps_start(struct netif * netif,const char * start_ip,u16_t ip_num)857 err_t dhcps_start(struct netif *netif, const char *start_ip, u16_t ip_num)
858 {
859     struct dhcps *dhcps = NULL;
860     ip4_addr_t address_in_hton;
861     int err;
862 
863     LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
864     dhcps = netif_get_dhcps(netif);
865 
866     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
867                 ("dhcps_start(netif=%p) %s\n", (void *)netif, netif_get_name(netif)));
868 
869     if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
870         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
871                     ("MTU =%"U16_F",DHCP Msg Len Required =%"U32_F"\n", netif->mtu, DHCP_MAX_MSG_LEN_MIN_REQUIRED));
872         return ERR_MEM;
873     }
874 
875     if (dhcps != NULL) {
876         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): DHCP Server is already started\n"));
877         return ERR_MEM;
878     }
879 
880     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting new DHCP Server\n"));
881     dhcps = (struct dhcps *)mem_malloc(sizeof(struct dhcps));
882     if (dhcps == NULL) {
883         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): could not allocate dhcp\n"));
884         return ERR_MEM;
885     }
886 
887     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): allocated dhcp"));
888 
889     (void)memset_s(dhcps, sizeof(struct dhcps), 0, sizeof(struct dhcps));
890 
891     dhcps->pcb = udp_new();
892     if (dhcps->pcb == NULL) {
893         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate pcb\n"));
894         mem_free((void *)dhcps);
895         return ERR_MEM;
896     }
897 
898 #if LWIP_SO_BINDTODEVICE
899     /* bind dhcp udp_pcb to specific netif, this could make dhcp server start on multiple netif */
900     dhcps->pcb->ifindex = netif->ifindex;
901 #endif
902     if ((start_ip == NULL) || (ip_num == 0)) {
903         /* use default ip lease configuration. */
904         dhcps->start_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr) + 1;
905         dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
906         dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
907         if (dhcps->lease_num > LWIP_DHCPS_MAX_LEASE) {
908             dhcps->lease_num = LWIP_DHCPS_MAX_LEASE;
909             dhcps->end_addr.addr = dhcps->start_addr.addr + LWIP_DHCPS_MAX_LEASE - 1;
910         }
911     } else {
912         dhcps->start_addr.addr = ntohl(ipaddr_addr(start_ip));
913         dhcps->end_addr.addr = (u32_t)(dhcps->start_addr.addr +
914                                        (u32_t)(LWIP_MIN(ip_num - 1, LWIP_DHCPS_MAX_LEASE - 1)));
915 
916         ip4_addr_set_hton(&address_in_hton, &dhcps->start_addr);
917 
918         if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
919             ip4_addr_isbroadcast((&address_in_hton), netif)) {
920             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): %s in not a valid ip lease\n", start_ip));
921             udp_remove(dhcps->pcb);
922             mem_free((void *)dhcps);
923             return ERR_ARG;
924         }
925 
926         ip4_addr_set_hton(&address_in_hton, &dhcps->end_addr);
927 
928         if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
929             ip4_addr_isbroadcast((&address_in_hton), netif)) {
930             dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
931         }
932         dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
933     }
934 
935     dhcps->netif = netif;
936     dhcps->pcb->so_options |= SOF_BROADCAST;
937     err = udp_bind(dhcps->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
938     if (err != ERR_OK) {
939         udp_remove(dhcps->pcb);
940         mem_free((void *)dhcps);
941         return ERR_MEM;
942     }
943 
944     err = udp_connect(dhcps->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
945     if (err != ERR_OK) {
946         udp_remove(dhcps->pcb);
947         mem_free((void *)dhcps);
948         return ERR_MEM;
949     }
950     udp_recv(dhcps->pcb, dhcps_recv, netif);
951     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting DHCPS Successfully\n"));
952 #ifdef  LWIP_DEV_DEBUG
953     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
954                 ("dhcps_start(): DHCPS Conf:: netif addr = %"U32_F" dhcps start addr%"U32_F" dhcp end addr%"U32_F"\n",
955                 ip_2_ip4(&netif->ip_addr)->addr, dhcps->start_addr.addr, dhcps->end_addr.addr));
956 #endif
957     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
958                 ("dhcps_start(): DHCPS Lease Conf:: Lease Time = %"U32_F" Offer Time = %"U32_F"\n",
959                     LWIP_DHCPS_LEASE_TIME, LWIP_DHCPS_OFFER_TIME));
960     netif_set_dhcps(netif, dhcps);
961     return ERR_OK;
962 }
963 
dhcps_stop(struct netif * netif)964 void dhcps_stop(struct netif *netif)
965 {
966     LWIP_ERROR("dhcps_stop: netif != NULL", (netif != NULL), return);
967     struct dhcps *dhcps = netif_get_dhcps(netif);
968     if (dhcps != NULL) {
969         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Stopping DHCP Server\n"));
970         if (dhcps->pcb != NULL) {
971             LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Removing UDP PCB\n"));
972             udp_remove(dhcps->pcb);
973             dhcps->pcb = NULL;
974         }
975 
976         mem_free(dhcps);
977         netif_set_dhcps(netif, NULL);
978     }
979 }
980 
981 #endif
982 
983