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, ðaddr) != 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, ðaddr)) {
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