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