1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
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 //#include "esp_common.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include "lwip/inet.h"
18 #include "lwip/err.h"
19 #include "lwip/pbuf.h"
20 #include "lwip/udp.h"
21 #include "lwip/mem.h"
22 #include "lwip/ip_addr.h"
23 #include "esp_netif.h"
24
25 #include "dhcpserver/dhcpserver.h"
26 #include "dhcpserver/dhcpserver_options.h"
27
28 #if ESP_DHCP
29
30 #define BOOTP_BROADCAST 0x8000
31
32 #define DHCP_REQUEST 1
33 #define DHCP_REPLY 2
34 #define DHCP_HTYPE_ETHERNET 1
35 #define DHCP_HLEN_ETHERNET 6
36 #define DHCP_MSG_LEN 236
37
38 #define DHCPS_SERVER_PORT 67
39 #define DHCPS_CLIENT_PORT 68
40
41 #define DHCPDISCOVER 1
42 #define DHCPOFFER 2
43 #define DHCPREQUEST 3
44 #define DHCPDECLINE 4
45 #define DHCPACK 5
46 #define DHCPNAK 6
47 #define DHCPRELEASE 7
48
49 #define DHCP_OPTION_SUBNET_MASK 1
50 #define DHCP_OPTION_ROUTER 3
51 #define DHCP_OPTION_DNS_SERVER 6
52 #define DHCP_OPTION_REQ_IPADDR 50
53 #define DHCP_OPTION_LEASE_TIME 51
54 #define DHCP_OPTION_MSG_TYPE 53
55 #define DHCP_OPTION_SERVER_ID 54
56 #define DHCP_OPTION_INTERFACE_MTU 26
57 #define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31
58 #define DHCP_OPTION_BROADCAST_ADDRESS 28
59 #define DHCP_OPTION_REQ_LIST 55
60 #define DHCP_OPTION_END 255
61
62 //#define USE_CLASS_B_NET 1
63 #define DHCPS_DEBUG 0
64 #define DHCPS_LOG printf
65
66 #define MAX_STATION_NUM CONFIG_LWIP_DHCPS_MAX_STATION_NUM
67
68 #define DHCPS_STATE_OFFER 1
69 #define DHCPS_STATE_DECLINE 2
70 #define DHCPS_STATE_ACK 3
71 #define DHCPS_STATE_NAK 4
72 #define DHCPS_STATE_IDLE 5
73 #define DHCPS_STATE_RELEASE 6
74
75 typedef struct _list_node {
76 void *pnode;
77 struct _list_node *pnext;
78 } list_node;
79
80 ////////////////////////////////////////////////////////////////////////////////////
81
82 static const u32_t magic_cookie = 0x63538263;
83
84 static struct netif *dhcps_netif = NULL;
85 static ip4_addr_t broadcast_dhcps;
86 static ip4_addr_t server_address;
87 static ip4_addr_t dns_server = {0};
88 static ip4_addr_t client_address; //added
89 static ip4_addr_t client_address_plus;
90 static ip4_addr_t s_dhcps_mask = {
91 #ifdef USE_CLASS_B_NET
92 .addr = PP_HTONL(LWIP_MAKEU32(255, 240, 0, 0))
93 #else
94 .addr = PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0))
95 #endif
96 };
97
98 static list_node *plist = NULL;
99 static bool renew = false;
100
101 static dhcps_lease_t dhcps_poll;
102 static dhcps_time_t dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute
103 static dhcps_offer_t dhcps_offer = 0xFF;
104 static dhcps_offer_t dhcps_dns = 0x00;
105 static dhcps_cb_t dhcps_cb;
106
107 /******************************************************************************
108 * FunctionName : dhcps_option_info
109 * Description : get the DHCP message option info
110 * Parameters : op_id -- DHCP message option id
111 * opt_len -- DHCP message option length
112 * Returns : DHCP message option addr
113 *******************************************************************************/
dhcps_option_info(u8_t op_id,u32_t opt_len)114 void *dhcps_option_info(u8_t op_id, u32_t opt_len)
115 {
116 void *option_arg = NULL;
117
118 switch (op_id) {
119 case IP_ADDRESS_LEASE_TIME:
120 if (opt_len == sizeof(dhcps_time_t)) {
121 option_arg = &dhcps_lease_time;
122 }
123
124 break;
125
126 case REQUESTED_IP_ADDRESS:
127 if (opt_len == sizeof(dhcps_lease_t)) {
128 option_arg = &dhcps_poll;
129 }
130
131 break;
132
133 case ROUTER_SOLICITATION_ADDRESS:
134 if (opt_len == sizeof(dhcps_offer_t)) {
135 option_arg = &dhcps_offer;
136 }
137
138 break;
139
140 case DOMAIN_NAME_SERVER:
141 if (opt_len == sizeof(dhcps_offer_t)) {
142 option_arg = &dhcps_dns;
143 }
144
145 break;
146 case SUBNET_MASK:
147 if (opt_len == sizeof(s_dhcps_mask)) {
148 option_arg = &s_dhcps_mask;
149 }
150
151 break;
152 default:
153 break;
154 }
155
156 return option_arg;
157 }
158
159 /******************************************************************************
160 * FunctionName : dhcps_set_option_info
161 * Description : set the DHCP message option info
162 * Parameters : op_id -- DHCP message option id
163 * opt_info -- DHCP message option info
164 * opt_len -- DHCP message option length
165 * Returns : none
166 *******************************************************************************/
dhcps_set_option_info(u8_t op_id,void * opt_info,u32_t opt_len)167 void dhcps_set_option_info(u8_t op_id, void *opt_info, u32_t opt_len)
168 {
169 if (opt_info == NULL) {
170 return;
171 }
172 switch (op_id) {
173 case IP_ADDRESS_LEASE_TIME:
174 if (opt_len == sizeof(dhcps_time_t)) {
175 dhcps_lease_time = *(dhcps_time_t *)opt_info;
176 }
177
178 break;
179
180 case REQUESTED_IP_ADDRESS:
181 if (opt_len == sizeof(dhcps_lease_t)) {
182 dhcps_poll = *(dhcps_lease_t *)opt_info;
183 }
184
185 break;
186
187 case ROUTER_SOLICITATION_ADDRESS:
188 if (opt_len == sizeof(dhcps_offer_t)) {
189 dhcps_offer = *(dhcps_offer_t *)opt_info;
190 }
191
192 break;
193
194 case DOMAIN_NAME_SERVER:
195 if (opt_len == sizeof(dhcps_offer_t)) {
196 dhcps_dns = *(dhcps_offer_t *)opt_info;
197 }
198 break;
199
200 case SUBNET_MASK:
201 if (opt_len == sizeof(s_dhcps_mask)) {
202 s_dhcps_mask = *(ip4_addr_t *)opt_info;
203 }
204
205
206 default:
207 break;
208 }
209 return;
210 }
211
212 /******************************************************************************
213 * FunctionName : node_insert_to_list
214 * Description : insert the node to the list
215 * Parameters : phead -- the head node of the list
216 * pinsert -- the insert node of the list
217 * Returns : none
218 *******************************************************************************/
node_insert_to_list(list_node ** phead,list_node * pinsert)219 static void node_insert_to_list(list_node **phead, list_node *pinsert)
220 {
221 list_node *plist = NULL;
222 struct dhcps_pool *pdhcps_pool = NULL;
223 struct dhcps_pool *pdhcps_node = NULL;
224
225 if (*phead == NULL) {
226 *phead = pinsert;
227 } else {
228 plist = *phead;
229 pdhcps_node = pinsert->pnode;
230 pdhcps_pool = plist->pnode;
231
232 if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
233 pinsert->pnext = plist;
234 *phead = pinsert;
235 } else {
236 while (plist->pnext != NULL) {
237 pdhcps_pool = plist->pnext->pnode;
238
239 if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
240 pinsert->pnext = plist->pnext;
241 plist->pnext = pinsert;
242 break;
243 }
244
245 plist = plist->pnext;
246 }
247
248 if (plist->pnext == NULL) {
249 plist->pnext = pinsert;
250 }
251 }
252 }
253
254 // pinsert->pnext = NULL;
255 }
256
257 /******************************************************************************
258 * FunctionName : node_delete_from_list
259 * Description : remove the node from list
260 * Parameters : phead -- the head node of the list
261 * pdelete -- the remove node of the list
262 * Returns : none
263 *******************************************************************************/
node_remove_from_list(list_node ** phead,list_node * pdelete)264 void node_remove_from_list(list_node **phead, list_node *pdelete)
265 {
266 list_node *plist = NULL;
267
268 plist = *phead;
269
270 if (plist == NULL) {
271 *phead = NULL;
272 } else {
273 if (plist == pdelete) {
274 // Note: Ignoring the "use after free" warnings, as it could only happen
275 // if the linked list contains loops
276 *phead = plist->pnext; // NOLINT(clang-analyzer-unix.Malloc)
277 pdelete->pnext = NULL;
278 } else {
279 while (plist != NULL) {
280 if (plist->pnext == pdelete) { // NOLINT(clang-analyzer-unix.Malloc)
281 plist->pnext = pdelete->pnext;
282 pdelete->pnext = NULL;
283 }
284
285 plist = plist->pnext;
286 }
287 }
288 }
289 }
290
291 /******************************************************************************
292 * FunctionName : add_msg_type
293 * Description : add TYPE option of DHCP message
294 * Parameters : optptr -- the addr of DHCP message option
295 * Returns : the addr of DHCP message option
296 *******************************************************************************/
add_msg_type(u8_t * optptr,u8_t type)297 static u8_t *add_msg_type(u8_t *optptr, u8_t type)
298 {
299 *optptr++ = DHCP_OPTION_MSG_TYPE;
300 *optptr++ = 1;
301 *optptr++ = type;
302 return optptr;
303 }
304
305 /******************************************************************************
306 * FunctionName : add_offer_options
307 * Description : add OFFER option of DHCP message
308 * Parameters : optptr -- the addr of DHCP message option
309 * Returns : the addr of DHCP message option
310 *******************************************************************************/
add_offer_options(u8_t * optptr)311 static u8_t *add_offer_options(u8_t *optptr)
312 {
313 ip4_addr_t ipadd;
314
315 ipadd.addr = *((u32_t *) &server_address);
316
317 *optptr++ = DHCP_OPTION_SUBNET_MASK;
318 *optptr++ = 4;
319 *optptr++ = ip4_addr1(&s_dhcps_mask);
320 *optptr++ = ip4_addr2(&s_dhcps_mask);
321 *optptr++ = ip4_addr3(&s_dhcps_mask);
322 *optptr++ = ip4_addr4(&s_dhcps_mask);
323
324 *optptr++ = DHCP_OPTION_LEASE_TIME;
325 *optptr++ = 4;
326 *optptr++ = ((dhcps_lease_time * DHCPS_LEASE_UNIT) >> 24) & 0xFF;
327 *optptr++ = ((dhcps_lease_time * DHCPS_LEASE_UNIT) >> 16) & 0xFF;
328 *optptr++ = ((dhcps_lease_time * DHCPS_LEASE_UNIT) >> 8) & 0xFF;
329 *optptr++ = ((dhcps_lease_time * DHCPS_LEASE_UNIT) >> 0) & 0xFF;
330
331 *optptr++ = DHCP_OPTION_SERVER_ID;
332 *optptr++ = 4;
333 *optptr++ = ip4_addr1(&ipadd);
334 *optptr++ = ip4_addr2(&ipadd);
335 *optptr++ = ip4_addr3(&ipadd);
336 *optptr++ = ip4_addr4(&ipadd);
337
338 if (dhcps_router_enabled(dhcps_offer)) {
339 esp_netif_ip_info_t if_ip;
340 memset(&if_ip , 0x00, sizeof(esp_netif_ip_info_t));
341 esp_netif_get_ip_info(dhcps_netif->state, &if_ip);
342
343 ip4_addr_t* gw_ip = (ip4_addr_t*)&if_ip.gw;
344
345 if (!ip4_addr_isany_val(*gw_ip)) {
346 *optptr++ = DHCP_OPTION_ROUTER;
347 *optptr++ = 4;
348 *optptr++ = ip4_addr1(gw_ip);
349 *optptr++ = ip4_addr2(gw_ip);
350 *optptr++ = ip4_addr3(gw_ip);
351 *optptr++ = ip4_addr4(gw_ip);
352 }
353 }
354
355 *optptr++ = DHCP_OPTION_DNS_SERVER;
356 *optptr++ = 4;
357 if (dhcps_dns_enabled(dhcps_dns)) {
358 *optptr++ = ip4_addr1(&dns_server);
359 *optptr++ = ip4_addr2(&dns_server);
360 *optptr++ = ip4_addr3(&dns_server);
361 *optptr++ = ip4_addr4(&dns_server);
362 }else {
363 *optptr++ = ip4_addr1(&ipadd);
364 *optptr++ = ip4_addr2(&ipadd);
365 *optptr++ = ip4_addr3(&ipadd);
366 *optptr++ = ip4_addr4(&ipadd);
367 }
368
369 ip4_addr_t broadcast_addr = { .addr = (ipadd.addr & s_dhcps_mask.addr) | ~s_dhcps_mask.addr };
370 *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
371 *optptr++ = 4;
372 *optptr++ = ip4_addr1(&broadcast_addr);
373 *optptr++ = ip4_addr2(&broadcast_addr);
374 *optptr++ = ip4_addr3(&broadcast_addr);
375 *optptr++ = ip4_addr4(&broadcast_addr);
376
377 *optptr++ = DHCP_OPTION_INTERFACE_MTU;
378 *optptr++ = 2;
379 *optptr++ = 0x05;
380 *optptr++ = 0xdc;
381
382 *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;
383 *optptr++ = 1;
384 *optptr++ = 0x00;
385
386 *optptr++ = 43;
387 *optptr++ = 6;
388
389 *optptr++ = 0x01;
390 *optptr++ = 4;
391 *optptr++ = 0x00;
392 *optptr++ = 0x00;
393 *optptr++ = 0x00;
394 *optptr++ = 0x02;
395
396 return optptr;
397 }
398
399 /******************************************************************************
400 * FunctionName : add_end
401 * Description : add end option of DHCP message
402 * Parameters : optptr -- the addr of DHCP message option
403 * Returns : the addr of DHCP message option
404 *******************************************************************************/
add_end(u8_t * optptr)405 static u8_t *add_end(u8_t *optptr)
406 {
407 *optptr++ = DHCP_OPTION_END;
408 return optptr;
409 }
410
411 /******************************************************************************
412 * FunctionName : create_msg
413 * Description : create response message
414 * Parameters : m -- DHCP message info
415 * Returns : none
416 *******************************************************************************/
create_msg(struct dhcps_msg * m)417 static void create_msg(struct dhcps_msg *m)
418 {
419 ip4_addr_t client;
420
421
422 client.addr = *((uint32_t *) &client_address);
423
424 m->op = DHCP_REPLY;
425
426 m->htype = DHCP_HTYPE_ETHERNET;
427
428 m->hlen = 6;
429
430 m->hops = 0;
431 // os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid));
432 m->secs = 0;
433 m->flags = htons(BOOTP_BROADCAST);
434
435 memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr));
436
437 memset((char *) m->ciaddr, 0, sizeof(m->ciaddr));
438
439 memset((char *) m->siaddr, 0, sizeof(m->siaddr));
440
441 memset((char *) m->giaddr, 0, sizeof(m->giaddr));
442
443 memset((char *) m->sname, 0, sizeof(m->sname));
444
445 memset((char *) m->file, 0, sizeof(m->file));
446
447 memset((char *) m->options, 0, sizeof(m->options));
448
449 u32_t magic_cookie_temp = magic_cookie;
450
451 memcpy((char *) m->options, &magic_cookie_temp, sizeof(magic_cookie_temp));
452 }
453
dhcps_pbuf_alloc(u16_t len)454 struct pbuf * dhcps_pbuf_alloc(u16_t len)
455 {
456 u16_t mlen = sizeof(struct dhcps_msg);
457
458 if (len > mlen) {
459 #if DHCPS_DEBUG
460 DHCPS_LOG("dhcps: len=%d mlen=%d", len, mlen);
461 #endif
462 mlen = len;
463 }
464
465 return pbuf_alloc(PBUF_TRANSPORT, mlen, PBUF_RAM);
466 }
467
468 /******************************************************************************
469 * FunctionName : send_offer
470 * Description : DHCP message OFFER Response
471 * Parameters : m -- DHCP message info
472 * Returns : none
473 *******************************************************************************/
send_offer(struct dhcps_msg * m,u16_t len)474 static void send_offer(struct dhcps_msg *m, u16_t len)
475 {
476 u8_t *end;
477 struct pbuf *p, *q;
478 u8_t *data;
479 u16_t cnt = 0;
480 u16_t i;
481 #if DHCPS_DEBUG
482 err_t SendOffer_err_t;
483 #endif
484 create_msg(m);
485
486 end = add_msg_type(&m->options[4], DHCPOFFER);
487 end = add_offer_options(end);
488 end = add_end(end);
489
490 p = dhcps_pbuf_alloc(len);
491 #if DHCPS_DEBUG
492 DHCPS_LOG("udhcp: send_offer>>p->ref = %d\n", p->ref);
493 #endif
494
495 if (p != NULL) {
496
497 #if DHCPS_DEBUG
498 DHCPS_LOG("dhcps: send_offer>>pbuf_alloc succeed\n");
499 DHCPS_LOG("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len);
500 DHCPS_LOG("dhcps: send_offer>>p->len = %d\n", p->len);
501 #endif
502 q = p;
503
504 while (q != NULL) {
505 data = (u8_t *)q->payload;
506
507 for (i = 0; i < q->len; i++) {
508 data[i] = ((u8_t *) m)[cnt++];
509 #if DHCPS_DEBUG
510 DHCPS_LOG("%02x ", data[i]);
511
512 if ((i + 1) % 16 == 0) {
513 DHCPS_LOG("\n");
514 }
515
516 #endif
517 }
518
519 q = q->next;
520 }
521 } else {
522
523 #if DHCPS_DEBUG
524 DHCPS_LOG("dhcps: send_offer>>pbuf_alloc failed\n");
525 #endif
526 return;
527 }
528
529 ip_addr_t ip_temp = IPADDR4_INIT(0x0);
530 ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
531 struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb;
532 #if DHCPS_DEBUG
533 SendOffer_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
534 DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t);
535 #else
536 udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
537 #endif
538
539 if (p->ref != 0) {
540 #if DHCPS_DEBUG
541 DHCPS_LOG("udhcp: send_offer>>free pbuf\n");
542 #endif
543 pbuf_free(p);
544 }
545 }
546
547 /******************************************************************************
548 * FunctionName : send_nak
549 * Description : DHCP message NACK Response
550 * Parameters : m -- DHCP message info
551 * Returns : none
552 *******************************************************************************/
send_nak(struct dhcps_msg * m,u16_t len)553 static void send_nak(struct dhcps_msg *m, u16_t len)
554 {
555 u8_t *end;
556 struct pbuf *p, *q;
557 u8_t *data;
558 u16_t cnt = 0;
559 u16_t i;
560 #if DHCPS_DEBUG
561 err_t SendNak_err_t;
562 #endif
563 create_msg(m);
564
565 end = add_msg_type(&m->options[4], DHCPNAK);
566 end = add_end(end);
567
568 p = dhcps_pbuf_alloc(len);
569 #if DHCPS_DEBUG
570 DHCPS_LOG("udhcp: send_nak>>p->ref = %d\n", p->ref);
571 #endif
572
573 if (p != NULL) {
574
575 #if DHCPS_DEBUG
576 DHCPS_LOG("dhcps: send_nak>>pbuf_alloc succeed\n");
577 DHCPS_LOG("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len);
578 DHCPS_LOG("dhcps: send_nak>>p->len = %d\n", p->len);
579 #endif
580 q = p;
581
582 while (q != NULL) {
583 data = (u8_t *)q->payload;
584
585 for (i = 0; i < q->len; i++) {
586 data[i] = ((u8_t *) m)[cnt++];
587 #if DHCPS_DEBUG
588 DHCPS_LOG("%02x ", data[i]);
589
590 if ((i + 1) % 16 == 0) {
591 DHCPS_LOG("\n");
592 }
593
594 #endif
595 }
596
597 q = q->next;
598 }
599 } else {
600
601 #if DHCPS_DEBUG
602 DHCPS_LOG("dhcps: send_nak>>pbuf_alloc failed\n");
603 #endif
604 return;
605 }
606
607 ip_addr_t ip_temp = IPADDR4_INIT(0x0);
608 ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
609 struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb;
610 #if DHCPS_DEBUG
611 SendNak_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
612 DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t);
613 #else
614 udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
615 #endif
616
617 if (p->ref != 0) {
618 #if DHCPS_DEBUG
619 DHCPS_LOG("udhcp: send_nak>>free pbuf\n");
620 #endif
621 pbuf_free(p);
622 }
623 }
624
625 /******************************************************************************
626 * FunctionName : send_ack
627 * Description : DHCP message ACK Response
628 * Parameters : m -- DHCP message info
629 * Returns : none
630 *******************************************************************************/
send_ack(struct dhcps_msg * m,u16_t len)631 static void send_ack(struct dhcps_msg *m, u16_t len)
632 {
633 u8_t *end;
634 struct pbuf *p, *q;
635 u8_t *data;
636 u16_t cnt = 0;
637 u16_t i;
638 err_t SendAck_err_t;
639 create_msg(m);
640
641 end = add_msg_type(&m->options[4], DHCPACK);
642 end = add_offer_options(end);
643 end = add_end(end);
644
645 p = dhcps_pbuf_alloc(len);
646 #if DHCPS_DEBUG
647 DHCPS_LOG("udhcp: send_ack>>p->ref = %d\n", p->ref);
648 #endif
649
650 if (p != NULL) {
651
652 #if DHCPS_DEBUG
653 DHCPS_LOG("dhcps: send_ack>>pbuf_alloc succeed\n");
654 DHCPS_LOG("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len);
655 DHCPS_LOG("dhcps: send_ack>>p->len = %d\n", p->len);
656 #endif
657 q = p;
658
659 while (q != NULL) {
660 data = (u8_t *)q->payload;
661
662 for (i = 0; i < q->len; i++) {
663 data[i] = ((u8_t *) m)[cnt++];
664 #if DHCPS_DEBUG
665 DHCPS_LOG("%02x ", data[i]);
666
667 if ((i + 1) % 16 == 0) {
668 DHCPS_LOG("\n");
669 }
670
671 #endif
672 }
673
674 q = q->next;
675 }
676 } else {
677
678 #if DHCPS_DEBUG
679 DHCPS_LOG("dhcps: send_ack>>pbuf_alloc failed\n");
680 #endif
681 return;
682 }
683
684 ip_addr_t ip_temp = IPADDR4_INIT(0x0);
685 ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
686 struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb;
687 SendAck_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
688 #if DHCPS_DEBUG
689 DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n", SendAck_err_t);
690 #endif
691
692 if (SendAck_err_t == ERR_OK) {
693 dhcps_cb(m->yiaddr);
694 }
695
696 if (p->ref != 0) {
697 #if DHCPS_DEBUG
698 DHCPS_LOG("udhcp: send_ack>>free pbuf\n");
699 #endif
700 pbuf_free(p);
701 }
702 }
703
704 /******************************************************************************
705 * FunctionName : parse_options
706 * Description : parse DHCP message options
707 * Parameters : optptr -- DHCP message option info
708 * len -- DHCP message option length
709 * Returns : none
710 *******************************************************************************/
parse_options(u8_t * optptr,s16_t len)711 static u8_t parse_options(u8_t *optptr, s16_t len)
712 {
713 ip4_addr_t client;
714 bool is_dhcp_parse_end = false;
715 struct dhcps_state s;
716
717 client.addr = *((uint32_t *) &client_address);
718
719 u8_t *end = optptr + len;
720 u16_t type = 0;
721
722 s.state = DHCPS_STATE_IDLE;
723
724 while (optptr < end) {
725 #if DHCPS_DEBUG
726 DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr);
727 #endif
728
729 switch ((s16_t) *optptr) {
730
731 case DHCP_OPTION_MSG_TYPE: //53
732 type = *(optptr + 2);
733 break;
734
735 case DHCP_OPTION_REQ_IPADDR://50
736 if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) {
737 #if DHCPS_DEBUG
738 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n");
739 #endif
740 s.state = DHCPS_STATE_ACK;
741 } else {
742 #if DHCPS_DEBUG
743 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n");
744 #endif
745 s.state = DHCPS_STATE_NAK;
746 }
747
748 break;
749
750 case DHCP_OPTION_END: {
751 is_dhcp_parse_end = true;
752 }
753 break;
754 }
755
756 if (is_dhcp_parse_end) {
757 break;
758 }
759
760 optptr += optptr[1] + 2;
761 }
762
763 switch (type) {
764
765 case DHCPDISCOVER://1
766 s.state = DHCPS_STATE_OFFER;
767 #if DHCPS_DEBUG
768 DHCPS_LOG("dhcps: DHCPD_STATE_OFFER\n");
769 #endif
770 break;
771
772 case DHCPREQUEST://3
773 if (!(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK)) {
774 if (renew == true) {
775 s.state = DHCPS_STATE_ACK;
776 } else {
777 s.state = DHCPS_STATE_NAK;
778 }
779
780 #if DHCPS_DEBUG
781 DHCPS_LOG("dhcps: DHCPD_STATE_NAK\n");
782 #endif
783 }
784
785 break;
786
787 case DHCPDECLINE://4
788 s.state = DHCPS_STATE_IDLE;
789 #if DHCPS_DEBUG
790 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
791 #endif
792 break;
793
794 case DHCPRELEASE://7
795 s.state = DHCPS_STATE_RELEASE;
796 #if DHCPS_DEBUG
797 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
798 #endif
799 break;
800 }
801
802 #if DHCPS_DEBUG
803 DHCPS_LOG("dhcps: return s.state = %d\n", s.state);
804 #endif
805 return s.state;
806 }
807
808 /******************************************************************************
809 * FunctionName : parse_msg
810 * Description : parse DHCP message from netif
811 * Parameters : m -- DHCP message info
812 * len -- DHCP message length
813 * Returns : DHCP message type
814 *******************************************************************************/
parse_msg(struct dhcps_msg * m,u16_t len)815 static s16_t parse_msg(struct dhcps_msg *m, u16_t len)
816 {
817 u32_t lease_timer = (dhcps_lease_time * DHCPS_LEASE_UNIT)/DHCPS_COARSE_TIMER_SECS;
818
819 if (memcmp((char *)m->options, &magic_cookie, sizeof(magic_cookie)) == 0) {
820 #if DHCPS_DEBUG
821 DHCPS_LOG("dhcps: len = %d\n", len);
822 #endif
823 ip4_addr_t addr_tmp;
824
825 struct dhcps_pool *pdhcps_pool = NULL;
826 list_node *pnode = NULL;
827 list_node *pback_node = NULL;
828 ip4_addr_t first_address;
829 bool flag = false;
830
831 first_address.addr = dhcps_poll.start_ip.addr;
832 client_address.addr = client_address_plus.addr;
833 renew = false;
834
835 if (plist != NULL) {
836 for (pback_node = plist; pback_node != NULL; pback_node = pback_node->pnext) {
837 pdhcps_pool = pback_node->pnode;
838
839 if (memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0) {
840 if (memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) {
841 renew = true;
842 }
843
844 client_address.addr = pdhcps_pool->ip.addr;
845 pdhcps_pool->lease_timer = lease_timer;
846 pnode = pback_node;
847 goto POOL_CHECK;
848 } else if (pdhcps_pool->ip.addr == client_address_plus.addr) {
849 addr_tmp.addr = htonl(client_address_plus.addr);
850 addr_tmp.addr++;
851 client_address_plus.addr = htonl(addr_tmp.addr);
852 client_address.addr = client_address_plus.addr;
853 }
854
855 if (flag == false) { // search the fisrt unused ip
856 if (first_address.addr < pdhcps_pool->ip.addr) {
857 flag = true;
858 } else {
859 addr_tmp.addr = htonl(first_address.addr);
860 addr_tmp.addr++;
861 first_address.addr = htonl(addr_tmp.addr);
862 }
863 }
864 }
865 } else {
866 client_address.addr = dhcps_poll.start_ip.addr;
867 }
868
869 if (client_address_plus.addr > dhcps_poll.end_ip.addr) {
870 client_address.addr = first_address.addr;
871 }
872
873 if (client_address.addr > dhcps_poll.end_ip.addr) {
874 client_address_plus.addr = dhcps_poll.start_ip.addr;
875 pdhcps_pool = NULL;
876 pnode = NULL;
877 } else {
878 pdhcps_pool = (struct dhcps_pool *)mem_malloc(sizeof(struct dhcps_pool));
879 memset(pdhcps_pool , 0x00 , sizeof(struct dhcps_pool));
880
881 pdhcps_pool->ip.addr = client_address.addr;
882 memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac));
883 pdhcps_pool->lease_timer = lease_timer;
884 pnode = (list_node *)mem_malloc(sizeof(list_node));
885 memset(pnode , 0x00 , sizeof(list_node));
886
887 pnode->pnode = pdhcps_pool;
888 pnode->pnext = NULL;
889 node_insert_to_list(&plist, pnode);
890
891 if (client_address.addr == dhcps_poll.end_ip.addr) {
892 client_address_plus.addr = dhcps_poll.start_ip.addr;
893 } else {
894 addr_tmp.addr = htonl(client_address.addr);
895 addr_tmp.addr++;
896 client_address_plus.addr = htonl(addr_tmp.addr);
897 }
898 }
899
900 POOL_CHECK:
901
902 if ((client_address.addr > dhcps_poll.end_ip.addr) || (ip4_addr_isany(&client_address))) {
903 if (pnode != NULL) {
904 node_remove_from_list(&plist, pnode);
905 free(pnode);
906 pnode = NULL;
907 }
908
909 if (pdhcps_pool != NULL) {
910 free(pdhcps_pool);
911 pdhcps_pool = NULL;
912 }
913
914 return 4;
915 }
916
917 s16_t ret = parse_options(&m->options[4], len);;
918
919 if (ret == DHCPS_STATE_RELEASE || ret == DHCPS_STATE_NAK) {
920 if (pnode != NULL) {
921 node_remove_from_list(&plist, pnode);
922 free(pnode);
923 pnode = NULL;
924 }
925
926 if (pdhcps_pool != NULL) {
927 free(pdhcps_pool);
928 pdhcps_pool = NULL;
929 }
930
931 memset(&client_address, 0x0, sizeof(client_address));
932 }
933
934 #if DHCPS_DEBUG
935 DHCPS_LOG("dhcps: xid changed\n");
936 DHCPS_LOG("dhcps: client_address.addr = %x\n", client_address.addr);
937 #endif
938 return ret;
939 }
940
941 return 0;
942 }
943
944 /******************************************************************************
945 * FunctionName : handle_dhcp
946 * Description : If an incoming DHCP message is in response to us, then trigger the state machine
947 * Parameters : arg -- arg user supplied argument (udp_pcb.recv_arg)
948 * pcb -- the udp_pcb which received data
949 * p -- the packet buffer that was received
950 * addr -- the remote IP address from which the packet was received
951 * port -- the remote port from which the packet was received
952 * Returns : none
953 *******************************************************************************/
handle_dhcp(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)954 static void handle_dhcp(void *arg,
955 struct udp_pcb *pcb,
956 struct pbuf *p,
957 const ip_addr_t *addr,
958 u16_t port)
959 {
960 struct dhcps_msg *pmsg_dhcps = NULL;
961 s16_t tlen, malloc_len;
962 u16_t i;
963 u16_t dhcps_msg_cnt = 0;
964 u8_t *p_dhcps_msg = NULL;
965 u8_t *data;
966
967 #if DHCPS_DEBUG
968 DHCPS_LOG("dhcps: handle_dhcp-> receive a packet\n");
969 #endif
970
971 if (p == NULL) {
972 return;
973 }
974
975 malloc_len = sizeof(struct dhcps_msg);
976 #if DHCPS_DEBUG
977 DHCPS_LOG("dhcps: handle_dhcp malloc_len=%d rx_len=%d", malloc_len, p->tot_len);
978 #endif
979 if (malloc_len < p->tot_len) {
980 malloc_len = p->tot_len;
981 }
982
983 pmsg_dhcps = (struct dhcps_msg *)mem_malloc(malloc_len);
984 if (NULL == pmsg_dhcps) {
985 pbuf_free(p);
986 return;
987 }
988
989 memset(pmsg_dhcps , 0x00 , malloc_len);
990 p_dhcps_msg = (u8_t *)pmsg_dhcps;
991 tlen = p->tot_len;
992 data = p->payload;
993
994 #if DHCPS_DEBUG
995 DHCPS_LOG("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen);
996 DHCPS_LOG("dhcps: handle_dhcp-> p->len = %d\n", p->len);
997 #endif
998
999 for (i = 0; i < p->len; i++) {
1000 p_dhcps_msg[dhcps_msg_cnt++] = data[i];
1001 #if DHCPS_DEBUG
1002 DHCPS_LOG("%02x ", data[i]);
1003
1004 if ((i + 1) % 16 == 0) {
1005 DHCPS_LOG("\n");
1006 }
1007
1008 #endif
1009 }
1010
1011 if (p->next != NULL) {
1012 #if DHCPS_DEBUG
1013 DHCPS_LOG("dhcps: handle_dhcp-> p->next != NULL\n");
1014 DHCPS_LOG("dhcps: handle_dhcp-> p->next->tot_len = %d\n", p->next->tot_len);
1015 DHCPS_LOG("dhcps: handle_dhcp-> p->next->len = %d\n", p->next->len);
1016 #endif
1017
1018 data = p->next->payload;
1019
1020 for (i = 0; i < p->next->len; i++) {
1021 p_dhcps_msg[dhcps_msg_cnt++] = data[i];
1022 #if DHCPS_DEBUG
1023 DHCPS_LOG("%02x ", data[i]);
1024
1025 if ((i + 1) % 16 == 0) {
1026 DHCPS_LOG("\n");
1027 }
1028
1029 #endif
1030 }
1031 }
1032
1033 #if DHCPS_DEBUG
1034 DHCPS_LOG("dhcps: handle_dhcp-> parse_msg(p)\n");
1035 #endif
1036
1037 switch (parse_msg(pmsg_dhcps, tlen - 240)) {
1038 case DHCPS_STATE_OFFER://1
1039 #if DHCPS_DEBUG
1040 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n");
1041 #endif
1042 send_offer(pmsg_dhcps, malloc_len);
1043 break;
1044
1045 case DHCPS_STATE_ACK://3
1046 #if DHCPS_DEBUG
1047 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n");
1048 #endif
1049 send_ack(pmsg_dhcps, malloc_len);
1050 break;
1051
1052 case DHCPS_STATE_NAK://4
1053 #if DHCPS_DEBUG
1054 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n");
1055 #endif
1056 send_nak(pmsg_dhcps, malloc_len);
1057 break;
1058
1059 default :
1060 break;
1061 }
1062
1063 #if DHCPS_DEBUG
1064 DHCPS_LOG("dhcps: handle_dhcp-> pbuf_free(p)\n");
1065 #endif
1066 pbuf_free(p);
1067 free(pmsg_dhcps);
1068 pmsg_dhcps = NULL;
1069 }
1070
1071 /******************************************************************************
1072 * FunctionName : dhcps_poll_set
1073 * Description : set ip poll from start to end for station
1074 * Parameters : ip -- The current ip addr
1075 * Returns : none
1076 *******************************************************************************/
dhcps_poll_set(u32_t ip)1077 static void dhcps_poll_set(u32_t ip)
1078 {
1079 u32_t softap_ip = 0, local_ip = 0;
1080 u32_t start_ip = 0;
1081 u32_t end_ip = 0;
1082
1083 if (dhcps_poll.enable == true) {
1084 softap_ip = htonl(ip);
1085 start_ip = htonl(dhcps_poll.start_ip.addr);
1086 end_ip = htonl(dhcps_poll.end_ip.addr);
1087
1088 /*config ip information can't contain local ip*/
1089 if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) {
1090 dhcps_poll.enable = false;
1091 } else {
1092 /*config ip information must be in the same segment as the local ip*/
1093 softap_ip >>= 8;
1094
1095 if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip))
1096 || (end_ip - start_ip > DHCPS_MAX_LEASE)) {
1097 dhcps_poll.enable = false;
1098 }
1099 }
1100 }
1101
1102 if (dhcps_poll.enable == false) {
1103 local_ip = softap_ip = htonl(ip);
1104 softap_ip &= 0xFFFFFF00;
1105 local_ip &= 0xFF;
1106
1107 if (local_ip >= 0x80) {
1108 local_ip -= DHCPS_MAX_LEASE;
1109 } else {
1110 local_ip ++;
1111 }
1112
1113 bzero(&dhcps_poll, sizeof(dhcps_poll));
1114 dhcps_poll.start_ip.addr = softap_ip | local_ip;
1115 dhcps_poll.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1);
1116 dhcps_poll.start_ip.addr = htonl(dhcps_poll.start_ip.addr);
1117 dhcps_poll.end_ip.addr = htonl(dhcps_poll.end_ip.addr);
1118 }
1119
1120 }
1121
1122
1123 /******************************************************************************
1124 * FunctionName : dhcps_set_new_lease_cb
1125 * Description : set callback for dhcp server when it assign an IP
1126 * to the connected dhcp client
1127 * Parameters : cb -- callback for dhcp server
1128 * Returns : none
1129 *******************************************************************************/
dhcps_set_new_lease_cb(dhcps_cb_t cb)1130 void dhcps_set_new_lease_cb(dhcps_cb_t cb)
1131 {
1132 dhcps_cb = cb;
1133 }
1134
1135 /******************************************************************************
1136 * FunctionName : dhcps_start
1137 * Description : start dhcp server function
1138 * Parameters : netif -- The current netif addr
1139 * : info -- The current ip info
1140 * Returns : none
1141 *******************************************************************************/
dhcps_start(struct netif * netif,ip4_addr_t ip)1142 void dhcps_start(struct netif *netif, ip4_addr_t ip)
1143 {
1144 dhcps_netif = netif;
1145
1146 if (dhcps_netif->dhcps_pcb != NULL) {
1147 udp_remove(dhcps_netif->dhcps_pcb);
1148 }
1149
1150 dhcps_netif->dhcps_pcb = udp_new();
1151 struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb;
1152
1153 if (pcb_dhcps == NULL || ip4_addr_isany_val(ip)) {
1154 printf("dhcps_start(): could not obtain pcb\n");
1155 }
1156
1157 dhcps_netif->dhcps_pcb = pcb_dhcps;
1158
1159 IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255);
1160
1161 server_address.addr = ip.addr;
1162 dhcps_poll_set(server_address.addr);
1163
1164 client_address_plus.addr = dhcps_poll.start_ip.addr;
1165
1166 udp_bind(pcb_dhcps, &netif->ip_addr, DHCPS_SERVER_PORT);
1167 udp_recv(pcb_dhcps, handle_dhcp, NULL);
1168 #if DHCPS_DEBUG
1169 DHCPS_LOG("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n");
1170 #endif
1171
1172 }
1173
1174 /******************************************************************************
1175 * FunctionName : dhcps_stop
1176 * Description : stop dhcp server function
1177 * Parameters : netif -- The current netif addr
1178 * Returns : none
1179 *******************************************************************************/
dhcps_stop(struct netif * netif)1180 void dhcps_stop(struct netif *netif)
1181 {
1182 struct netif *apnetif = netif;
1183
1184 if (apnetif == NULL) {
1185 printf("dhcps_stop: apnetif == NULL\n");
1186 return;
1187 }
1188
1189 if (apnetif->dhcps_pcb != NULL) {
1190 udp_disconnect(apnetif->dhcps_pcb);
1191 udp_remove(apnetif->dhcps_pcb);
1192 apnetif->dhcps_pcb = NULL;
1193 }
1194
1195 list_node *pnode = NULL;
1196 list_node *pback_node = NULL;
1197 pnode = plist;
1198
1199 while (pnode != NULL) {
1200 pback_node = pnode;
1201 pnode = pback_node->pnext;
1202 node_remove_from_list(&plist, pback_node);
1203 free(pback_node->pnode);
1204 pback_node->pnode = NULL;
1205 free(pback_node);
1206 pback_node = NULL;
1207 }
1208 }
1209
1210 /******************************************************************************
1211 * FunctionName : kill_oldest_dhcps_pool
1212 * Description : remove the oldest node from list
1213 * Parameters : none
1214 * Returns : none
1215 *******************************************************************************/
kill_oldest_dhcps_pool(void)1216 static void kill_oldest_dhcps_pool(void)
1217 {
1218 list_node *pre = NULL, *p = NULL;
1219 list_node *minpre = NULL, *minp = NULL;
1220 struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL;
1221 pre = plist;
1222 assert(pre != NULL && pre->pnext != NULL); // Expect the list to have at least 2 nodes
1223 p = pre->pnext;
1224 minpre = pre;
1225 minp = p;
1226
1227 while (p != NULL) {
1228 pdhcps_pool = p->pnode;
1229 pmin_pool = minp->pnode;
1230
1231 if (pdhcps_pool->lease_timer < pmin_pool->lease_timer) {
1232 minp = p;
1233 minpre = pre;
1234 }
1235
1236 pre = p;
1237 p = p->pnext;
1238 }
1239
1240 minpre->pnext = minp->pnext;
1241 free(minp->pnode);
1242 minp->pnode = NULL;
1243 free(minp);
1244 minp = NULL;
1245 }
1246
1247 /******************************************************************************
1248 * FunctionName : dhcps_coarse_tmr
1249 * Description : the lease time count
1250 * Parameters : none
1251 * Returns : none
1252 *******************************************************************************/
dhcps_coarse_tmr(void)1253 void dhcps_coarse_tmr(void)
1254 {
1255 u8_t num_dhcps_pool = 0;
1256 list_node *pback_node = NULL;
1257 list_node *pnode = NULL;
1258 struct dhcps_pool *pdhcps_pool = NULL;
1259 pnode = plist;
1260
1261 while (pnode != NULL) {
1262 pdhcps_pool = pnode->pnode;
1263 pdhcps_pool->lease_timer --;
1264
1265 if (pdhcps_pool->lease_timer == 0) {
1266 pback_node = pnode;
1267 pnode = pback_node->pnext;
1268 node_remove_from_list(&plist, pback_node);
1269 free(pback_node->pnode);
1270 pback_node->pnode = NULL;
1271 free(pback_node);
1272 pback_node = NULL;
1273 } else {
1274 pnode = pnode ->pnext;
1275 num_dhcps_pool ++;
1276 }
1277 }
1278
1279 if (num_dhcps_pool > MAX_STATION_NUM) {
1280 kill_oldest_dhcps_pool();
1281 }
1282 }
1283
1284 /******************************************************************************
1285 * FunctionName : dhcp_search_ip_on_mac
1286 * Description : Search ip address based on mac address
1287 * Parameters : mac -- The MAC addr
1288 * ip -- The IP info
1289 * Returns : true or false
1290 *******************************************************************************/
dhcp_search_ip_on_mac(u8_t * mac,ip4_addr_t * ip)1291 bool dhcp_search_ip_on_mac(u8_t *mac, ip4_addr_t *ip)
1292 {
1293 struct dhcps_pool *pdhcps_pool = NULL;
1294 list_node *pback_node = NULL;
1295 bool ret = false;
1296
1297 for (pback_node = plist; pback_node != NULL; pback_node = pback_node->pnext) {
1298 pdhcps_pool = pback_node->pnode;
1299
1300 if (memcmp(pdhcps_pool->mac, mac, sizeof(pdhcps_pool->mac)) == 0) {
1301 memcpy(&ip->addr, &pdhcps_pool->ip.addr, sizeof(pdhcps_pool->ip.addr));
1302 ret = true;
1303 break;
1304 }
1305 }
1306
1307 return ret;
1308 }
1309
1310 /******************************************************************************
1311 * FunctionName : dhcps_dns_setserver
1312 * Description : set DNS server address for dhcpserver
1313 * Parameters : dnsserver -- The DNS server address
1314 * Returns : none
1315 *******************************************************************************/
1316 void
dhcps_dns_setserver(const ip_addr_t * dnsserver)1317 dhcps_dns_setserver(const ip_addr_t *dnsserver)
1318 {
1319 if (dnsserver != NULL) {
1320 dns_server = *(ip_2_ip4(dnsserver));
1321 } else {
1322 dns_server = *(ip_2_ip4(IP_ADDR_ANY));
1323 }
1324 }
1325
1326 /******************************************************************************
1327 * FunctionName : dhcps_dns_getserver
1328 * Description : get DNS server address for dhcpserver
1329 * Parameters : none
1330 * Returns : ip4_addr_t
1331 *******************************************************************************/
1332 ip4_addr_t
dhcps_dns_getserver(void)1333 dhcps_dns_getserver(void)
1334 {
1335 return dns_server;
1336 }
1337 #endif // ESP_DHCP
1338