1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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"
17 #include "lwip/inet.h"
19 #include "lwip/pbuf.h"
22 #include "lwip/ip_addr.h"
23 #include "apps/dhcpserver.h"
25 #include "tcpip_adapter.h"
33 } DhcpsFlags = DHCPS_STOP;
35 #define DHCPS_MAX_LEASE 0x64
36 #define BOOTP_BROADCAST 0x8000
38 #define DHCP_REQUEST 1
40 #define DHCP_HTYPE_ETHERNET 1
41 #define DHCP_HLEN_ETHERNET 6
42 #define DHCP_MSG_LEN 236
44 #define DHCPS_SERVER_PORT 67
45 #define DHCPS_CLIENT_PORT 68
47 #define DHCPDISCOVER 1
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
68 //#define USE_CLASS_B_NET 1
70 #define DHCPS_LOG printf
72 #define DYC_DHCP_CRASH //os_printf
75 #define MAX_STATION_NUM 8
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
87 static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
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;
102 IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4)
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;
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
122 static enum dyc_dhcps_flags get_dhcps_status(void )
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
131 *******************************************************************************/
132 void node_insert_to_list(list_node **phead, list_node* pinsert)
134 list_node *plist = NULL;
135 struct dhcps_pool *pdhcps_pool = NULL;
136 struct dhcps_pool *pdhcps_node = NULL;
141 pdhcps_node = pinsert->pnode;
142 pdhcps_pool = plist->pnode;
144 if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
145 pinsert->pnext = plist;
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;
155 plist = plist->pnext;
158 if(plist->pnext == NULL) {
159 plist->pnext = pinsert;
163 // pinsert->pnext = NULL;
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
171 *******************************************************************************/
172 void node_remove_from_list(list_node **phead, list_node* pdelete)
174 list_node *plist = NULL;
180 if (plist == pdelete){
181 *phead = plist->pnext;
182 pdelete->pnext = NULL;
184 while (plist != NULL) {
185 if (plist->pnext == pdelete){
186 plist->pnext = pdelete->pnext;
187 pdelete->pnext = NULL;
189 plist = plist->pnext;
194 ///////////////////////////////////////////////////////////////////////////////////
196 * ��DHCP msg��Ϣ�ṹ����������
198 * @param optptr -- DHCP msg��Ϣλ��
199 * @param type -- Ҫ��ӵ�����option
201 * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
203 ///////////////////////////////////////////////////////////////////////////////////
204 static u8_t* add_msg_type(u8_t *optptr, u8_t type)
206 *optptr++ = DHCP_OPTION_MSG_TYPE;
211 ///////////////////////////////////////////////////////////////////////////////////
213 * ��DHCP msg�ṹ������offerӦ������
215 * @param optptr -- DHCP msg��Ϣλ��
217 * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
219 ///////////////////////////////////////////////////////////////////////////////////
220 static u8_t* add_offer_options(u8_t *optptr)
224 ipadd.addr = *( (u32_t *) &server_address);
226 #ifdef USE_CLASS_B_NET
227 *optptr++ = DHCP_OPTION_SUBNET_MASK;
228 *optptr++ = 4; //length
234 *optptr++ = DHCP_OPTION_SUBNET_MASK;
242 *optptr++ = DHCP_OPTION_LEASE_TIME;
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;
249 *optptr++ = DHCP_OPTION_SERVER_ID;
251 *optptr++ = ip4_addr1( &ipadd);
252 *optptr++ = ip4_addr2( &ipadd);
253 *optptr++ = ip4_addr3( &ipadd);
254 *optptr++ = ip4_addr4( &ipadd);
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));
261 tcpip_adapter_get_ip_info(WIFI_IF_AP, &if_ip);
263 *optptr++ = DHCP_OPTION_ROUTER;
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);
272 *optptr++ = DHCP_OPTION_DNS_SERVER;
274 *optptr++ = ip4_addr1( &ipadd);
275 *optptr++ = ip4_addr2( &ipadd);
276 *optptr++ = ip4_addr3( &ipadd);
277 *optptr++ = ip4_addr4( &ipadd);
281 *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
283 *optptr++ = ip4_addr1( &ipadd);
288 *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
290 *optptr++ = ip4_addr1( &ipadd);
291 *optptr++ = ip4_addr2( &ipadd);
292 *optptr++ = ip4_addr3( &ipadd);
296 *optptr++ = DHCP_OPTION_INTERFACE_MTU;
306 *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;
322 ///////////////////////////////////////////////////////////////////////////////////
324 * ��DHCP msg�ṹ����ӽ����־����
326 * @param optptr -- DHCP msg��Ϣλ��
328 * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ
330 ///////////////////////////////////////////////////////////////////////////////////
331 static u8_t* add_end(u8_t *optptr)
334 *optptr++ = DHCP_OPTION_END;
337 ///////////////////////////////////////////////////////////////////////////////////
338 ///////////////////////////////////////////////////////////////////////////////////
339 static void create_msg(struct dhcps_msg *m)
344 client.addr = *( (uint32_t *) &client_address);
348 m->htype = DHCP_HTYPE_ETHERNET;
353 // os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid));
355 m->flags = htons(BOOTP_BROADCAST);
357 memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr));
359 memset((char *) m->ciaddr, 0, sizeof(m->ciaddr));
361 memset((char *) m->siaddr, 0, sizeof(m->siaddr));
363 memset((char *) m->giaddr, 0, sizeof(m->giaddr));
365 memset((char *) m->sname, 0, sizeof(m->sname));
367 memset((char *) m->file, 0, sizeof(m->file));
369 memset((char *) m->options, 0, sizeof(m->options));
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]);
375 u32_t magic_cookie_temp = magic_cookie;
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);
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,");
385 ///////////////////////////////////////////////////////////////////////////////////
389 * @param -- m ָ����Ҫ���͵�DHCP msg����
391 ///////////////////////////////////////////////////////////////////////////////////
392 static void send_offer(struct dhcps_msg *m)
399 err_t SendOffer_err_t;
402 end = add_msg_type(&m->options[4], DHCPOFFER);
403 end = add_offer_options(end);
406 p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
408 DHCPS_LOG("udhcp: send_offer>>p->ref = %d\n", p->ref);
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);
419 data = (u8_t *)q->payload;
420 for(i=0; i<q->len; i++)
422 data[i] = ((u8_t *) m)[cnt++];
424 DHCPS_LOG("%02x ",data[i]);
436 DHCPS_LOG("dhcps: send_offer>>pbuf_alloc failed\n");
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 );
445 DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n",SendOffer_err_t);
449 DHCPS_LOG("udhcp: send_offer>>free pbuf\n");
454 ///////////////////////////////////////////////////////////////////////////////////
458 * @param m ָ����Ҫ���͵�DHCP msg����
460 ///////////////////////////////////////////////////////////////////////////////////
461 static void send_nak(struct dhcps_msg *m)
471 end = add_msg_type(&m->options[4], DHCPNAK);
474 p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
476 DHCPS_LOG("udhcp: send_nak>>p->ref = %d\n", p->ref);
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);
487 data = (u8_t *)q->payload;
488 for(i=0; i<q->len; i++)
490 data[i] = ((u8_t *) m)[cnt++];
492 DHCPS_LOG("%02x ",data[i]);
504 DHCPS_LOG("dhcps: send_nak>>pbuf_alloc failed\n");
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 );
513 DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n",SendNak_err_t);
517 DHCPS_LOG("udhcp: send_nak>>free pbuf\n");
522 ///////////////////////////////////////////////////////////////////////////////////
524 * ����һ��ACK��DHCP�ͻ���
526 * @param m ָ����Ҫ���͵�DHCP msg����
528 ///////////////////////////////////////////////////////////////////////////////////
529 static void send_ack(struct dhcps_msg *m)
539 end = add_msg_type(&m->options[4], DHCPACK);
540 end = add_offer_options(end);
543 p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
545 DHCPS_LOG("udhcp: send_ack>>p->ref = %d\n", p->ref);
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);
556 data = (u8_t *)q->payload;
557 for(i=0; i<q->len; i++)
559 data[i] = ((u8_t *) m)[cnt++];
561 DHCPS_LOG("%02x ",data[i]);
573 DHCPS_LOG("dhcps: send_ack>>pbuf_alloc failed\n");
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 );
582 DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t);
587 DHCPS_LOG("udhcp: send_ack>>free pbuf\n");
592 ///////////////////////////////////////////////////////////////////////////////////
594 * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ��
596 * @param optptr DHCP msg���������
597 * @param len ��������Ĵ��?(byte)
599 * @return uint8_t ���ش�����DHCP Server״ֵ̬
601 ///////////////////////////////////////////////////////////////////////////////////
602 static u8_t parse_options(u8_t *optptr, s16_t len)
605 bool is_dhcp_parse_end = false;
606 struct dhcps_state s;
608 client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP
610 u8_t *end = optptr + len;
613 s.state = DHCPS_STATE_IDLE;
615 while (optptr < end) {
617 DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr);
619 switch ((s16_t) *optptr) {
621 case DHCP_OPTION_MSG_TYPE: //53
622 type = *(optptr + 2);
625 case DHCP_OPTION_REQ_IPADDR://50
626 if( memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) {
628 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n");
630 s.state = DHCPS_STATE_ACK;
633 DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n");
635 s.state = DHCPS_STATE_NAK;
638 case DHCP_OPTION_END:
640 is_dhcp_parse_end = true;
645 if(is_dhcp_parse_end){
649 optptr += optptr[1] + 2;
654 case DHCPDISCOVER://1
655 s.state = DHCPS_STATE_OFFER;
657 DHCPS_LOG("dhcps: DHCPD_STATE_OFFER\n");
662 if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) {
664 s.state = DHCPS_STATE_ACK;
666 s.state = DHCPS_STATE_NAK;
669 DHCPS_LOG("dhcps: DHCPD_STATE_NAK\n");
675 s.state = DHCPS_STATE_IDLE;
677 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
682 s.state = DHCPS_STATE_RELEASE;
684 DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
689 DHCPS_LOG("dhcps: return s.state = %d\n", s.state);
693 ///////////////////////////////////////////////////////////////////////////////////
694 ///////////////////////////////////////////////////////////////////////////////////
695 static s16_t parse_msg(struct dhcps_msg *m, u16_t len)
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);
703 if(memcmp((char *)m->options,
705 sizeof(magic_cookie)) == 0){
707 DHCPS_LOG("dhcps: len = %d\n", len);
711 // memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid));
713 struct dhcps_pool *pdhcps_pool = NULL;
714 list_node *pnode = NULL;
715 list_node *pback_node = NULL;
716 ip4_addr_t first_address;
720 first_address.addr = dhcps_lease.start_ip.addr;
721 client_address.addr = client_address_plus.addr;
723 // addr_tmp.addr = htonl(client_address_plus.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) {
733 client_address.addr = pdhcps_pool->ip.addr;
734 pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER;
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);
742 client_address_plus.addr = htonl(addr_tmp.addr);
743 client_address.addr = client_address_plus.addr;
746 if(flag == false) { // search the fisrt unused ip
747 if(first_address.addr < pdhcps_pool->ip.addr) {
750 addr_tmp.addr = htonl(first_address.addr);
752 first_address.addr = htonl(addr_tmp.addr);
756 if (client_address_plus.addr > dhcps_lease.end_ip.addr) {
757 client_address.addr = first_address.addr;
759 if (client_address.addr > dhcps_lease.end_ip.addr) {
760 client_address_plus.addr = dhcps_lease.start_ip.addr;
764 pdhcps_pool = (struct dhcps_pool *)malloc(sizeof(struct dhcps_pool));
765 memset(pdhcps_pool ,0x00 ,sizeof(struct dhcps_pool));
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));
773 pnode->pnode = pdhcps_pool;
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;
779 addr_tmp.addr = htonl(client_address.addr);
781 client_address_plus.addr = htonl(addr_tmp.addr);
786 if ((client_address.addr > dhcps_lease.end_ip.addr) || (ip4_addr_isany(&client_address))){
788 node_remove_from_list(&plist,pnode);
793 if (pdhcps_pool != NULL) {
797 // client_address_plus.addr = dhcps_lease.start_ip.addr;
801 s16_t ret = parse_options(&m->options[4], len);;
803 if(ret == DHCPS_STATE_RELEASE) {
805 node_remove_from_list(&plist,pnode);
810 if (pdhcps_pool != NULL) {
814 memset(&client_address,0x0,sizeof(client_address));
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 )
820 //if (wifi_softap_set_station_info(m->chaddr, &client_address) == false) {
824 DHCPS_LOG("dhcps: xid changed\n");
825 DHCPS_LOG("dhcps: client_address.addr = %x\n", client_address.addr);
833 static void handle_dhcp(void *arg,
836 const ip_addr_t *addr,
839 struct dhcps_msg *pmsg_dhcps = NULL;
842 u16_t dhcps_msg_cnt=0;
843 u8_t *p_dhcps_msg = NULL;
847 DHCPS_LOG("dhcps: handle_dhcp-> receive a packet\n");
851 pmsg_dhcps = (struct dhcps_msg *)malloc(sizeof(struct dhcps_msg));
852 memset(pmsg_dhcps ,0x00 ,sizeof(struct dhcps_msg));
854 if (NULL == pmsg_dhcps){
858 p_dhcps_msg = (u8_t *)pmsg_dhcps;
863 DHCPS_LOG("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen);
864 DHCPS_LOG("dhcps: handle_dhcp-> p->len = %d\n", p->len);
867 for(i=0; i<p->len; i++){
868 p_dhcps_msg[dhcps_msg_cnt++] = data[i];
870 DHCPS_LOG("%02x ",data[i]);
877 if(p->next != NULL) {
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);
884 data = p->next->payload;
885 for(i=0; i<p->next->len; i++){
886 p_dhcps_msg[dhcps_msg_cnt++] = data[i];
888 DHCPS_LOG("%02x ",data[i]);
897 * DHCP �ͻ���������Ϣ����
900 DHCPS_LOG("dhcps: handle_dhcp-> parse_msg(p)\n");
903 switch(parse_msg(pmsg_dhcps, tlen - 240)) {
904 case DHCPS_STATE_OFFER://1
906 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n");
908 send_offer(pmsg_dhcps);
910 case DHCPS_STATE_ACK://3
912 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n");
914 send_ack(pmsg_dhcps);
916 case DHCPS_STATE_NAK://4
918 DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n");
920 send_nak(pmsg_dhcps);
926 DHCPS_LOG("dhcps: handle_dhcp-> pbuf_free(p)\n");
932 ///////////////////////////////////////////////////////////////////////////////////
933 static void wifi_softap_init_dhcps_lease(u32_t ip)
935 u32_t softap_ip = 0,local_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;
946 /*config ip information must be in the same segment as the local ip*/
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;
955 if (dhcps_lease.enable == false) {
956 local_ip = softap_ip = htonl(ip);
957 softap_ip &= 0xFFFFFF00;
959 if (local_ip >= 0x80)
960 local_ip -= DHCPS_MAX_LEASE;
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);
970 // os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip);
974 ///////////////////////////////////////////////////////////////////////////////////
975 void dhcps_start(struct netif *netif)
977 struct netif * apnetif =netif;
980 if(apnetif->dhcps_pcb != NULL) {
981 udp_remove(apnetif->dhcps_pcb);
983 pcb_dhcps = udp_new();
984 if (pcb_dhcps == NULL) {
985 printf("dhcps_start(): could not obtain pcb\n");
987 apnetif->dhcps_pcb = pcb_dhcps;
989 IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255);
991 server_address = netif->ip_addr.u_addr.ip4;
992 wifi_softap_init_dhcps_lease( server_address.addr );
994 client_address_plus.addr = dhcps_lease.start_ip.addr;
996 udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT);
997 udp_recv(pcb_dhcps, handle_dhcp, NULL);
999 DHCPS_LOG("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n");
1001 DhcpsFlags = DHCPS_STARTED;
1005 void dhcps_stop(struct netif *netif )
1007 struct netif * apnetif = netif;
1010 printf("dhcps_stop: apnetif == NULL\n");
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;
1020 list_node *pnode = NULL;
1021 list_node *pback_node = NULL;
1023 while (pnode != NULL) {
1025 pnode = pback_node->pnext;
1026 node_remove_from_list(&plist, pback_node);
1027 free(pback_node->pnode);
1028 pback_node->pnode = NULL;
1032 DhcpsFlags = DHCPS_STOP;
1035 bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please)
1039 struct ip_info info;
1040 u32_t softap_ip = 0;
1044 //uint8 opmode = wifi_get_opmode();
1046 //if (opmode == STATION_MODE || opmode == NULL_MODE) {
1049 if (please == NULL || get_dhcps_status() == DHCPS_STARTED)
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);
1057 softap_ip = htonl(info.ip.addr);
1058 start_ip = htonl(please->start_ip.addr);
1059 end_ip = htonl(please->end_ip.addr);
1061 /*config ip information can't contain local ip*/
1062 if ((start_ip <= softap_ip) && (softap_ip <= end_ip))
1065 /*config ip information must be in the same segment as the local ip*/
1067 if ((start_ip >> 8 != softap_ip)
1068 || (end_ip >> 8 != softap_ip)) {
1072 if (end_ip - start_ip > DHCPS_MAX_LEASE)
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;
1081 dhcps_lease.enable = please->enable;
1082 // dhcps_lease_flag = false;
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,
1091 * Returns : true or false
1092 *******************************************************************************/
1093 bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please)
1098 if (dhcps_lease.enable == false){
1099 if (get_dhcps_status() == DHCPS_STOP)
1104 please->start_ip.addr = dhcps_lease.start_ip.addr;
1105 please->end_ip.addr = dhcps_lease.end_ip.addr;
1109 static void kill_oldest_dhcps_pool(void)
1111 list_node *pre = NULL, *p = NULL;
1112 list_node *minpre = NULL, *minp = NULL;
1113 struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL;
1119 pdhcps_pool = p->pnode;
1120 pmin_pool = minp->pnode;
1121 if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){
1128 minpre->pnext = minp->pnext;
1135 void dhcps_coarse_tmr(void)
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;
1142 while (pnode != NULL) {
1143 pdhcps_pool = pnode->pnode;
1144 pdhcps_pool->lease_timer --;
1145 if (pdhcps_pool->lease_timer == 0){
1147 pnode = pback_node->pnext;
1148 node_remove_from_list(&plist,pback_node);
1149 free(pback_node->pnode);
1150 pback_node->pnode = NULL;
1154 pnode = pnode ->pnext;
1159 if (num_dhcps_pool >= MAX_STATION_NUM)
1160 kill_oldest_dhcps_pool();
1163 bool wifi_softap_set_dhcps_offer_option(u8_t level, void* optarg)
1165 bool offer_flag = true;
1168 if (optarg == NULL && get_dhcps_status() == false)
1171 if (level <= OFFER_START || level >= OFFER_END)
1176 offer = (*(u8_t *)optarg) & 0x01;
1186 bool wifi_softap_set_dhcps_lease_time(u32_t minute)
1189 if (get_dhcps_status() == DHCPS_STARTED) {
1196 dhcps_lease_time = minute;
1200 bool wifi_softap_reset_dhcps_lease_time(void)
1203 if (get_dhcps_status() == DHCPS_STARTED) {
1206 dhcps_lease_time = DHCPS_LEASE_TIME_DEF;
1210 u32_t wifi_softap_get_dhcps_lease_time(void) // minute
1212 return dhcps_lease_time;
1216 #include <sys/types.h>
1217 #include <sys/socket.h>
1218 #include "lwip/sys.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;
1225 void micros_overflow_tick(void* arg)
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;
1233 unsigned long millis()
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;
1240 unsigned long micros()
1242 return system_get_time();
1245 void dhcps_set_default_time(void)
1247 os_timer_disarm(µs_overflow_timer);
1248 os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
1249 os_timer_arm(µs_overflow_timer, 60000, 1);
1252 time_t time(time_t * t)
1254 time_t seconds = millis();
1263 * Initialize the binding list.
1267 dhcp_binding_list_init (binding_list *list)
1273 * Create a new binding
1275 * The binding is added to the binding list,
1276 * and a pointer to the binding is returned for further manipulations.
1280 dhcp_binding_add (binding_list *list, uint32_t address, uint8_t *cident, uint8_t cident_len, int is_static)
1283 address_binding *binding = calloc(1, sizeof(*binding));
1285 binding->address = address;
1286 binding->cident_len = cident_len;
1287 memcpy(binding->cident, cident, cident_len);
1289 binding->is_static = is_static;
1291 // add to binding list
1292 STAILQ_INSERT_HEAD(list, binding, pointers);
1298 * Updated bindings status, i.e. set to EXPIRED the status of the
1303 dhcp_binding_statuses_update (binding_list *list)
1305 address_binding *binding, *binding_temp;
1307 STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1309 if(binding->binding_time + binding->lease_time < time(NULL))
1311 binding->status = EXPIRED;
1317 * Search a static or dynamic binding having the given client identifier.
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.
1325 dhcp_binding_search (binding_list *list, uint8_t *cident, uint8_t cident_len, int is_static, int status)
1327 address_binding *binding, *binding_temp;
1329 STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
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)
1337 else if(status == binding->status)
1346 * Get an available free address
1348 * If a zero address is returned, no more address are available.
1352 dhcp_binding_take_free_address (pool_indexes *indexes)
1354 if(indexes->current <= indexes->last)
1356 uint32_t address = indexes->current;
1357 indexes->current = htonl(ntohl(indexes->current) + 1);
1366 * Create a new dynamic binding or reuse an expired one.
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.
1372 * If the dynamic pool of addresses is full a NULL pointer will be returned.
1376 dhcp_binding_new_dynamic (binding_list *list, pool_indexes *indexes, uint32_t address, uint8_t *cident, uint8_t cident_len)
1378 address_binding *binding, *binding_temp;
1379 address_binding *found_binding = NULL;
1384 STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1386 // search a previous binding using the requested IP address
1388 if(binding->address == address)
1390 found_binding = binding;
1396 if(found_binding != NULL &&
1397 !found_binding->is_static &&
1398 found_binding->status != PENDING &&
1399 found_binding->status != ASSOCIATED)
1402 // the requested IP address is available (reuse an expired association)
1403 return found_binding;
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!). */
1414 uint32_t address = dhcp_binding_take_free_address(indexes);
1417 return dhcp_binding_add(list, address, cident, cident_len, 0);
1419 else // search any previously assigned address which is expired
1422 STAILQ_FOREACH_SAFE(binding, list, pointers, binding_temp)
1424 if(!binding->is_static &&
1425 found_binding->status != PENDING &&
1426 found_binding->status != ASSOCIATED)
1430 // if executions reach here no more addresses are available
1437 * Delete an binding list and deallocate its memory.
1438 * Deallocate even the list elements.
1442 dhcp_binding_list_delete (binding_list *list)
1444 address_binding *opt = STAILQ_FIRST(list);
1445 address_binding *tmp;
1449 tmp = STAILQ_NEXT(opt, pointers);
1457 /* Value parsing functions:
1459 * Parse the string pointed by s, and allocate the
1460 * pointer p to contain the parsed data.
1462 * On success return the size of the parsed data,
1463 * on error return zero.
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);
1476 static const uint8_t dhcp_option_magic[4] = {0x63, 0x82, 0x53, 0x63};
1477 static address_pool dhcp_address_pool = {0};
1480 * Mapping table between DHCP options and
1481 * functions that parse their value.
1486 int (*f) (char *, void **);
1487 } dhcp_option_info [256] =
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 },
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 },
1582 /* Value parsing functions */
1585 dhcp_option_byte (char *s, void **p)
1587 *p = malloc(sizeof(uint8_t));
1588 uint8_t n = ((uint8_t) strtol(s, NULL, 0));
1589 memcpy(*p, &n, sizeof(n));
1591 return sizeof(uint8_t);
1595 dhcp_option_byte_list (char *s, void **p)
1597 *p = malloc(strlen(s) * sizeof(uint8_t)); // slightly over the strictly requested size
1601 char *s2 = strdup(s);
1602 char *s3 = strtok(s2, ", ");
1607 uint8_t n = ((uint8_t) strtol(s3, NULL, 0));
1609 memcpy(((uint8_t *) *p) + count, &n, sizeof(uint8_t));
1611 count += sizeof(uint8_t);
1612 s3 = strtok(NULL, " ");
1621 dhcp_option_short (char *s, void **p)
1623 *p = malloc(sizeof(uint16_t));
1624 uint16_t n = ((uint16_t) strtol(s, NULL, 0));
1625 memcpy(*p, &n, sizeof(n));
1627 return sizeof(uint16_t);
1631 dhcp_option_short_list (char *s, void **p)
1633 *p = malloc(strlen(s) * sizeof(uint16_t)); // slightly over the strictly requested size
1637 char *s2 = strdup(s);
1638 char *s3 = strtok(s2, ", ");
1643 uint16_t n = ((uint16_t) strtol(s3, NULL, 0));
1645 memcpy(((uint8_t *) *p) + count, &n, sizeof(uint16_t));
1647 count += sizeof(uint16_t);
1648 s3 = strtok(NULL, " ");
1657 dhcp_option_long (char *s, void **p)
1659 *p = malloc(sizeof(uint32_t));
1660 uint32_t n = strtol(s, NULL, 0);
1661 memcpy(*p, &n, sizeof(n));
1663 return sizeof(uint32_t);
1667 dhcp_option_string (char *s, void **p)
1675 dhcp_option_ip (char *s, void **p)
1677 struct sockaddr_in ip;
1679 *p = malloc(sizeof(uint32_t));
1681 if (inet_aton(s, &ip.sin_addr) == 0) // error: invalid IP address
1687 memcpy(*p, &ip.sin_addr, sizeof(uint32_t));
1689 return sizeof(uint32_t);
1693 dhcp_option_ip_list (char *s, void **p)
1695 *p = malloc(strlen(s) * sizeof(uint32_t) / 4); // slightly over the strictly required size
1699 char *s2 = strdup(s);
1700 char *s3 = strtok(s2, ", ");
1704 struct sockaddr_in ip;
1706 if (inet_aton(s3, &ip.sin_addr) == 0) // error: invalid IP address
1712 memcpy(((uint8_t *) *p) + count, &ip.sin_addr, sizeof(uint32_t));
1714 count += sizeof(uint32_t);
1715 s3 = strtok(NULL, " ");
1723 /* Option-related functions */
1726 * Given the name of the option and its value as strings,
1727 * fill the dhcp_option structure pointed by opt.
1729 * On success return the parsed option id,
1730 * otherwise return zero.
1733 dhcp_option_parse (dhcp_option *opt, char *name, char *value)
1735 int (*f) (char *, void **);
1741 for (id = 0; id < 256; id++) // search the option by name
1743 if (dhcp_option_info[id].name &&
1744 strcmp(dhcp_option_info[id].name, name) == 0) break;
1747 if (id == 256) // not found
1749 log_info("Unsupported DHCP option '%s'", name);
1753 f = dhcp_option_info[id].f;
1755 if (f == NULL) // no parsing function available
1757 log_info("Unsupported DHCP option '%s'", name);
1761 len = f(value, (void **)&p); // parse the value
1763 if(len == 0) // error parsing the value
1766 // structure filling
1769 memcpy(opt->data, p, len);
1777 * Initialize an option list.
1781 dhcp_option_list_init (dhcp_option_list *list)
1787 * Given a list of options search an option having
1788 * the passed option id, and returns a pointer to it.
1790 * If the option is not present the function returns NULL.
1793 static dhcp_option *
1794 dhcp_option_search (dhcp_option_list *list, uint8_t id)
1796 dhcp_option *opt, *opt_temp;
1798 STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1810 * Print options in list.
1814 dhcp_option_print (dhcp_option_list *list)
1816 dhcp_option *opt, *opt_temp;
1819 STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1822 printf("options[%d]=%d (%s)\n", i++, opt->id,
1823 dhcp_option_info[opt->id].name);
1830 * Append the provided option to the list.
1832 * Always allocate new memory, that must be freed later...
1836 dhcp_option_append (dhcp_option_list *list, dhcp_option *opt)
1838 dhcp_option *nopt = calloc(1, sizeof(*nopt));
1839 memcpy(nopt, opt, 2 + opt->len);
1841 STAILQ_INSERT_TAIL(list, nopt, pointers);
1845 * Parse the options contained in a DHCP message into a list.
1847 * Return 1 on success, 0 if the options are malformed.
1851 dhcp_option_parse_to_list (dhcp_option_list *list, dhcp_option *opts, size_t len)
1853 dhcp_option *opt, *end;
1856 end = (dhcp_option *)(((uint8_t *)opts) + len);
1859 memcmp(opt, dhcp_option_magic, sizeof(dhcp_option_magic)) != 0)
1862 opt = (dhcp_option *)(((uint8_t *) opt) + 4);
1865 opt->id != END) // TODO: check also valid option sizes
1868 if ((dhcp_option *)(((uint8_t *) opt) + 2 + opt->len) >= end)
1869 return 0; // the len field is too long
1871 dhcp_option_append(list, opt);
1873 opt = (dhcp_option *)(((uint8_t *) opt) + 2 + opt->len);
1876 if (opt < end && opt->id == END)
1883 * Serialize a list of options, to be inserted directly inside
1884 * the options section of a DHCP message.
1886 * Return 0 on error, the total serialized len on success.
1890 dhcp_option_list_serialize (dhcp_option_list *list, uint8_t *buf, size_t len)
1897 memcpy(p, dhcp_option_magic, sizeof(dhcp_option_magic));
1901 dhcp_option *opt, *opt_temp;
1903 STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1906 if (len <= 2 + opt->len)
1909 memcpy(p, opt, 2 + opt->len);
1911 len -= 2 + opt->len;
1927 * Delete an option list and deallocate its memory.
1928 * Deallocate even the list elements.
1932 dhcp_option_list_delete (dhcp_option_list *list)
1934 dhcp_option *opt = STAILQ_FIRST(list);
1939 tmp = STAILQ_NEXT(opt, pointers);
1947 static void dhcp_options_default_fill(dhcp_option_list *list, dhcp_option_list *reply_opts)
1949 dhcp_option *opt, *opt_temp;
1952 STAILQ_FOREACH_SAFE(opt, list, pointers, opt_temp)
1954 log_info("options[%d]=%d (%s)\n", i++, opt->id, dhcp_option_info[opt->id].name);
1957 dhcp_option_append(reply_opts, opt);
1962 dhcp_options_requested_fill (dhcp_option *requested_opts, dhcp_option_list *reply_opts)
1964 uint8_t len = requested_opts->len;
1965 uint8_t *id = requested_opts->data;
1968 for (i = 0; i < len; i++)
1972 dhcp_option *opt = dhcp_option_search(&dhcp_address_pool.options, id[i]);
1975 dhcp_option_append(reply_opts, opt);
1978 dhcp_option_print(reply_opts);
1981 static bool dhcp_options_add(char* name, char* value)
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);
1992 log_info( "error: invalid dhcp option specified: %s,%s",name, value);
1993 REQUIRE_ACTION(option, add_error, flags = false);
1996 dhcp_option_append(&dhcp_address_pool.options, option);
1998 if(option->id == IP_ADDRESS_LEASE_TIME)
1999 dhcp_address_pool.lease_time = ntohl(*((uint32_t *)option->data));
2007 * Message handling routines.
2010 static uint8_t dhcp_request_expand (dhcps_msg *request, size_t len)
2012 dhcp_option_list_init(&request->opts);
2014 if (request->hdr.hlen < 1 || request->hdr.hlen > 16)
2017 if (dhcp_option_parse_to_list(&request->opts, (dhcp_option *)request->hdr.options, len - DHCP_HEADER_SIZE) == 0)
2020 dhcp_option *type_opt = dhcp_option_search(&request->opts, DHCP_MESSAGE_TYPE);
2022 if (type_opt == NULL)
2025 uint8_t type = type_opt->data[0];
2031 dhcp_reply_init (dhcps_msg *request, dhcps_msg *reply)
2033 memset(&reply->hdr, 0, sizeof(reply->hdr));
2035 dhcp_option_list_init(&reply->opts);
2037 reply->hdr.op = BOOTREPLY;
2039 reply->hdr.htype = request->hdr.htype;
2040 reply->hdr.hlen = request->hdr.hlen;
2042 reply->hdr.xid = request->hdr.xid;
2043 reply->hdr.flags = request->hdr.flags;
2045 reply->hdr.giaddr = request->hdr.giaddr;
2047 memcpy(reply->hdr.chaddr, request->hdr.chaddr, request->hdr.hlen);
2052 static int dhcp_reply_send(struct udp_pcb *pcb, ip_addr_t *addr, dhcps_msg *reply)
2054 size_t len = 0, ret = 0;
2055 struct pbuf *p = NULL, *q = NULL;
2060 len = dhcp_option_list_serialize(&reply->opts, reply->hdr.options, sizeof(reply->hdr) - DHCP_HEADER_SIZE);
2061 len += DHCP_HEADER_SIZE;
2063 dhcp_option *type_opt = dhcp_option_search(&reply->opts, DHCP_MESSAGE_TYPE);
2064 if (type_opt == NULL)
2067 // if (type_opt->data[0] == DHCP_OFFER)
2068 addr->u_addr.ip4.addr = INADDR_BROADCAST;
2070 // ip4_addr_set(ip_2_ip4(addr), &reply->hdr.yiaddr); // use the address assigned by us
2072 if (reply->hdr.yiaddr.addr != 0)
2074 log_info("send_dhcp_reply %s\n", inet_ntoa(*addr));
2077 p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
2084 data = (u8_t *)q->payload;
2085 for (i = 0; i< q->len; i++)
2087 data[i] = ((u8_t *) reply)[cnt++];
2098 ret = udp_sendto(pcb, p, addr, BOOTPC);
2099 log_info("dhcp_send %d %d\n", ret, p->ref);
2109 dhcp_reply_fill (dhcps_msg *request, dhcps_msg *reply,
2110 address_binding *binding, uint8_t type)
2112 static dhcp_option type_opt, server_id_opt;
2114 type_opt.id = DHCP_MESSAGE_TYPE;
2116 type_opt.data[0] = type;
2117 dhcp_option_append(&reply->opts, &type_opt);
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);
2126 reply->hdr.yiaddr.addr = binding->address;
2129 if (type != DHCPS_NAK)
2131 dhcp_option *requested_opts = dhcp_option_search(&request->opts, PARAMETER_REQUEST_LIST);
2134 dhcp_options_default_fill(&dhcp_address_pool.options, &reply->opts);
2141 dhcp_discover (dhcps_msg *request, dhcps_msg *reply)
2143 address_binding *binding = NULL;
2144 binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC, EMPTY);
2148 /* a static binding has been configured for this client */
2149 log_info("%s %d %p",__FILE__, __LINE__, binding);
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);
2159 /* The client's current address as recorded in the client's current
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);
2169 /* The address requested in the 'Requested IP Address' option, if that
2170 address is valid and not already allocated, ELSE */
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). */
2177 /* extract requested IP address */
2178 uint32_t address = 0;
2179 dhcp_option *address_opt = dhcp_option_search(&request->opts, REQUESTED_IP_ADDRESS);
2181 if (address_opt != NULL)
2182 memcpy(&address, address_opt->data, sizeof(address));
2184 binding = dhcp_binding_new_dynamic(&dhcp_address_pool.bindings, &dhcp_address_pool.indexes, address, request->hdr.chaddr, request->hdr.hlen);
2186 if (binding == NULL)
2188 log_info("Can not offer an address, no address available.");
2194 if (binding->binding_time + binding->lease_time < time(NULL))
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;
2202 return dhcp_reply_fill(request, reply, binding, DHCPS_OFFER);
2206 dhcp_request (dhcps_msg *request, dhcps_msg *reply)
2208 address_binding *binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, PENDING);
2210 uint32_t server_id = 0;
2211 dhcp_option *server_id_opt = dhcp_option_search(&request->opts, SERVER_IDENTIFIER);
2213 if (server_id_opt != NULL)
2214 memcpy(&server_id, server_id_opt->data, sizeof(server_id));
2216 if (server_id == dhcp_address_pool.server_id)
2218 /* this request is an answer to our offer */
2219 if (binding != NULL)
2221 log_info("Ack, associated");
2223 binding->status = ASSOCIATED;
2224 binding->lease_time = dhcp_address_pool.lease_time;
2226 return dhcp_reply_fill(request, reply, binding, DHCPS_ACK);
2230 log_info("Nak, not associated");
2232 return dhcp_reply_fill(request, reply, NULL, DHCPS_NAK);
2236 else if (server_id != 0)
2238 /* this request is an answer to another offer */
2240 binding->status = EMPTY;
2241 binding->lease_time = 0;
2250 dhcp_decline (dhcps_msg *request, dhcps_msg *reply)
2252 address_binding *binding = NULL;
2253 binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, PENDING);
2256 binding->status = EMPTY;
2263 dhcp_release (dhcps_msg *request, dhcps_msg *reply)
2265 address_binding *binding = NULL;
2266 binding = dhcp_binding_search(&dhcp_address_pool.bindings, request->hdr.chaddr, request->hdr.hlen, STATIC_OR_DYNAMIC, ASSOCIATED);
2269 binding->status = RELEASED;
2276 dhcp_inform (dhcps_msg *request, dhcps_msg *reply)
2278 return dhcp_reply_fill(request, reply, NULL, DHCPS_ACK);
2282 * If an incoming DHCP message is in response to us, then trigger the state machine.
2284 * Dispatch client DHCP messages to the correct handling routines
2287 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2289 struct netif *netif = ip_current_input_netif();
2291 struct pbuf *pthis = NULL;
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);
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);
2305 len = pbuf_copy_partial(p, &request->hdr, p->tot_len, 0);
2306 if (len < DHCP_HEADER_SIZE + 5)
2308 goto free_pbuf_and_return;
2312 if (request->hdr.op != BOOTREQUEST)
2314 goto free_pbuf_and_return;
2318 type = dhcp_request_expand(request, len);
2319 dhcp_reply_init(request, reply);
2322 case DHCPS_DISCOVER:
2323 type = dhcp_discover(request, reply);
2327 type = dhcp_request(request, reply);
2331 type = dhcp_decline(request, reply);
2335 type = dhcp_release(request, reply);
2339 type = dhcp_inform(request, reply);
2343 log_info("%s.%u: request with invalid DHCP message type option",inet_ntoa(addr), port);
2347 if (type != DHCP_NONE)
2348 dhcp_reply_send(pcb, (ip_addr_t *)addr, reply);
2350 dhcp_option_list_delete(&request->opts);
2351 dhcp_option_list_delete(&reply->opts);
2355 free_pbuf_and_return:
2356 if (request != NULL)
2364 void dhcps_set_default_option(struct dhcps_lease *pool_addr)
2366 ip4_addr_t server_ip, broadcast, dns;
2367 REQUIRE_ASSERT(pool_addr);
2368 address_pool *dhcps_addr_pool = &dhcp_address_pool;
2370 if (dhcps_addr_pool->flags){
2373 dhcp_option_list_init(&dhcps_addr_pool->options);
2374 dhcps_addr_pool->flags = true;
2377 /* Load configuration */
2378 dhcps_option_set(IP_ADDRESS_LEASE_TIME, "36000");
2379 dhcps_option_set(SUBNET_MASK, inet_ntoa(pool_addr->net_mask));
2381 server_ip.addr = dhcps_addr_pool->server_id;
2382 dhcps_option_set(ROUTER, inet_ntoa(server_ip));
2384 broadcast.addr = server_ip.addr | ~(pool_addr->net_mask.addr);
2385 dhcps_option_set(BROADCAST_ADDRESS,inet_ntoa(broadcast));
2387 dns.addr = DHCP_SERVER_OPENDNS;
2388 dhcps_option_set(DOMAIN_NAME_SERVER, inet_ntoa(dns));
2391 static void dhcps_set_default_binding(address_pool *pool_addr)
2393 REQUIRE_ASSERT(pool_addr);
2394 dhcp_binding_list_init(&pool_addr->bindings);
2397 static address_pool* dhcps_try_open_socket(address_pool *pool_addr)
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);
2407 void dhcps_start(struct netif *netif, struct dhcps_lease *lease_pool)
2409 REQUIRE_ASSERT(netif);
2410 REQUIRE_ASSERT(lease_pool);
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);
2419 void dhcps_stop(struct netif *netif )
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));
2428 bool dhcps_lease_set(struct dhcps_lease *please)
2430 REQUIRE_ASSERT(please);
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;
2439 bool dhcps_lease_get(struct dhcps_lease *please)
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");
2448 bool dhcps_option_set(u8_t opt_id, void* optarg)
2450 if (dhcp_address_pool.flags){
2451 dhcp_option *opt = dhcp_option_search(&dhcp_address_pool.options, opt_id);
2454 opt->len = strlen(optarg);
2455 memset(opt->data, 0, sizeof(opt->data));
2456 memcpy(opt->data, optarg, opt->len);
2461 return dhcp_options_add(dhcp_option_info[opt_id].name, optarg);
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);
2470 bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please)
2475 bool wifi_softap_set_dhcps_lease_time(u32_t minute)
2480 #endif /*ifdef LWIP_ESP8266*/