]> granicus.if.org Git - esp-idf/blob - components/lwip/apps/dhcpserver.c
Initial public version
[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 "apps/dhcpserver.h"
24
25 #include "tcpip_adapter.h"
26
27 #ifdef LWIP_ESP8266
28
29 enum dyc_dhcps_flags{
30         DHCPS_STARTED = 0x00,
31         DHCPS_STOP = 0x01,
32         _END
33 } DhcpsFlags = DHCPS_STOP;
34
35 #define DHCPS_MAX_LEASE 0x64
36 #define BOOTP_BROADCAST 0x8000
37
38 #define DHCP_REQUEST        1
39 #define DHCP_REPLY          2
40 #define DHCP_HTYPE_ETHERNET 1
41 #define DHCP_HLEN_ETHERNET  6
42 #define DHCP_MSG_LEN      236
43
44 #define DHCPS_SERVER_PORT  67
45 #define DHCPS_CLIENT_PORT  68
46
47 #define DHCPDISCOVER  1
48 #define DHCPOFFER     2
49 #define DHCPREQUEST   3
50 #define DHCPDECLINE   4
51 #define DHCPACK       5
52 #define DHCPNAK       6
53 #define DHCPRELEASE   7
54
55 #define DHCP_OPTION_SUBNET_MASK   1
56 #define DHCP_OPTION_ROUTER        3
57 #define DHCP_OPTION_DNS_SERVER    6
58 #define DHCP_OPTION_REQ_IPADDR   50
59 #define DHCP_OPTION_LEASE_TIME   51
60 #define DHCP_OPTION_MSG_TYPE     53
61 #define DHCP_OPTION_SERVER_ID    54
62 #define DHCP_OPTION_INTERFACE_MTU 26
63 #define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31
64 #define DHCP_OPTION_BROADCAST_ADDRESS 28
65 #define DHCP_OPTION_REQ_LIST     55
66 #define DHCP_OPTION_END         255
67
68 //#define USE_CLASS_B_NET 1
69 #define DHCPS_DEBUG          0
70 #define DHCPS_LOG printf
71
72 #define DYC_DHCP_CRASH //os_printf
73
74
75 #define MAX_STATION_NUM      8
76
77 #define DHCPS_STATE_OFFER 1
78 #define DHCPS_STATE_DECLINE 2
79 #define DHCPS_STATE_ACK 3
80 #define DHCPS_STATE_NAK 4
81 #define DHCPS_STATE_IDLE 5
82 #define DHCPS_STATE_RELEASE 6
83
84
85
86 #ifdef MEMLEAK_DEBUG
87 static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
88 #endif
89
90 ////////////////////////////////////////////////////////////////////////////////////
91 //static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
92 //static u8_t old_xid[4] = {0};
93 static const u32_t magic_cookie  = 0x63538263;
94 //static const u32_t magic_cookie = 0x63538263;
95 //static const char magic_cookie[] = {0x63,0x82,0x53,0x63};
96 //static const u32_t magic_cookie = 0x63538263;
97 //static const u32_t magic_cookie_temp  = 0x63538263;
98
99 /*
100 ip_2_ip4(ipaddr)
101 IP_IS_V6(dest)
102 IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4)    
103 */
104
105
106 static struct udp_pcb *pcb_dhcps = NULL;
107 static ip4_addr_t  broadcast_dhcps;
108 static ip4_addr_t server_address;
109 static ip4_addr_t client_address;        //added
110 static ip4_addr_t client_address_plus;
111
112 static struct dhcps_lease dhcps_lease;
113 //static bool dhcps_lease_flag = true;
114 static list_node *plist = NULL;
115 static u8_t offer = 0xFF;
116 static bool renew = false;
117 #define DHCPS_LEASE_TIME_DEF    (120)
118 u32_t dhcps_lease_time = DHCPS_LEASE_TIME_DEF;  //minute
119
120
121
122 static enum dyc_dhcps_flags get_dhcps_status(void )
123 {
124     return DhcpsFlags;
125 }
126 /******************************************************************************
127  * FunctionName : node_insert_to_list
128  * Description  : insert the node to the list
129  * Parameters   : arg -- Additional argument to pass to the callback function
130  * Returns      : none
131 *******************************************************************************/
132 void node_insert_to_list(list_node **phead, list_node* pinsert)
133 {
134         list_node *plist = NULL;
135         struct dhcps_pool *pdhcps_pool = NULL;
136         struct dhcps_pool *pdhcps_node = NULL;
137         if (*phead == NULL)
138                 *phead = pinsert;
139         else {
140                 plist = *phead;
141                 pdhcps_node = pinsert->pnode;
142                 pdhcps_pool = plist->pnode;
143
144                 if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
145                     pinsert->pnext = plist;
146                     *phead = pinsert;
147                 } else {
148             while (plist->pnext != NULL) {
149                 pdhcps_pool = plist->pnext->pnode;
150                 if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
151                     pinsert->pnext = plist->pnext;
152                     plist->pnext = pinsert;
153                     break;
154                 }
155                 plist = plist->pnext;
156             }
157
158             if(plist->pnext == NULL) {
159                 plist->pnext = pinsert;
160             }
161                 }
162         }
163 //      pinsert->pnext = NULL;
164 }
165
166 /******************************************************************************
167  * FunctionName : node_delete_from_list
168  * Description  : remove the node from list
169  * Parameters   : arg -- Additional argument to pass to the callback function
170  * Returns      : none
171 *******************************************************************************/
172 void node_remove_from_list(list_node **phead, list_node* pdelete)
173 {
174         list_node *plist = NULL;
175
176         plist = *phead;
177         if (plist == NULL){
178                 *phead = NULL;
179         } else {
180                 if (plist == pdelete){
181                         *phead = plist->pnext;
182                         pdelete->pnext = NULL;
183                 } else {
184                         while (plist != NULL) {
185                                 if (plist->pnext == pdelete){
186                                         plist->pnext = pdelete->pnext;
187                                         pdelete->pnext = NULL;
188                                 }
189                                 plist = plist->pnext;
190                         }
191                 }
192         }
193 }
194 ///////////////////////////////////////////////////////////////////////////////////
195 /*
196  * ��DHCP msg��Ϣ�ṹ����������
197  *
198  * @param optptr -- DHCP msg��Ϣλ��
199  * @param type -- Ҫ��ӵ�����option
200  *
201  * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
202  */
203 ///////////////////////////////////////////////////////////////////////////////////
204 static u8_t* add_msg_type(u8_t *optptr, u8_t type)
205 {
206         *optptr++ = DHCP_OPTION_MSG_TYPE;
207         *optptr++ = 1;
208         *optptr++ = type;
209         return optptr;
210 }
211 ///////////////////////////////////////////////////////////////////////////////////
212 /*
213  * ��DHCP msg�ṹ������offerӦ������
214  *
215  * @param optptr -- DHCP msg��Ϣλ��
216  *
217  * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
218  */
219 ///////////////////////////////////////////////////////////////////////////////////
220 static u8_t* add_offer_options(u8_t *optptr)
221 {
222         ip4_addr_t ipadd;
223
224         ipadd.addr = *( (u32_t *) &server_address);
225
226 #ifdef USE_CLASS_B_NET
227         *optptr++ = DHCP_OPTION_SUBNET_MASK;
228         *optptr++ = 4;  //length
229         *optptr++ = 255;
230         *optptr++ = 240;        
231         *optptr++ = 0;
232         *optptr++ = 0;
233 #else
234         *optptr++ = DHCP_OPTION_SUBNET_MASK;
235         *optptr++ = 4;  
236         *optptr++ = 255;
237         *optptr++ = 255;        
238         *optptr++ = 255;
239         *optptr++ = 0;
240 #endif
241
242         *optptr++ = DHCP_OPTION_LEASE_TIME;
243         *optptr++ = 4;  
244         *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF;
245         *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF;
246         *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF;
247         *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF;
248
249         *optptr++ = DHCP_OPTION_SERVER_ID;
250         *optptr++ = 4;  
251         *optptr++ = ip4_addr1( &ipadd);
252         *optptr++ = ip4_addr2( &ipadd);
253         *optptr++ = ip4_addr3( &ipadd);
254         *optptr++ = ip4_addr4( &ipadd);
255
256         if (dhcps_router_enabled(offer)){
257                 struct ip_info if_ip;
258                 //bzero(&if_ip, sizeof(struct ip_info));
259               memset(&if_ip ,0x00, sizeof(struct ip_info));
260         
261                 tcpip_adapter_get_ip_info(WIFI_IF_AP, &if_ip);
262
263                 *optptr++ = DHCP_OPTION_ROUTER;
264                 *optptr++ = 4;
265                 *optptr++ = ip4_addr1( &if_ip.gw);
266                 *optptr++ = ip4_addr2( &if_ip.gw);
267                 *optptr++ = ip4_addr3( &if_ip.gw);
268                 *optptr++ = ip4_addr4( &if_ip.gw);
269         }
270
271 #ifdef USE_DNS
272             *optptr++ = DHCP_OPTION_DNS_SERVER;
273             *optptr++ = 4;
274             *optptr++ = ip4_addr1( &ipadd);
275                 *optptr++ = ip4_addr2( &ipadd);
276                 *optptr++ = ip4_addr3( &ipadd);
277                 *optptr++ = ip4_addr4( &ipadd);
278 #endif
279
280 #ifdef CLASS_B_NET
281         *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
282         *optptr++ = 4;  
283         *optptr++ = ip4_addr1( &ipadd);
284         *optptr++ = 255;
285         *optptr++ = 255;
286         *optptr++ = 255;
287 #else
288         *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
289         *optptr++ = 4;  
290         *optptr++ = ip4_addr1( &ipadd);
291         *optptr++ = ip4_addr2( &ipadd);
292         *optptr++ = ip4_addr3( &ipadd);
293         *optptr++ = 255;
294 #endif
295
296         *optptr++ = DHCP_OPTION_INTERFACE_MTU;
297         *optptr++ = 2;  
298 #ifdef CLASS_B_NET
299         *optptr++ = 0x05;       
300         *optptr++ = 0xdc;
301 #else
302         *optptr++ = 0x02;       
303         *optptr++ = 0x40;
304 #endif
305
306         *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;
307         *optptr++ = 1;  
308         *optptr++ = 0x00; 
309
310         *optptr++ = 43; 
311         *optptr++ = 6;  
312
313         *optptr++ = 0x01;       
314         *optptr++ = 4;  
315         *optptr++ = 0x00;
316         *optptr++ = 0x00;
317         *optptr++ = 0x00;
318         *optptr++ = 0x02;       
319
320         return optptr;
321 }
322 ///////////////////////////////////////////////////////////////////////////////////
323 /*
324  * ��DHCP msg�ṹ����ӽ����־����
325  *
326  * @param optptr -- DHCP msg��Ϣλ��
327  *
328  * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
329  */
330 ///////////////////////////////////////////////////////////////////////////////////
331 static u8_t* add_end(u8_t *optptr)
332 {
333
334         *optptr++ = DHCP_OPTION_END;
335         return optptr;
336 }
337 ///////////////////////////////////////////////////////////////////////////////////
338 ///////////////////////////////////////////////////////////////////////////////////
339 static void create_msg(struct dhcps_msg *m)
340 {
341         ip4_addr_t client;
342
343
344         client.addr = *( (uint32_t *) &client_address);
345
346         m->op = DHCP_REPLY;
347
348         m->htype = DHCP_HTYPE_ETHERNET;
349
350         m->hlen = 6;  
351
352         m->hops = 0;
353 //        os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid));
354         m->secs = 0;
355         m->flags = htons(BOOTP_BROADCAST); 
356
357         memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr));
358
359         memset((char *) m->ciaddr, 0, sizeof(m->ciaddr));
360
361         memset((char *) m->siaddr, 0, sizeof(m->siaddr));
362
363         memset((char *) m->giaddr, 0, sizeof(m->giaddr));
364
365         memset((char *) m->sname, 0, sizeof(m->sname));
366
367         memset((char *) m->file, 0, sizeof(m->file));
368
369         memset((char *) m->options, 0, sizeof(m->options));
370         
371 //        u32_t temp  = 0x63538263;
372  //       u8 *log_temp = (u8 *)&temp;
373 //DYC_DHCP_CRASH("l:%0x,%0x,%0x,%0x,",log_temp[0],log_temp[1],log_temp[2],log_temp[3]);
374
375 u32_t magic_cookie_temp = magic_cookie;
376
377 //extern bool system_get_string_from_flash(void *flash_str, void* ram_str,uint8 ram_str_len);
378 //system_get_string_from_flash((void *)(&magic_cookie), (void *)(&magic_cookie_temp),4);
379 //os_printf("ck_tmp3:%08X\n",magic_cookie_temp);
380
381         //memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie));
382         memcpy((char *) m->options, &magic_cookie_temp, sizeof(magic_cookie_temp));
383 //        DYC_DHCP_CRASH("m,");
384 }
385 ///////////////////////////////////////////////////////////////////////////////////
386 /*
387  * ����һ��OFFER
388  *
389  * @param -- m ָ����Ҫ���͵�DHCP msg����
390  */
391 ///////////////////////////////////////////////////////////////////////////////////
392 static void send_offer(struct dhcps_msg *m)
393 {
394         u8_t *end;
395             struct pbuf *p, *q;
396             u8_t *data;
397             u16_t cnt=0;
398             u16_t i;
399                 err_t SendOffer_err_t;
400         create_msg(m);
401
402         end = add_msg_type(&m->options[4], DHCPOFFER);
403         end = add_offer_options(end);
404         end = add_end(end);
405
406             p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
407 #if DHCPS_DEBUG
408                 DHCPS_LOG("udhcp: send_offer>>p->ref = %d\n", p->ref);
409 #endif
410             if(p != NULL){
411                
412 #if DHCPS_DEBUG
413                 DHCPS_LOG("dhcps: send_offer>>pbuf_alloc succeed\n");
414                 DHCPS_LOG("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len);
415                 DHCPS_LOG("dhcps: send_offer>>p->len = %d\n", p->len);
416 #endif
417                 q = p;
418                 while(q != NULL){
419                     data = (u8_t *)q->payload;
420                     for(i=0; i<q->len; i++)
421                     {
422                         data[i] = ((u8_t *) m)[cnt++];
423 #if DHCPS_DEBUG
424                                         DHCPS_LOG("%02x ",data[i]);
425                                         if((i+1)%16 == 0){
426                                                 DHCPS_LOG("\n");
427                                         }
428 #endif
429                     }
430
431                     q = q->next;
432                 }
433             }else{
434                 
435 #if DHCPS_DEBUG
436                 DHCPS_LOG("dhcps: send_offer>>pbuf_alloc failed\n");
437 #endif
438                 return;
439             }
440         
441         ip_addr_t ip_temp = IPADDR4_INIT(0x0);
442         ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
443                 SendOffer_err_t = udp_sendto( pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT );
444 #if DHCPS_DEBUG
445                 DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n",SendOffer_err_t);
446 #endif
447             if(p->ref != 0){    
448 #if DHCPS_DEBUG
449                 DHCPS_LOG("udhcp: send_offer>>free pbuf\n");
450 #endif
451                 pbuf_free(p);
452             }
453 }
454 ///////////////////////////////////////////////////////////////////////////////////
455 /*
456  * ����һ��NAK��Ϣ
457  *
458  * @param m ָ����Ҫ���͵�DHCP msg����
459  */
460 ///////////////////////////////////////////////////////////////////////////////////
461 static void send_nak(struct dhcps_msg *m)
462 {
463         u8_t *end;
464         struct pbuf *p, *q;
465         u8_t *data;
466         u16_t cnt=0;
467         u16_t i;
468         err_t SendNak_err_t;
469         create_msg(m);
470
471         end = add_msg_type(&m->options[4], DHCPNAK);
472         end = add_end(end);
473
474             p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
475 #if DHCPS_DEBUG
476                 DHCPS_LOG("udhcp: send_nak>>p->ref = %d\n", p->ref);
477 #endif
478             if(p != NULL){
479                 
480 #if DHCPS_DEBUG
481                 DHCPS_LOG("dhcps: send_nak>>pbuf_alloc succeed\n");
482                 DHCPS_LOG("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len);
483                 DHCPS_LOG("dhcps: send_nak>>p->len = %d\n", p->len);
484 #endif
485                 q = p;
486                 while(q != NULL){
487                     data = (u8_t *)q->payload;
488                     for(i=0; i<q->len; i++)
489                     {
490                         data[i] = ((u8_t *) m)[cnt++];
491 #if DHCPS_DEBUG                                 
492                                         DHCPS_LOG("%02x ",data[i]);
493                                         if((i+1)%16 == 0){
494                                                 DHCPS_LOG("\n");
495                                         }
496 #endif
497                     }
498
499                     q = q->next;
500                 }
501             }else{
502                 
503 #if DHCPS_DEBUG
504                 DHCPS_LOG("dhcps: send_nak>>pbuf_alloc failed\n");
505 #endif
506                 return;
507         }
508
509         ip_addr_t ip_temp = IPADDR4_INIT(0x0);
510         ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);       
511         SendNak_err_t = udp_sendto( pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT );
512 #if DHCPS_DEBUG
513                 DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n",SendNak_err_t);
514 #endif
515             if(p->ref != 0){
516 #if DHCPS_DEBUG                 
517                 DHCPS_LOG("udhcp: send_nak>>free pbuf\n");
518 #endif
519                 pbuf_free(p);
520             }
521 }
522 ///////////////////////////////////////////////////////////////////////////////////
523 /*
524  * ����һ��ACK��DHCP�ͻ���
525  *
526  * @param m ָ����Ҫ���͵�DHCP msg����
527  */
528 ///////////////////////////////////////////////////////////////////////////////////
529 static void send_ack(struct dhcps_msg *m)
530 {
531         u8_t *end;
532         struct pbuf *p, *q;
533         u8_t *data;
534         u16_t cnt=0;
535         u16_t i;
536         err_t SendAck_err_t;
537         create_msg(m);
538
539         end = add_msg_type(&m->options[4], DHCPACK);
540         end = add_offer_options(end);
541         end = add_end(end);
542             
543             p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
544 #if DHCPS_DEBUG
545                 DHCPS_LOG("udhcp: send_ack>>p->ref = %d\n", p->ref);
546 #endif
547             if(p != NULL){
548                 
549 #if DHCPS_DEBUG
550                 DHCPS_LOG("dhcps: send_ack>>pbuf_alloc succeed\n");
551                 DHCPS_LOG("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len);
552                 DHCPS_LOG("dhcps: send_ack>>p->len = %d\n", p->len);
553 #endif
554                 q = p;
555                 while(q != NULL){
556                     data = (u8_t *)q->payload;
557                     for(i=0; i<q->len; i++)
558                     {
559                         data[i] = ((u8_t *) m)[cnt++];
560 #if DHCPS_DEBUG                                 
561                                         DHCPS_LOG("%02x ",data[i]);
562                                         if((i+1)%16 == 0){
563                                                 DHCPS_LOG("\n");
564                                         }
565 #endif
566                     }
567
568                     q = q->next;
569                 }
570             }else{
571             
572 #if DHCPS_DEBUG
573                 DHCPS_LOG("dhcps: send_ack>>pbuf_alloc failed\n");
574 #endif
575                 return;
576             }
577
578         ip_addr_t ip_temp = IPADDR4_INIT(0x0);
579         ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);   
580         SendAck_err_t = udp_sendto( pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT );
581 #if DHCPS_DEBUG
582                 DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t);
583 #endif
584             
585             if(p->ref != 0){
586 #if DHCPS_DEBUG
587                 DHCPS_LOG("udhcp: send_ack>>free pbuf\n");
588 #endif
589                 pbuf_free(p);
590             }
591 }
592 ///////////////////////////////////////////////////////////////////////////////////
593 /*
594  * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ��
595  *
596  * @param optptr DHCP msg�е���������
597  * @param len ��������Ĵ��?(byte)
598  *
599  * @return uint8_t ���ش�����DHCP Server״ֵ̬
600  */
601 ///////////////////////////////////////////////////////////////////////////////////
602 static u8_t parse_options(u8_t *optptr, s16_t len)
603 {
604        ip4_addr_t client;
605         bool is_dhcp_parse_end = false;
606         struct dhcps_state s;
607
608         client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP
609
610         u8_t *end = optptr + len;
611         u16_t type = 0;
612
613         s.state = DHCPS_STATE_IDLE;
614
615         while (optptr < end) {
616 #if DHCPS_DEBUG
617                 DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr);
618 #endif
619                 switch ((s16_t) *optptr) {
620
621                 case DHCP_OPTION_MSG_TYPE:      //53
622                         type = *(optptr + 2);
623                         break;
624
625                 case DHCP_OPTION_REQ_IPADDR://50
626                         if( memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) {
627 #if DHCPS_DEBUG
628                                 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n");
629 #endif
630                             s.state = DHCPS_STATE_ACK;
631                         }else {
632 #if DHCPS_DEBUG
633                                 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n");
634 #endif
635                             s.state = DHCPS_STATE_NAK;
636                         }
637                         break;
638                 case DHCP_OPTION_END:
639                                     {
640                                         is_dhcp_parse_end = true;
641                                     }
642                         break;
643             }
644
645                     if(is_dhcp_parse_end){
646                             break;
647                     }
648
649             optptr += optptr[1] + 2;
650         }
651
652         switch (type){
653         
654                 case DHCPDISCOVER://1
655                 s.state = DHCPS_STATE_OFFER;
656 #if DHCPS_DEBUG
657                 DHCPS_LOG("dhcps: DHCPD_STATE_OFFER\n");
658 #endif
659                 break;
660
661                 case DHCPREQUEST://3
662                 if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) {
663                     if(renew == true) {
664                         s.state = DHCPS_STATE_ACK;
665                     } else {
666                         s.state = DHCPS_STATE_NAK;
667                     }
668 #if DHCPS_DEBUG
669                                 DHCPS_LOG("dhcps: DHCPD_STATE_NAK\n");
670 #endif
671                 }
672                 break;
673
674                         case DHCPDECLINE://4
675                 s.state = DHCPS_STATE_IDLE;
676 #if DHCPS_DEBUG
677                 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
678 #endif
679                 break;
680
681                 case DHCPRELEASE://7
682                 s.state = DHCPS_STATE_RELEASE;
683 #if DHCPS_DEBUG
684                 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
685 #endif
686                 break;
687         }
688 #if DHCPS_DEBUG
689         DHCPS_LOG("dhcps: return s.state = %d\n", s.state);
690 #endif
691         return s.state;
692 }
693 ///////////////////////////////////////////////////////////////////////////////////
694 ///////////////////////////////////////////////////////////////////////////////////
695 static s16_t parse_msg(struct dhcps_msg *m, u16_t len)
696 {
697
698 //u32 magic_cookie_temp = magic_cookie;
699 //extern bool system_get_string_from_flash(void *flash_str, void* ram_str,uint8 ram_str_len);
700 //system_get_string_from_flash((void *)(&magic_cookie), (void *)(&magic_cookie_temp),4);
701 //os_printf("ck_tmp4:%08X\n",magic_cookie_temp);
702
703                 if(memcmp((char *)m->options,
704                     &magic_cookie,
705                     sizeof(magic_cookie)) == 0){
706 #if DHCPS_DEBUG
707                         DHCPS_LOG("dhcps: len = %d\n", len);
708 #endif
709
710                       ip4_addr_t addr_tmp;    
711 //                      memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid));
712
713                         struct dhcps_pool *pdhcps_pool = NULL;
714                         list_node *pnode = NULL;
715                         list_node *pback_node = NULL;
716                         ip4_addr_t first_address;
717                         bool flag = false;
718
719 //                                              POOL_START:
720                         first_address.addr = dhcps_lease.start_ip.addr;
721                         client_address.addr = client_address_plus.addr;
722                         renew = false;
723 //                                                      addr_tmp.addr =  htonl(client_address_plus.addr);
724 //                                                      addr_tmp.addr++;
725 //                                                      client_address_plus.addr = htonl(addr_tmp.addr);
726                         for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) {
727                                 pdhcps_pool = pback_node->pnode;
728                                 if (memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0){
729 //                                                                      os_printf("the same device request ip\n");
730                                         if (memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) {
731                                             renew = true;
732                                         }
733                                         client_address.addr = pdhcps_pool->ip.addr;
734                                         pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER;
735                                         pnode = pback_node;
736                                         goto POOL_CHECK;
737                                 } else if (pdhcps_pool->ip.addr == client_address_plus.addr){
738 //                                                                      client_address.addr = client_address_plus.addr;
739 //                                                                      os_printf("the ip addr has been request\n");
740                                         addr_tmp.addr = htonl(client_address_plus.addr);
741                                         addr_tmp.addr++;
742                                         client_address_plus.addr = htonl(addr_tmp.addr);
743                                         client_address.addr = client_address_plus.addr;
744                                 }
745
746                                 if(flag == false) { // search the fisrt unused ip
747                                     if(first_address.addr < pdhcps_pool->ip.addr) {
748                                         flag = true;
749                                     } else {
750                                         addr_tmp.addr = htonl(first_address.addr);
751                                         addr_tmp.addr++;
752                                         first_address.addr = htonl(addr_tmp.addr);
753                                     }
754                                 }
755                         }
756                         if (client_address_plus.addr > dhcps_lease.end_ip.addr) {
757                             client_address.addr = first_address.addr;
758                         }
759                         if (client_address.addr > dhcps_lease.end_ip.addr) {
760                             client_address_plus.addr = dhcps_lease.start_ip.addr;
761                             pdhcps_pool = NULL;
762                             pnode = NULL;
763                         } else {
764                                 pdhcps_pool = (struct dhcps_pool *)malloc(sizeof(struct dhcps_pool));
765                             memset(pdhcps_pool ,0x00 ,sizeof(struct dhcps_pool));
766                     
767                                 pdhcps_pool->ip.addr = client_address.addr;
768                                 memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac));
769                                 pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER;
770                                 pnode = (list_node *)malloc(sizeof(list_node ));
771                             memset(pnode ,0x00 ,sizeof(list_node));
772                     
773                                 pnode->pnode = pdhcps_pool;
774                             pnode->pnext = NULL;
775                             node_insert_to_list(&plist,pnode);
776                             if (client_address.addr == dhcps_lease.end_ip.addr) {
777                                     client_address_plus.addr = dhcps_lease.start_ip.addr;
778                             } else {
779                                     addr_tmp.addr = htonl(client_address.addr);
780                                     addr_tmp.addr++;
781                                     client_address_plus.addr = htonl(addr_tmp.addr);
782                             }
783                         }
784
785                         POOL_CHECK:
786                         if ((client_address.addr > dhcps_lease.end_ip.addr) || (ip4_addr_isany(&client_address))){
787                             if(pnode != NULL) {
788                                 node_remove_from_list(&plist,pnode);
789                                 free(pnode);
790                                 pnode = NULL;
791                             }
792
793                             if (pdhcps_pool != NULL) {
794                                 free(pdhcps_pool);
795                                 pdhcps_pool = NULL;
796                             }
797 // client_address_plus.addr = dhcps_lease.start_ip.addr;
798                                 return 4;
799                         }
800
801                         s16_t ret = parse_options(&m->options[4], len);;
802
803                         if(ret == DHCPS_STATE_RELEASE) {
804                             if(pnode != NULL) {
805                                 node_remove_from_list(&plist,pnode);
806                                 free(pnode);
807                                 pnode = NULL;
808                             }
809
810                             if (pdhcps_pool != NULL) {
811                                 free(pdhcps_pool);
812                                 pdhcps_pool = NULL;
813                             }
814                             memset(&client_address,0x0,sizeof(client_address));
815                         }
816
817 //TO_DO ,  set (ap-> sta)   ip_addr   no use.
818 //if ( tcpip_dep_set_ip_info(STATION_IF, struct ip_info *if_ip) == false )
819     //return 0;
820 //if (wifi_softap_set_station_info(m->chaddr, &client_address) == false) {
821    // return 0;
822
823 #if DHCPS_DEBUG
824                         DHCPS_LOG("dhcps: xid changed\n");
825                         DHCPS_LOG("dhcps: client_address.addr = %x\n", client_address.addr);
826 #endif
827                 return ret;
828             }
829         return 0;
830 }
831
832
833 static void handle_dhcp(void *arg,
834                                         struct udp_pcb *pcb, 
835                                         struct pbuf *p,  
836                                         const ip_addr_t *addr,
837                                         u16_t port)
838 {
839         struct dhcps_msg *pmsg_dhcps = NULL;
840         s16_t tlen;
841         u16_t i;
842         u16_t dhcps_msg_cnt=0;
843         u8_t *p_dhcps_msg = NULL;
844         u8_t *data;
845
846 #if DHCPS_DEBUG
847         DHCPS_LOG("dhcps: handle_dhcp-> receive a packet\n");
848 #endif
849             if (p==NULL) return;
850
851             pmsg_dhcps = (struct dhcps_msg *)malloc(sizeof(struct dhcps_msg));
852            memset(pmsg_dhcps ,0x00 ,sizeof(struct dhcps_msg));
853         
854             if (NULL == pmsg_dhcps){
855                 pbuf_free(p);
856                 return;
857             }
858             p_dhcps_msg = (u8_t *)pmsg_dhcps;
859                 tlen = p->tot_len;
860             data = p->payload;
861
862 #if DHCPS_DEBUG
863             DHCPS_LOG("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen);
864             DHCPS_LOG("dhcps: handle_dhcp-> p->len = %d\n", p->len);
865 #endif          
866
867             for(i=0; i<p->len; i++){
868                 p_dhcps_msg[dhcps_msg_cnt++] = data[i];
869 #if DHCPS_DEBUG                                 
870                         DHCPS_LOG("%02x ",data[i]);
871                         if((i+1)%16 == 0){
872                                 DHCPS_LOG("\n");
873                         }
874 #endif
875             }
876                 
877                 if(p->next != NULL) {
878 #if DHCPS_DEBUG
879                 DHCPS_LOG("dhcps: handle_dhcp-> p->next != NULL\n");
880                 DHCPS_LOG("dhcps: handle_dhcp-> p->next->tot_len = %d\n",p->next->tot_len);
881                 DHCPS_LOG("dhcps: handle_dhcp-> p->next->len = %d\n",p->next->len);
882 #endif
883                         
884                 data = p->next->payload;
885                 for(i=0; i<p->next->len; i++){
886                     p_dhcps_msg[dhcps_msg_cnt++] = data[i];
887 #if DHCPS_DEBUG                                 
888                                 DHCPS_LOG("%02x ",data[i]);
889                                 if((i+1)%16 == 0){
890                                         DHCPS_LOG("\n");
891                                 }
892 #endif
893                         }
894                 }
895
896                 /*
897              * DHCP �ͻ���������Ϣ����
898             */
899 #if DHCPS_DEBUG
900         DHCPS_LOG("dhcps: handle_dhcp-> parse_msg(p)\n");
901 #endif
902                 
903         switch(parse_msg(pmsg_dhcps, tlen - 240)) {
904                 case DHCPS_STATE_OFFER://1 
905 #if DHCPS_DEBUG            
906                  DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n");
907 #endif                  
908                      send_offer(pmsg_dhcps);
909                      break;
910                 case DHCPS_STATE_ACK://3
911 #if DHCPS_DEBUG
912                  DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n");
913 #endif                  
914                      send_ack(pmsg_dhcps);
915                      break;
916                 case DHCPS_STATE_NAK://4
917 #if DHCPS_DEBUG            
918                  DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n");
919 #endif
920                      send_nak(pmsg_dhcps);
921                      break;
922                 default :
923                                  break;
924         }
925 #if DHCPS_DEBUG
926         DHCPS_LOG("dhcps: handle_dhcp-> pbuf_free(p)\n");
927 #endif
928         pbuf_free(p);
929         free(pmsg_dhcps);
930         pmsg_dhcps = NULL;
931 }
932 ///////////////////////////////////////////////////////////////////////////////////
933 static void wifi_softap_init_dhcps_lease(u32_t ip)
934 {
935         u32_t softap_ip = 0,local_ip = 0;
936         u32_t start_ip = 0;
937         u32_t end_ip = 0;
938         if (dhcps_lease.enable == true) {
939                 softap_ip = htonl(ip);
940                 start_ip = htonl(dhcps_lease.start_ip.addr);
941                 end_ip = htonl(dhcps_lease.end_ip.addr);
942                 /*config ip information can't contain local ip*/
943                 if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) {
944                         dhcps_lease.enable = false;
945                 } else {
946                         /*config ip information must be in the same segment as the local ip*/
947                         softap_ip >>= 8;
948                         if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip))
949                                         || (end_ip - start_ip > DHCPS_MAX_LEASE)) {
950                                 dhcps_lease.enable = false;
951                         }
952                 }
953         }
954
955         if (dhcps_lease.enable == false) {
956                 local_ip = softap_ip = htonl(ip);
957                 softap_ip &= 0xFFFFFF00;
958                 local_ip &= 0xFF;
959                 if (local_ip >= 0x80)
960                         local_ip -= DHCPS_MAX_LEASE;
961                 else
962                         local_ip ++;
963
964                 bzero(&dhcps_lease, sizeof(dhcps_lease));
965                 dhcps_lease.start_ip.addr = softap_ip | local_ip;
966                 dhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1);
967                 dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr);
968                 dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr);
969         }
970 //      os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip);
971 }
972
973
974 ///////////////////////////////////////////////////////////////////////////////////
975 void dhcps_start(struct netif *netif)
976 {
977         struct netif * apnetif =netif;
978
979
980         if(apnetif->dhcps_pcb != NULL) {
981             udp_remove(apnetif->dhcps_pcb);
982        }
983         pcb_dhcps = udp_new();
984         if (pcb_dhcps == NULL) {
985                 printf("dhcps_start(): could not obtain pcb\n");
986         }
987         apnetif->dhcps_pcb = pcb_dhcps;
988
989         IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255);
990
991         server_address = netif->ip_addr.u_addr.ip4;
992         wifi_softap_init_dhcps_lease( server_address.addr );
993     
994         client_address_plus.addr = dhcps_lease.start_ip.addr;
995     
996         udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT);
997         udp_recv(pcb_dhcps, handle_dhcp, NULL);
998 #if DHCPS_DEBUG
999         DHCPS_LOG("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n");
1000 #endif
1001         DhcpsFlags = DHCPS_STARTED;
1002
1003 }
1004
1005 void dhcps_stop(struct netif *netif )
1006 {
1007     struct netif * apnetif = netif;
1008     if(apnetif == NULL)
1009     {
1010         printf("dhcps_stop: apnetif == NULL\n");
1011         return;
1012     }
1013     udp_disconnect(pcb_dhcps);
1014 //      dhcps_lease_flag = true;
1015     if(apnetif->dhcps_pcb != NULL) {
1016         udp_remove(apnetif->dhcps_pcb);
1017         apnetif->dhcps_pcb = NULL;
1018     }
1019
1020     list_node *pnode = NULL;
1021     list_node *pback_node = NULL;
1022     pnode = plist;
1023     while (pnode != NULL) {
1024         pback_node = pnode;
1025         pnode = pback_node->pnext;
1026         node_remove_from_list(&plist, pback_node);
1027         free(pback_node->pnode);
1028         pback_node->pnode = NULL;
1029         free(pback_node);
1030         pback_node = NULL;
1031     }
1032     DhcpsFlags = DHCPS_STOP;
1033 }
1034
1035 bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please)
1036 {
1037
1038 //  NOT USE
1039         struct ip_info info;
1040         u32_t softap_ip = 0;
1041         u32_t start_ip = 0;
1042         u32_t end_ip = 0;
1043     
1044         //uint8 opmode = wifi_get_opmode();
1045        //uint8 opmode = 0;
1046         //if (opmode == STATION_MODE || opmode == NULL_MODE) {
1047                 //return false;
1048         //}
1049         if (please == NULL || get_dhcps_status() == DHCPS_STARTED)
1050                 return false;
1051
1052         if(please->enable) {
1053               struct ip_info ip_info;
1054                 memset(&ip_info, 0x00, sizeof(struct ip_info));
1055               tcpip_adapter_get_ip_info(WIFI_IF_AP, &info);
1056
1057               softap_ip = htonl(info.ip.addr);
1058                 start_ip = htonl(please->start_ip.addr);
1059                 end_ip = htonl(please->end_ip.addr);
1060
1061                 /*config ip information can't contain local ip*/
1062                 if ((start_ip <= softap_ip) && (softap_ip <= end_ip))
1063                         return false;
1064
1065                 /*config ip information must be in the same segment as the local ip*/
1066                 softap_ip >>= 8;
1067                 if ((start_ip >> 8 != softap_ip)
1068                                 || (end_ip >> 8 != softap_ip)) {
1069                         return false;
1070                 }
1071
1072                 if (end_ip - start_ip > DHCPS_MAX_LEASE)
1073                         return false;
1074
1075                memset(&dhcps_lease, 0x00, sizeof(dhcps_lease));
1076     //          dhcps_lease.start_ip.addr = start_ip;
1077     //          dhcps_lease.end_ip.addr = end_ip;
1078                 dhcps_lease.start_ip.addr = please->start_ip.addr;
1079                 dhcps_lease.end_ip.addr = please->end_ip.addr;
1080         }
1081         dhcps_lease.enable = please->enable;
1082 //      dhcps_lease_flag = false;
1083         return true;
1084 }
1085
1086 /******************************************************************************
1087  * FunctionName : wifi_softap_get_dhcps_lease
1088  * Description  : get the lease information of DHCP server
1089  * Parameters   : please -- Additional argument to get the lease information,
1090  *                                                      Little-Endian.
1091  * Returns      : true or false
1092 *******************************************************************************/
1093 bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please)
1094 {
1095
1096         if (NULL == please)
1097                 return false;
1098         if (dhcps_lease.enable == false){
1099                 if (get_dhcps_status() == DHCPS_STOP)
1100                         return false;
1101         } else {
1102             ;
1103         }
1104         please->start_ip.addr = dhcps_lease.start_ip.addr;
1105         please->end_ip.addr = dhcps_lease.end_ip.addr;
1106         return true;
1107 }
1108
1109 static void kill_oldest_dhcps_pool(void)
1110 {
1111         list_node *pre = NULL, *p = NULL;
1112         list_node *minpre = NULL, *minp = NULL;
1113         struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL;
1114         pre = plist;
1115         p = pre->pnext;
1116         minpre = pre;
1117         minp = p;
1118         while (p != NULL){
1119                 pdhcps_pool = p->pnode;
1120                 pmin_pool = minp->pnode;
1121                 if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){
1122                         minp = p;
1123                         minpre = pre;
1124                 }
1125                 pre = p;
1126                 p = p->pnext;
1127         }
1128         minpre->pnext = minp->pnext;
1129         free(minp->pnode);
1130         minp->pnode = NULL;
1131         free(minp);
1132         minp = NULL;
1133 }
1134
1135 void dhcps_coarse_tmr(void)
1136 {
1137         u8_t num_dhcps_pool = 0;
1138         list_node *pback_node = NULL;
1139         list_node *pnode = NULL;
1140         struct dhcps_pool *pdhcps_pool = NULL;
1141         pnode = plist;
1142         while (pnode != NULL) {
1143                 pdhcps_pool = pnode->pnode;
1144                 pdhcps_pool->lease_timer --;
1145                 if (pdhcps_pool->lease_timer == 0){
1146                         pback_node = pnode;
1147                         pnode = pback_node->pnext;
1148                         node_remove_from_list(&plist,pback_node);
1149                         free(pback_node->pnode);
1150                         pback_node->pnode = NULL;
1151                         free(pback_node);
1152                         pback_node = NULL;
1153                 } else {
1154                         pnode = pnode ->pnext;
1155                         num_dhcps_pool ++;
1156                 }
1157         }
1158
1159         if (num_dhcps_pool >= MAX_STATION_NUM)
1160                 kill_oldest_dhcps_pool();
1161 }
1162
1163 bool wifi_softap_set_dhcps_offer_option(u8_t level, void* optarg)
1164 {
1165         bool offer_flag = true;
1166         u8_t option = 0;
1167
1168         if (optarg == NULL && get_dhcps_status() == false)
1169                 return false;
1170
1171         if (level <= OFFER_START || level >= OFFER_END)
1172                 return false;
1173
1174         switch (level){
1175                 case OFFER_ROUTER:
1176                         offer = (*(u8_t *)optarg) & 0x01;
1177                         offer_flag = true;
1178                         break;
1179                 default :
1180                         offer_flag = false;
1181                         break;
1182         }
1183         return offer_flag;
1184 }
1185
1186 bool wifi_softap_set_dhcps_lease_time(u32_t minute)
1187 {
1188
1189     if (get_dhcps_status() == DHCPS_STARTED) {
1190         return false;
1191     }
1192
1193     if(minute == 0) {
1194         return false;
1195     }
1196     dhcps_lease_time = minute;
1197     return true;
1198 }
1199
1200 bool wifi_softap_reset_dhcps_lease_time(void)
1201 {
1202
1203     if (get_dhcps_status() == DHCPS_STARTED) {
1204         return false;
1205     }
1206     dhcps_lease_time = DHCPS_LEASE_TIME_DEF;
1207     return true;
1208 }
1209
1210 u32_t wifi_softap_get_dhcps_lease_time(void) // minute
1211 {
1212     return dhcps_lease_time;
1213 }
1214 #else
1215 #include <stdio.h>
1216 #include <sys/types.h>
1217 #include <sys/socket.h>
1218 #include "lwip/sys.h"
1219 #include <netdb.h>
1220 #include <errno.h>
1221 static os_timer_t micros_overflow_timer;
1222 static uint32_t micros_at_last_overflow_tick = 0;
1223 static uint32_t micros_overflow_count = 0;
1224
1225 void micros_overflow_tick(void* arg)
1226 {
1227     uint32_t m = system_get_time();
1228     if(m < micros_at_last_overflow_tick)
1229         ++micros_overflow_count;
1230     micros_at_last_overflow_tick = m;
1231 }
1232
1233 unsigned long  millis()
1234 {
1235     uint32_t m = system_get_time();
1236     uint32_t c = micros_overflow_count + ((m < micros_at_last_overflow_tick) ? 1 : 0);
1237     return c * 4294967 + m / 1000;
1238 }
1239
1240 unsigned long  micros()
1241 {
1242     return system_get_time();
1243 }
1244
1245 void dhcps_set_default_time(void)
1246 {
1247         os_timer_disarm(&micros_overflow_timer);
1248     os_timer_setfn(&micros_overflow_timer, (os_timer_func_t*) &micros_overflow_tick, 0);
1249     os_timer_arm(&micros_overflow_timer, 60000, 1);
1250 }
1251
1252 time_t time(time_t * t)
1253 {
1254     time_t seconds = millis();
1255     if (t)
1256     {
1257         *t = seconds;
1258     }
1259     return seconds;
1260 }
1261
1262 /*
1263  * Initialize the binding list.
1264  */
1265
1266 void
1267 dhcp_binding_list_init (binding_list *list)
1268 {
1269     STAILQ_INIT(list);
1270 }
1271
1272 /*
1273  * Create a new binding
1274  *
1275  * The binding is added to the binding list,
1276  * and a pointer to the binding is returned for further manipulations.
1277  */
1278
1279 address_binding *
1280 dhcp_binding_add (binding_list *list, uint32_t address, uint8_t *cident, uint8_t cident_len, int is_static)
1281 {
1282     // fill binding
1283     address_binding *binding = calloc(1, sizeof(*binding));
1284
1285     binding->address = address;
1286     binding->cident_len = cident_len;
1287     memcpy(binding->cident, cident, cident_len);
1288
1289     binding->is_static = is_static;
1290
1291     // add to binding list
1292     STAILQ_INSERT_HEAD(list, binding, pointers);
1293
1294     return binding;
1295 }
1296
1297 /*
1298  * Updated bindings status, i.e. set to EXPIRED the status of the
1299  * expired bindings.
1300  */
1301
1302 void
1303 dhcp_binding_statuses_update (binding_list *list)
1304 {
1305     address_binding *binding, *binding_temp;
1306
1307     STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1308     {
1309         if(binding->binding_time + binding->lease_time < time(NULL))
1310         {
1311             binding->status = EXPIRED;
1312         }
1313     }
1314 }
1315
1316 /*
1317  * Search a static or dynamic binding having the given client identifier.
1318  *
1319  * If the is_static option is true a static binding will be searched,
1320  * otherwise a dynamic one. If status is not zero, an binding with that
1321  * status will be searched.
1322  */
1323
1324 address_binding *
1325 dhcp_binding_search (binding_list *list, uint8_t *cident, uint8_t cident_len, int is_static, int status)
1326 {
1327     address_binding *binding, *binding_temp;
1328
1329     STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1330     {
1331         if((binding->is_static == is_static || is_static == STATIC_OR_DYNAMIC) &&
1332            binding->cident_len == cident_len &&
1333            memcmp(binding->cident, cident, cident_len) == 0)
1334         {
1335             if(status == 0)
1336                 return binding;
1337             else if(status == binding->status)
1338                 return binding;
1339         }
1340     }
1341
1342     return NULL;
1343 }
1344
1345 /*
1346  * Get an available free address
1347  *
1348  * If a zero address is returned, no more address are available.
1349  */
1350
1351 static uint32_t
1352 dhcp_binding_take_free_address (pool_indexes *indexes)
1353 {
1354     if(indexes->current <= indexes->last)
1355     {
1356         uint32_t address = indexes->current;
1357         indexes->current = htonl(ntohl(indexes->current) + 1);
1358         return address;
1359
1360     }
1361     else
1362         return 0;
1363 }
1364
1365 /*
1366  * Create a new dynamic binding or reuse an expired one.
1367  *
1368  * An attemp will be made to assign to the client the requested IP address
1369  * contained in the address option. An address equals to zero means that no
1370  * specific address has been requested.
1371  *
1372  * If the dynamic pool of addresses is full a NULL pointer will be returned.
1373  */
1374
1375 address_binding *
1376 dhcp_binding_new_dynamic (binding_list *list, pool_indexes *indexes, uint32_t address, uint8_t *cident, uint8_t cident_len)
1377 {
1378     address_binding *binding, *binding_temp;
1379     address_binding *found_binding = NULL;
1380
1381     if (address != 0)
1382     {
1383
1384         STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1385         {
1386             // search a previous binding using the requested IP address
1387
1388             if(binding->address == address)
1389             {
1390                 found_binding = binding;
1391                 break;
1392             }
1393         }
1394     }
1395
1396     if(found_binding != NULL &&
1397        !found_binding->is_static &&
1398        found_binding->status != PENDING &&
1399        found_binding->status != ASSOCIATED)
1400     {
1401
1402         // the requested IP address is available (reuse an expired association)
1403         return found_binding;
1404
1405     }
1406     else
1407     {
1408
1409         /* the requested IP address is already in use, or no address has been
1410                requested, or the address requested has never been allocated
1411                (we do not support this last case and just return the next
1412                available address!). */
1413
1414         uint32_t address = dhcp_binding_take_free_address(indexes);
1415
1416         if(address != 0)
1417             return dhcp_binding_add(list, address, cident, cident_len, 0);
1418
1419         else   // search any previously assigned address which is expired
1420         {
1421
1422             STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1423             {
1424                 if(!binding->is_static &&
1425                    found_binding->status != PENDING &&
1426                    found_binding->status != ASSOCIATED)
1427                     return binding;
1428             }
1429
1430             // if executions reach here no more addresses are available
1431             return NULL;
1432         }
1433     }
1434 }
1435
1436 /*
1437  * Delete an binding list and deallocate its memory.
1438  * Deallocate even the list elements.
1439  */
1440
1441 static void
1442 dhcp_binding_list_delete (binding_list *list)
1443 {
1444     address_binding *opt = STAILQ_FIRST(list);
1445     address_binding *tmp;
1446
1447     while (opt != NULL)
1448     {
1449         tmp = STAILQ_NEXT(opt, pointers);
1450         free(opt);
1451         opt = tmp;
1452     }
1453
1454     STAILQ_INIT(list);
1455 }
1456
1457 /* Value parsing functions:
1458  *
1459  * Parse the string pointed by s, and allocate the
1460  * pointer p to contain the parsed data.
1461  *
1462  * On success return the size of the parsed data,
1463  * on error return zero.
1464  */
1465
1466 static  int dhcp_option_byte (char *s, void **p);
1467 static  int dhcp_option_byte_list (char *s, void **p);
1468 static  int dhcp_option_short (char *s, void **p);
1469 static  int dhcp_option_short_list (char *s, void **p);
1470 static  int dhcp_option_long (char *s, void **p);
1471 static  int dhcp_option_string (char *s, void **p);
1472 static  int dhcp_option_ip (char *s, void **p);
1473 static  int dhcp_option_ip_list (char *s, void **p);
1474
1475 /* Global pool */
1476 static  const uint8_t dhcp_option_magic[4] = {0x63, 0x82, 0x53, 0x63};
1477 static address_pool dhcp_address_pool = {0};
1478
1479 /*
1480  * Mapping table between DHCP options and
1481  * functions that parse their value.
1482  */
1483 static struct
1484 {
1485     char *name;
1486     int (*f) (char *, void **);
1487 } dhcp_option_info [256] =
1488 {
1489     [PAD] { "PAD", NULL },
1490     [END] { "END", NULL },
1491     [SUBNET_MASK] { "SUBNET_MASK", dhcp_option_ip },
1492     [TIME_OFFSET] { "TIME_OFFSET", dhcp_option_long },
1493     [ROUTER] { "ROUTER", dhcp_option_ip_list },
1494     [TIME_SERVER] { "TIME_SERVER", dhcp_option_ip_list },
1495     [NAME_SERVER] { "NAME_SERVER", dhcp_option_ip_list },
1496     [DOMAIN_NAME_SERVER] { "DOMAIN_NAME_SERVER", dhcp_option_ip_list },
1497     [LOG_SERVER] { "LOG_SERVER", dhcp_option_ip_list },
1498     [COOKIE_SERVER] { "COOKIE_SERVER", dhcp_option_ip_list },
1499     [LPR_SERVER] { "LPR_SERVER", dhcp_option_ip_list },
1500     [IMPRESS_SERVER] { "IMPRESS_SERVER", dhcp_option_ip_list },
1501     [RESOURCE_LOCATION_SERVER] { "RESOURCE_LOCATION_SERVER", dhcp_option_ip_list },
1502     [HOST_NAME] { "HOST_NAME", dhcp_option_string },
1503     [BOOT_FILE_SIZE] { "BOOT_FILE_SIZE", dhcp_option_short },
1504     [MERIT_DUMP_FILE] { "MERIT_DUMP_FILE", dhcp_option_string },
1505     [DOMAIN_NAME] { "DOMAIN_NAME", dhcp_option_string },
1506     [SWAP_SERVER] { "SWAP_SERVER", dhcp_option_ip },
1507     [ROOT_PATH] { "ROOT_PATH", dhcp_option_string },
1508     [EXTENSIONS_PATH] { "EXTENSIONS_PATH", dhcp_option_string },
1509     [IP_FORWARDING] { "IP_FORWARDING", dhcp_option_byte },
1510     [NON_LOCAL_SOURCE_ROUTING] { "NON_LOCAL_SOURCE_ROUTING", dhcp_option_byte },
1511     [POLICY_FILTER] { "POLICY_FILTER", dhcp_option_ip_list },
1512     [MAXIMUM_DATAGRAM_REASSEMBLY_SIZE] { "MAXIMUM_DATAGRAM_REASSEMBLY_SIZE", dhcp_option_short },
1513     [DEFAULT_IP_TIME_TO_LIVE] { "DEFAULT_IP_TIME_TO_LIVE", dhcp_option_byte },
1514     [PATH_MTU_AGING_TIMEOUT] { "PATH_MTU_AGING_TIMEOUT", dhcp_option_long },
1515     [PATH_MTU_PLATEAU_TABLE] { "PATH_MTU_PLATEAU_TABLE", dhcp_option_short_list },
1516     [INTERFACE_MTU] { "INTERFACE_MTU", dhcp_option_short },
1517     [ALL_SUBNETS_ARE_LOCAL] { "ALL_SUBNETS_ARE_LOCAL", dhcp_option_byte },
1518     [BROADCAST_ADDRESS] { "BROADCAST_ADDRESS", dhcp_option_ip },
1519     [PERFORM_MASK_DISCOVERY] { "PERFORM_MASK_DISCOVERY", dhcp_option_byte },
1520     [MASK_SUPPLIER] { "MASK_SUPPLIER", dhcp_option_byte },
1521     [PERFORM_ROUTER_DISCOVERY] { "PERFORM_ROUTER_DISCOVERY", dhcp_option_byte },
1522     [ROUTER_SOLICITATION_ADDRESS] { "ROUTER_SOLICITATION_ADDRESS", dhcp_option_ip },
1523     [STATIC_ROUTE] { "STATIC_ROUTE", dhcp_option_ip_list },
1524     [TRAILER_ENCAPSULATION] { "TRAILER_ENCAPSULATION", dhcp_option_byte },
1525     [ARP_CACHE_TIMEOUT] { "ARP_CACHE_TIMEOUT", dhcp_option_long },
1526     [ETHERNET_ENCAPSULATION] { "ETHERNET_ENCAPSULATION", dhcp_option_byte },
1527     [TCP_DEFAULT_TTL] { "TCP_DEFAULT_TTL", dhcp_option_byte },
1528     [TCP_KEEPALIVE_INTERVAL] { "TCP_KEEPALIVE_INTERVAL", dhcp_option_long },
1529     [TCP_KEEPALIVE_GARBAGE] { "TCP_KEEPALIVE_GARBAGE", dhcp_option_byte },
1530     [NETWORK_INFORMATION_SERVICE_DOMAIN] { "NETWORK_INFORMATION_SERVICE_DOMAIN", dhcp_option_string },
1531     [NETWORK_INFORMATION_SERVERS] { "NETWORK_INFORMATION_SERVERS", dhcp_option_ip_list },
1532     [NETWORK_TIME_PROTOCOL_SERVERS] { "NETWORK_TIME_PROTOCOL_SERVERS", dhcp_option_ip_list },
1533     [VENDOR_SPECIFIC_INFORMATION] { "VENDOR_SPECIFIC_INFORMATION", dhcp_option_byte_list },
1534     [NETBIOS_OVER_TCP_IP_NAME_SERVER] { "NETBIOS_OVER_TCP_IP_NAME_SERVER", dhcp_option_ip_list },
1535     [NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER] { "NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER", dhcp_option_ip_list },
1536     [NETBIOS_OVER_TCP_IP_NODE_TYPE] { "NETBIOS_OVER_TCP_IP_NODE_TYPE", dhcp_option_byte },
1537     [NETBIOS_OVER_TCP_IP_SCOPE] { "NETBIOS_OVER_TCP_IP_SCOPE", dhcp_option_string },
1538     [X_WINDOW_SYSTEM_FONT_SERVER] { "X_WINDOW_SYSTEM_FONT_SERVER", dhcp_option_ip_list },
1539     [X_WINDOW_SYSTEM_DISPLAY_MANAGER] { "X_WINDOW_SYSTEM_DISPLAY_MANAGER", dhcp_option_ip_list },
1540     [NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN] { "NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN", dhcp_option_string },
1541     [NETWORK_INFORMATION_SERVICE_PLUS_SERVERS] { "NETWORK_INFORMATION_SERVICE_PLUS_SERVERS", dhcp_option_ip_list },
1542     [MOBILE_IP_HOME_AGENT] { "MOBILE_IP_HOME_AGENT", dhcp_option_ip_list },
1543     [SMTP_SERVER] { "SMTP_SERVER", dhcp_option_ip_list },
1544     [POP3_SERVER] { "POP3_SERVER", dhcp_option_ip_list },
1545     [NNTP_SERVER] { "NNTP_SERVER", dhcp_option_ip_list },
1546     [DEFAULT_WWW_SERVER] { "DEFAULT_WWW_SERVER", dhcp_option_ip_list },
1547     [DEFAULT_FINGER_SERVER] { "DEFAULT_FINGER_SERVER", dhcp_option_ip_list },
1548     [DEFAULT_IRC_SERVER] { "DEFAULT_IRC_SERVER", dhcp_option_ip_list },
1549     [STREETTALK_SERVER] { "STREETTALK_SERVER", dhcp_option_ip_list },
1550     [STREETTALK_DIRECTORY_ASSISTANCE_SERVER] { "STREETTALK_DIRECTORY_ASSISTANCE_SERVER",  dhcp_option_ip_list },
1551     [REQUESTED_IP_ADDRESS] { "REQUESTED_IP_ADDRESS", NULL },
1552     [IP_ADDRESS_LEASE_TIME] { "IP_ADDRESS_LEASE_TIME", dhcp_option_long },
1553     [OPTION_OVERLOAD] { "OPTION_OVERLOAD", dhcp_option_byte },
1554     [TFTP_SERVER_NAME] { "TFTP_SERVER_NAME", dhcp_option_string },
1555     [BOOTFILE_NAME] { "BOOTFILE_NAME", dhcp_option_string },
1556     [DHCP_MESSAGE_TYPE] { "DHCP_MESSAGE_TYPE", NULL },
1557     [SERVER_IDENTIFIER] { "SERVER_IDENTIFIER", dhcp_option_ip },
1558     [PARAMETER_REQUEST_LIST] { "PARAMETER_REQUEST_LIST", NULL },
1559     [MESSAGE] { "MESSAGE", NULL },
1560     [MAXIMUM_DHCP_MESSAGE_SIZE] { "MAXIMUM_DHCP_MESSAGE_SIZE", NULL },
1561     [RENEWAL_T1_TIME_VALUE] { "RENEWAL_T1_TIME_VALUE", dhcp_option_long },
1562     [REBINDING_T2_TIME_VALUE] { "REBINDING_T2_TIME_VALUE", dhcp_option_long },
1563     [VENDOR_CLASS_IDENTIFIER] { "VENDOR_CLASS_IDENTIFIER", NULL },
1564     [CLIENT_IDENTIFIER] { "CLIENT_IDENTIFIER", NULL },
1565
1566     [USER_CLASS] { "USER_CLASS", NULL },
1567     [FQDN] { "FQDN", NULL },
1568     [DHCP_AGENT_OPTIONS] { "DHCP_AGENT_OPTIONS", NULL },
1569     [NDS_SERVERS] { "NDS_SERVERS", NULL },
1570     [NDS_TREE_NAME] { "NDS_TREE_NAME", NULL },
1571     [NDS_CONTEXT] { "NDS_CONTEXT", NULL },
1572     [CLIENT_LAST_TRANSACTION_TIME] { "CLIENT_LAST_TRANSACTION_TIME", NULL },
1573     [ASSOCIATED_IP] { "ASSOCIATED_IP", NULL },
1574     [USER_AUTHENTICATION_PROTOCOL] { "USER_AUTHENTICATION_PROTOCOL", NULL },
1575     [AUTO_CONFIGURE] { "AUTO_CONFIGURE", NULL },
1576     [NAME_SERVICE_SEARCH] { "NAME_SERVICE_SEARCH", dhcp_option_string },
1577     [SUBNET_SELECTION] { "SUBNET_SELECTION", NULL },
1578     [DOMAIN_SEARCH] { "DOMAIN_SEARCH", dhcp_option_string },
1579     [CLASSLESS_ROUTE] { "CLASSLESS_ROUTE", dhcp_option_string },
1580 };
1581
1582 /* Value parsing functions */
1583
1584 static int
1585 dhcp_option_byte (char *s, void **p)
1586 {
1587     *p = malloc(sizeof(uint8_t));
1588     uint8_t n = ((uint8_t) strtol(s, NULL, 0));
1589     memcpy(*p, &n, sizeof(n));
1590
1591     return sizeof(uint8_t);
1592 }
1593
1594 static int
1595 dhcp_option_byte_list (char *s, void **p)
1596 {
1597     *p = malloc(strlen(s) * sizeof(uint8_t)); // slightly over the strictly requested size
1598
1599     int count = 0;
1600
1601     char *s2 = strdup(s);
1602     char *s3 = strtok(s2, ", ");
1603
1604     while(s3 != NULL)
1605     {
1606
1607         uint8_t n = ((uint8_t) strtol(s3, NULL, 0));
1608
1609         memcpy(((uint8_t *) *p) + count, &n, sizeof(uint8_t));
1610
1611         count += sizeof(uint8_t);
1612         s3 = strtok(NULL, " ");
1613     }
1614
1615     free(s2);
1616
1617     return count;
1618 }
1619
1620 static int
1621 dhcp_option_short (char *s, void **p)
1622 {
1623     *p = malloc(sizeof(uint16_t));
1624     uint16_t n = ((uint16_t) strtol(s, NULL, 0));
1625     memcpy(*p, &n, sizeof(n));
1626
1627     return sizeof(uint16_t);
1628 }
1629
1630 static int
1631 dhcp_option_short_list (char *s, void **p)
1632 {
1633     *p = malloc(strlen(s) * sizeof(uint16_t)); // slightly over the strictly requested size
1634
1635     int count = 0;
1636
1637     char *s2 = strdup(s);
1638     char *s3 = strtok(s2, ", ");
1639
1640     while(s3 != NULL)
1641     {
1642
1643         uint16_t n = ((uint16_t) strtol(s3, NULL, 0));
1644
1645         memcpy(((uint8_t *) *p) + count, &n, sizeof(uint16_t));
1646
1647         count += sizeof(uint16_t);
1648         s3 = strtok(NULL, " ");
1649     }
1650
1651     free(s2);
1652
1653     return count;
1654 }
1655
1656 static int
1657 dhcp_option_long (char *s, void **p)
1658 {
1659     *p = malloc(sizeof(uint32_t));
1660     uint32_t n = strtol(s, NULL, 0);
1661     memcpy(*p, &n, sizeof(n));
1662
1663     return sizeof(uint32_t);
1664 }
1665
1666 static int
1667 dhcp_option_string (char *s, void **p)
1668 {
1669     *p = strdup(s);
1670
1671     return strlen(s);
1672 }
1673
1674 static int
1675 dhcp_option_ip (char *s, void **p)
1676 {
1677     struct sockaddr_in ip;
1678
1679     *p = malloc(sizeof(uint32_t));
1680
1681     if (inet_aton(s, &ip.sin_addr) == 0)   // error: invalid IP address
1682     {
1683         free(*p);
1684         return 0;
1685     }
1686
1687     memcpy(*p, &ip.sin_addr, sizeof(uint32_t));
1688
1689     return sizeof(uint32_t);
1690 }
1691
1692 static int
1693 dhcp_option_ip_list (char *s, void **p)
1694 {
1695     *p = malloc(strlen(s) * sizeof(uint32_t) / 4); // slightly over the strictly required size
1696
1697     int count = 0;
1698
1699     char *s2 = strdup(s);
1700     char *s3 = strtok(s2, ", ");
1701
1702     while(s3 != NULL)
1703     {
1704         struct sockaddr_in ip;
1705
1706         if (inet_aton(s3, &ip.sin_addr) == 0)   // error: invalid IP address
1707         {
1708             free(*p);
1709             return 0;
1710         }
1711
1712         memcpy(((uint8_t *) *p) + count, &ip.sin_addr, sizeof(uint32_t));
1713
1714         count += sizeof(uint32_t);
1715         s3 = strtok(NULL, " ");
1716     }
1717
1718     free(s2);
1719
1720     return count;
1721 }
1722
1723 /* Option-related functions */
1724
1725 /*
1726  * Given the name of the option and its value as strings,
1727  * fill the dhcp_option structure pointed by opt.
1728  *
1729  * On success return the parsed option id,
1730  * otherwise return zero.
1731  */
1732 static uint8_t
1733 dhcp_option_parse (dhcp_option *opt, char *name, char *value)
1734 {
1735     int (*f) (char *, void **);
1736     int id;
1737
1738     uint8_t len;
1739     uint8_t *p;
1740
1741     for (id = 0; id < 256; id++)   // search the option by name
1742     {
1743         if (dhcp_option_info[id].name &&
1744             strcmp(dhcp_option_info[id].name, name) == 0) break;
1745     }
1746
1747     if (id == 256)   // not found
1748     {
1749         log_info("Unsupported DHCP option '%s'", name);
1750         return 0;
1751     }
1752
1753     f = dhcp_option_info[id].f;
1754
1755     if (f == NULL)   // no parsing function available
1756     {
1757         log_info("Unsupported DHCP option '%s'", name);
1758         return 0;
1759     }
1760
1761     len = f(value, (void **)&p); // parse the value
1762
1763     if(len == 0) // error parsing the value
1764         return 0;
1765
1766     // structure filling
1767     opt->id = id;
1768     opt->len = len;
1769     memcpy(opt->data, p, len);
1770
1771     free(p);
1772
1773     return opt->id;
1774 }
1775
1776 /*
1777  * Initialize an option list.
1778  */
1779
1780 static void
1781 dhcp_option_list_init (dhcp_option_list *list)
1782 {
1783     STAILQ_INIT(list);
1784 }
1785
1786 /*
1787  * Given a list of options search an option having
1788  * the passed option id, and returns a pointer to it.
1789  *
1790  * If the option is not present the function returns NULL.
1791  */
1792
1793 static dhcp_option *
1794 dhcp_option_search (dhcp_option_list *list, uint8_t id)
1795 {
1796     dhcp_option *opt, *opt_temp;
1797
1798     STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1799     {
1800
1801         if(opt->id == id)
1802             return opt;
1803
1804     }
1805
1806     return NULL;
1807 }
1808
1809 /*
1810  * Print options in list.
1811  */
1812
1813 static void
1814 dhcp_option_print (dhcp_option_list *list)
1815 {
1816     dhcp_option *opt, *opt_temp;
1817     int i=0;
1818
1819     STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1820     {
1821
1822         printf("options[%d]=%d (%s)\n", i++, opt->id,
1823                dhcp_option_info[opt->id].name);
1824
1825     }
1826 }
1827
1828
1829 /*
1830  * Append the provided option to the list.
1831  *
1832  * Always allocate new memory, that must be freed later...
1833  */
1834
1835 static void
1836 dhcp_option_append (dhcp_option_list *list, dhcp_option *opt)
1837 {
1838     dhcp_option *nopt = calloc(1, sizeof(*nopt));
1839     memcpy(nopt, opt, 2 + opt->len);
1840
1841     STAILQ_INSERT_TAIL(list, nopt, pointers);
1842 }
1843
1844 /*
1845  * Parse the options contained in a DHCP message into a list.
1846  *
1847  * Return 1 on success, 0 if the options are malformed.
1848  */
1849
1850 static int
1851 dhcp_option_parse_to_list (dhcp_option_list *list, dhcp_option *opts, size_t len)
1852 {
1853     dhcp_option *opt, *end;
1854
1855     opt = opts;
1856     end = (dhcp_option *)(((uint8_t *)opts) + len);
1857
1858     if (len < 4 ||
1859         memcmp(opt, dhcp_option_magic, sizeof(dhcp_option_magic)) != 0)
1860         return 0;
1861
1862     opt = (dhcp_option *)(((uint8_t *) opt) + 4);
1863
1864     while (opt < end  &&
1865            opt->id != END)   // TODO: check also valid option sizes
1866     {
1867
1868         if ((dhcp_option *)(((uint8_t *) opt) + 2 + opt->len) >= end)
1869             return 0; // the len field is too long
1870
1871         dhcp_option_append(list, opt);
1872
1873         opt = (dhcp_option *)(((uint8_t *) opt) + 2 + opt->len);
1874     }
1875
1876     if (opt < end && opt->id == END)
1877         return 1;
1878
1879     return 0;
1880 }
1881
1882 /*
1883  * Serialize a list of options, to be inserted directly inside
1884  * the options section of a DHCP message.
1885  *
1886  * Return 0 on error, the total serialized len on success.
1887  */
1888
1889 static size_t
1890 dhcp_option_list_serialize (dhcp_option_list *list, uint8_t *buf, size_t len)
1891 {
1892     uint8_t *p = buf;
1893
1894     if (len < 4)
1895         return 0;
1896
1897     memcpy(p, dhcp_option_magic, sizeof(dhcp_option_magic));
1898     p += 4;
1899     len -= 4;
1900
1901     dhcp_option *opt, *opt_temp;
1902
1903     STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1904     {
1905
1906         if (len <= 2 + opt->len)
1907             return 0;
1908
1909         memcpy(p, opt, 2 + opt->len);
1910         p   += 2 + opt->len;
1911         len -= 2 + opt->len;
1912
1913     }
1914
1915     if (len < 1)
1916         return 0;
1917
1918     *p = END;
1919
1920     p++;
1921     len--;
1922
1923     return p - buf;
1924 }
1925
1926 /*
1927  * Delete an option list and deallocate its memory.
1928  * Deallocate even the list elements.
1929  */
1930
1931 static void
1932 dhcp_option_list_delete (dhcp_option_list *list)
1933 {
1934     dhcp_option *opt = STAILQ_FIRST(list);
1935     dhcp_option *tmp;
1936
1937     while (opt != NULL)
1938     {
1939         tmp = STAILQ_NEXT(opt, pointers);
1940         free(opt);
1941         opt = tmp;
1942     }
1943
1944     STAILQ_INIT(list);
1945 }
1946
1947 static void dhcp_options_default_fill(dhcp_option_list *list, dhcp_option_list *reply_opts)
1948 {
1949     dhcp_option *opt, *opt_temp;
1950     int i = 0;
1951
1952     STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1953     {
1954         log_info("options[%d]=%d (%s)\n", i++, opt->id, dhcp_option_info[opt->id].name);
1955
1956         if (opt != NULL)
1957             dhcp_option_append(reply_opts, opt);
1958     }
1959 }
1960
1961 static void
1962 dhcp_options_requested_fill (dhcp_option *requested_opts, dhcp_option_list *reply_opts)
1963 {
1964     uint8_t len = requested_opts->len;
1965     uint8_t *id = requested_opts->data;
1966
1967     int i = 0;
1968     for (i = 0; i < len; i++)
1969     {
1970         if(id[i] != 0)
1971         {
1972             dhcp_option *opt = dhcp_option_search(&dhcp_address_pool.options, id[i]);
1973
1974             if(opt != NULL)
1975                 dhcp_option_append(reply_opts, opt);
1976         }
1977     }
1978     dhcp_option_print(reply_opts);
1979 }
1980
1981 static bool dhcp_options_add(char* name, char* value)
1982 {
1983     uint8_t id = 0;
1984     bool flags = true;
1985     REQUIRE_ACTION(name, add_error, flags = false);
1986     REQUIRE_ACTION(value, add_error, flags = false);
1987     dhcp_option *option = calloc(1, sizeof(*option));
1988     REQUIRE_ACTION(option, add_error, flags = false);
1989     id = dhcp_option_parse(option, name, value);
1990     if (id == 0)
1991     {
1992         log_info( "error: invalid dhcp option specified: %s,%s",name, value);
1993         REQUIRE_ACTION(option, add_error, flags = false);
1994     }
1995
1996     dhcp_option_append(&dhcp_address_pool.options, option);
1997
1998     if(option->id == IP_ADDRESS_LEASE_TIME)
1999         dhcp_address_pool.lease_time = ntohl(*((uint32_t *)option->data));
2000
2001 add_error:
2002     free(option);
2003     return flags;
2004 }
2005
2006 /*
2007  * Message handling routines.
2008  */
2009
2010 static uint8_t dhcp_request_expand (dhcps_msg *request, size_t len)
2011 {
2012     dhcp_option_list_init(&request->opts);
2013
2014     if (request->hdr.hlen < 1 || request->hdr.hlen > 16)
2015         return 0;
2016
2017     if (dhcp_option_parse_to_list(&request->opts, (dhcp_option *)request->hdr.options, len - DHCP_HEADER_SIZE) == 0)
2018         return 0;
2019
2020     dhcp_option *type_opt = dhcp_option_search(&request->opts, DHCP_MESSAGE_TYPE);
2021
2022     if (type_opt == NULL)
2023         return 0;
2024
2025     uint8_t type = type_opt->data[0];
2026
2027     return type;
2028 }
2029
2030 static int
2031 dhcp_reply_init (dhcps_msg *request, dhcps_msg *reply)
2032 {
2033     memset(&reply->hdr, 0, sizeof(reply->hdr));
2034
2035     dhcp_option_list_init(&reply->opts);
2036
2037     reply->hdr.op = BOOTREPLY;
2038
2039     reply->hdr.htype = request->hdr.htype;
2040     reply->hdr.hlen  = request->hdr.hlen;
2041
2042     reply->hdr.xid   = request->hdr.xid;
2043     reply->hdr.flags = request->hdr.flags;
2044
2045     reply->hdr.giaddr = request->hdr.giaddr;
2046
2047     memcpy(reply->hdr.chaddr, request->hdr.chaddr, request->hdr.hlen);
2048
2049     return 1;
2050 }
2051
2052 static int dhcp_reply_send(struct udp_pcb *pcb, ip_addr_t *addr, dhcps_msg *reply)
2053 {
2054     size_t len = 0, ret = 0;
2055     struct pbuf *p = NULL, *q = NULL;
2056     u8_t *data = NULL;
2057     u16_t cnt = 0;
2058     u16_t i = 0;
2059
2060     len = dhcp_option_list_serialize(&reply->opts, reply->hdr.options, sizeof(reply->hdr) - DHCP_HEADER_SIZE);
2061     len += DHCP_HEADER_SIZE;
2062
2063     dhcp_option *type_opt = dhcp_option_search(&reply->opts, DHCP_MESSAGE_TYPE);
2064     if (type_opt == NULL)
2065         return -1;
2066
2067 //    if (type_opt->data[0] == DHCP_OFFER)
2068     addr->u_addr.ip4.addr = INADDR_BROADCAST;
2069 //    else
2070 //        ip4_addr_set(ip_2_ip4(addr), &reply->hdr.yiaddr); // use the address assigned by us
2071
2072     if (reply->hdr.yiaddr.addr != 0)
2073     {
2074         log_info("send_dhcp_reply %s\n", inet_ntoa(*addr));
2075     }
2076
2077     p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
2078
2079     if (p != NULL)
2080     {
2081         q = p;
2082         while (q != NULL)
2083         {
2084             data = (u8_t *)q->payload;
2085             for (i = 0; i< q->len; i++)
2086             {
2087                 data[i] = ((u8_t *) reply)[cnt++];
2088             }
2089
2090             q = q->next;
2091         }
2092     }
2093     else
2094     {
2095         return 0;
2096     }
2097
2098     ret = udp_sendto(pcb, p, addr, BOOTPC);
2099     log_info("dhcp_send %d %d\n", ret, p->ref);
2100     if(p->ref != 0)
2101     {
2102         pbuf_free(p);
2103     }
2104
2105     return ret;
2106 }
2107
2108 static int
2109 dhcp_reply_fill (dhcps_msg *request, dhcps_msg *reply,
2110                  address_binding *binding, uint8_t type)
2111 {
2112     static dhcp_option type_opt, server_id_opt;
2113
2114     type_opt.id = DHCP_MESSAGE_TYPE;
2115     type_opt.len = 1;
2116     type_opt.data[0] = type;
2117     dhcp_option_append(&reply->opts, &type_opt);
2118
2119     server_id_opt.id = SERVER_IDENTIFIER;
2120     server_id_opt.len = 4;
2121     memcpy(server_id_opt.data, &dhcp_address_pool.server_id, sizeof(dhcp_address_pool.server_id));
2122     dhcp_option_append(&reply->opts, &server_id_opt);
2123
2124     if(binding != NULL)
2125     {
2126         reply->hdr.yiaddr.addr = binding->address;
2127     }
2128
2129     if (type != DHCPS_NAK)
2130     {
2131         dhcp_option *requested_opts = dhcp_option_search(&request->opts, PARAMETER_REQUEST_LIST);
2132
2133         if (requested_opts)
2134             dhcp_options_default_fill(&dhcp_address_pool.options, &reply->opts);
2135     }
2136
2137     return type;
2138 }
2139
2140 static int
2141 dhcp_discover (dhcps_msg *request, dhcps_msg *reply)
2142 {
2143     address_binding *binding = NULL;
2144     binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC, EMPTY);
2145
2146     if (binding)
2147     {
2148         /* a static binding has been configured for this client */
2149         log_info("%s %d %p",__FILE__, __LINE__, binding);
2150     }
2151     else
2152     {
2153         /* use dynamic pool */
2154         /* If an address is available, the new address SHOULD be chosen as follows: */
2155         binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr,request->hdr.hlen, DYNAMIC, EMPTY);
2156
2157         if (binding)
2158         {
2159             /* The client's current address as recorded in the client's current
2160                binding, ELSE */
2161
2162             /* The client's previous address as recorded in the client's (now
2163                expired or released) binding, if that address is in the server's
2164                pool of available addresses and not already allocated, ELSE */
2165             log_info("%s %d %p",__FILE__, __LINE__, binding);
2166         }
2167         else
2168         {
2169             /* The address requested in the 'Requested IP Address' option, if that
2170                address is valid and not already allocated, ELSE */
2171
2172             /* A new address allocated from the server's pool of available
2173                addresses; the address is selected based on the subnet from which
2174                the message was received (if 'giaddr' is 0) or on the address of
2175                the relay agent that forwarded the message ('giaddr' when not 0). */
2176
2177             /* extract requested IP address */
2178             uint32_t address = 0;
2179             dhcp_option *address_opt = dhcp_option_search(&request->opts, REQUESTED_IP_ADDRESS);
2180
2181             if (address_opt != NULL)
2182                 memcpy(&address, address_opt->data, sizeof(address));
2183
2184             binding = dhcp_binding_new_dynamic(&dhcp_address_pool.bindings, &dhcp_address_pool.indexes, address, request->hdr.chaddr, request->hdr.hlen);
2185
2186             if (binding == NULL)
2187             {
2188                 log_info("Can not offer an address, no address available.");
2189                 return 0;
2190             }
2191         }
2192     }
2193
2194     if (binding->binding_time + binding->lease_time < time(NULL))
2195     {
2196         log_info("%s %d %p",__FILE__, __LINE__, binding);
2197         binding->status = PENDING;
2198         binding->binding_time = time(NULL);
2199         binding->lease_time = dhcp_address_pool.pending_time;
2200     }
2201
2202     return dhcp_reply_fill(request, reply, binding, DHCPS_OFFER);
2203 }
2204
2205 static int
2206 dhcp_request (dhcps_msg *request, dhcps_msg *reply)
2207 {
2208     address_binding *binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, PENDING);
2209
2210     uint32_t server_id = 0;
2211     dhcp_option *server_id_opt = dhcp_option_search(&request->opts, SERVER_IDENTIFIER);
2212
2213     if (server_id_opt != NULL)
2214         memcpy(&server_id, server_id_opt->data, sizeof(server_id));
2215
2216     if (server_id == dhcp_address_pool.server_id)
2217     {
2218         /* this request is an answer to our offer */
2219         if (binding != NULL)
2220         {
2221             log_info("Ack, associated");
2222
2223             binding->status = ASSOCIATED;
2224             binding->lease_time = dhcp_address_pool.lease_time;
2225
2226             return dhcp_reply_fill(request, reply, binding, DHCPS_ACK);
2227         }
2228         else
2229         {
2230             log_info("Nak, not associated");
2231
2232             return dhcp_reply_fill(request, reply, NULL, DHCPS_NAK);
2233         }
2234
2235     }
2236     else if (server_id != 0)
2237     {
2238         /* this request is an answer to another offer */
2239         
2240         binding->status = EMPTY;
2241         binding->lease_time = 0;
2242
2243         return 0;
2244     }
2245
2246     return 0;
2247 }
2248
2249 static int
2250 dhcp_decline (dhcps_msg *request, dhcps_msg *reply)
2251 {
2252     address_binding *binding = NULL;
2253     binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, PENDING);
2254     if(binding != NULL)
2255     {
2256         binding->status = EMPTY;
2257     }
2258
2259     return 0;
2260 }
2261
2262 static int
2263 dhcp_release (dhcps_msg *request, dhcps_msg *reply)
2264 {
2265     address_binding *binding = NULL;
2266     binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, ASSOCIATED);
2267     if(binding != NULL)
2268     {
2269         binding->status = RELEASED;
2270     }
2271
2272     return 0;
2273 }
2274
2275 static int
2276 dhcp_inform (dhcps_msg *request, dhcps_msg *reply)
2277 {
2278     return dhcp_reply_fill(request, reply, NULL, DHCPS_ACK);
2279 }
2280
2281 /**
2282  * If an incoming DHCP message is in response to us, then trigger the state machine.
2283  *
2284  * Dispatch client DHCP messages to the correct handling routines
2285  *
2286  */
2287 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2288 {
2289     struct netif *netif = ip_current_input_netif();
2290
2291     struct pbuf *pthis = NULL;
2292
2293     LWIP_UNUSED_ARG(arg);
2294     LWIP_ASSERT("invalid server address type", !IP_IS_V6(addr));
2295     /* prevent warnings about unused arguments */
2296     LWIP_UNUSED_ARG(pcb);
2297     LWIP_UNUSED_ARG(addr);
2298     LWIP_UNUSED_ARG(port);
2299     uint8_t type = 0;
2300     dhcps_msg *request = calloc(1, sizeof(dhcps_msg));
2301     REQUIRE_ACTION(request, free_pbuf_and_return, 0);
2302     dhcps_msg *reply = calloc(1, sizeof(dhcps_msg));
2303     REQUIRE_ACTION(reply, free_pbuf_and_return, 0);
2304     size_t len = 0;
2305     len = pbuf_copy_partial(p, &request->hdr, p->tot_len, 0);
2306     if (len < DHCP_HEADER_SIZE + 5)
2307     {
2308         goto free_pbuf_and_return;
2309     }
2310     else
2311     {
2312         if (request->hdr.op != BOOTREQUEST)
2313         {
2314             goto free_pbuf_and_return;
2315         }
2316         else
2317         {
2318             type = dhcp_request_expand(request, len);
2319             dhcp_reply_init(request, reply);
2320             switch (type)
2321             {
2322                 case DHCPS_DISCOVER:
2323                     type = dhcp_discover(request, reply);
2324                     break;
2325
2326                 case DHCPS_REQUEST:
2327                     type = dhcp_request(request, reply);
2328                     break;
2329
2330                 case DHCPS_DECLINE:
2331                     type = dhcp_decline(request, reply);
2332                     break;
2333
2334                 case DHCPS_RELEASE:
2335                     type = dhcp_release(request, reply);
2336                     break;
2337
2338                 case DHCPS_INFORM:
2339                     type = dhcp_inform(request, reply);
2340                     break;
2341
2342                 default:
2343                     log_info("%s.%u: request with invalid DHCP message type option",inet_ntoa(addr), port);
2344                     break;
2345             }
2346
2347             if (type != DHCP_NONE)
2348                 dhcp_reply_send(pcb, (ip_addr_t *)addr, reply);
2349
2350             dhcp_option_list_delete(&request->opts);
2351             dhcp_option_list_delete(&reply->opts);
2352         }
2353     }
2354
2355 free_pbuf_and_return:
2356     if (request != NULL)
2357         free(request);
2358
2359     if (reply != NULL)
2360         free(reply);
2361     pbuf_free(p);
2362 }
2363
2364 void dhcps_set_default_option(struct dhcps_lease *pool_addr)
2365 {
2366     ip4_addr_t server_ip, broadcast, dns;
2367     REQUIRE_ASSERT(pool_addr);
2368         address_pool *dhcps_addr_pool = &dhcp_address_pool; 
2369
2370         if (dhcps_addr_pool->flags){
2371         
2372         } else{
2373                 dhcp_option_list_init(&dhcps_addr_pool->options);
2374                 dhcps_addr_pool->flags = true;
2375         }
2376
2377         /* Load configuration */
2378     dhcps_option_set(IP_ADDRESS_LEASE_TIME, "36000");
2379     dhcps_option_set(SUBNET_MASK, inet_ntoa(pool_addr->net_mask));
2380
2381     server_ip.addr = dhcps_addr_pool->server_id;
2382     dhcps_option_set(ROUTER, inet_ntoa(server_ip));
2383
2384     broadcast.addr = server_ip.addr | ~(pool_addr->net_mask.addr);
2385     dhcps_option_set(BROADCAST_ADDRESS,inet_ntoa(broadcast));
2386
2387     dns.addr = DHCP_SERVER_OPENDNS;
2388     dhcps_option_set(DOMAIN_NAME_SERVER, inet_ntoa(dns));
2389 }
2390
2391 static void dhcps_set_default_binding(address_pool *pool_addr)
2392 {
2393         REQUIRE_ASSERT(pool_addr);
2394         dhcp_binding_list_init(&pool_addr->bindings);
2395 }
2396
2397 static address_pool* dhcps_try_open_socket(address_pool *pool_addr)
2398 {
2399     REQUIRE_ASSERT(pool_addr);
2400     pool_addr->socket = udp_new();
2401     REQUIRE_ASSERT(pool_addr->socket);
2402     udp_bind(pool_addr->socket, IP_ADDR_ANY, BOOTPS);
2403     udp_recv(pool_addr->socket, dhcp_recv, pool_addr);
2404     return pool_addr;
2405 }
2406
2407 void dhcps_start(struct netif *netif, struct dhcps_lease *lease_pool)
2408 {
2409     REQUIRE_ASSERT(netif);
2410     REQUIRE_ASSERT(lease_pool);
2411         
2412         dhcp_address_pool.server_id = netif->ip_addr.u_addr.ip4.addr;           
2413     dhcps_set_default_time();
2414         dhcps_set_default_binding(&dhcp_address_pool);
2415     dhcps_set_default_option(lease_pool);    
2416     dhcps_try_open_socket(&dhcp_address_pool);
2417 }
2418
2419 void dhcps_stop(struct netif *netif )
2420 {
2421     dhcp_binding_list_delete(&dhcp_address_pool.bindings);
2422     dhcp_option_list_delete(&dhcp_address_pool.options);
2423     udp_remove(dhcp_address_pool.socket);
2424         dhcp_address_pool.flags = false;
2425 //      memset(&dhcp_address_pool, 0, sizeof(address_pool));
2426 }
2427
2428 bool dhcps_lease_set(struct dhcps_lease *please)
2429 {    
2430         REQUIRE_ASSERT(please);
2431                 
2432     dhcp_address_pool.indexes.first   = please->start_ip.addr;
2433     dhcp_address_pool.indexes.last    = please->end_ip.addr;
2434     dhcp_address_pool.indexes.current = please->start_ip.addr;
2435     
2436     return true;
2437 }
2438
2439 bool dhcps_lease_get(struct dhcps_lease *please)
2440 {
2441         REQUIRE_ASSERT(please);
2442         please->start_ip.addr = dhcp_address_pool.indexes.first;
2443     please->end_ip.addr = dhcp_address_pool.indexes.last;
2444     please->net_mask.addr = inet_addr("255.255.255.0");
2445         return true;
2446 }
2447
2448 bool dhcps_option_set(u8_t opt_id, void* optarg)
2449 {
2450         if (dhcp_address_pool.flags){
2451                 dhcp_option *opt = dhcp_option_search(&dhcp_address_pool.options, opt_id);
2452             if (opt)
2453             {
2454                 opt->len = strlen(optarg);
2455                 memset(opt->data, 0, sizeof(opt->data));
2456                 memcpy(opt->data, optarg, opt->len);
2457                 return true;
2458             }
2459             else
2460             {
2461                 return dhcp_options_add(dhcp_option_info[opt_id].name, optarg);
2462             }
2463         } else{
2464                 dhcp_option_list_init(&dhcp_address_pool.options);
2465                 dhcp_address_pool.flags = true;
2466                 return dhcp_options_add(dhcp_option_info[opt_id].name, optarg);
2467         }   
2468 }
2469
2470 bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please)
2471 {
2472     return false;
2473 }
2474
2475 bool wifi_softap_set_dhcps_lease_time(u32_t minute)
2476 {
2477     return false;
2478 }
2479
2480 #endif   /*ifdef  LWIP_ESP8266*/
2481
2482
2483
2484
2485