#include "lwip/inet.h" #include "lwip/err.h" #include "lwip/pbuf.h" #include "lwip/udp.h" #include "lwip/mem.h" //#include "crypto/common.h" #include "osapi.h" #include "lwip/app/dhcpserver.h" #ifndef LWIP_OPEN_SRC #include "net80211/ieee80211_var.h" #endif #include "user_interface.h" #ifdef MEMLEAK_DEBUG static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; #endif //////////////////////////////////////////////////////////////////////////////////// //static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; //static u8_t old_xid[4] = {0}; static const uint32 magic_cookie ICACHE_RODATA_ATTR = 0x63538263; static struct udp_pcb *pcb_dhcps = NULL; static struct ip_addr broadcast_dhcps; static struct ip_addr server_address; static struct ip_addr client_address;//added static struct dhcps_lease dhcps_lease; //static bool dhcps_lease_flag = true; static list_node *plist = NULL; static uint8 offer = 0xFF; static bool renew = false; #define DHCPS_LEASE_TIME_DEF (120) uint32 dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute void wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force); uint32 wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip); /****************************************************************************** * FunctionName : node_insert_to_list * Description : insert the node to the list * Parameters : arg -- Additional argument to pass to the callback function * Returns : none *******************************************************************************/ void ICACHE_FLASH_ATTR node_insert_to_list(list_node **phead, list_node* pinsert) { list_node *plist = NULL; struct dhcps_pool *pdhcps_pool = NULL; struct dhcps_pool *pdhcps_node = NULL; if (*phead == NULL) *phead = pinsert; else { plist = *phead; pdhcps_node = pinsert->pnode; pdhcps_pool = plist->pnode; if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { pinsert->pnext = plist; *phead = pinsert; } else { while (plist->pnext != NULL) { pdhcps_pool = plist->pnext->pnode; if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { pinsert->pnext = plist->pnext; plist->pnext = pinsert; break; } plist = plist->pnext; } if(plist->pnext == NULL) { plist->pnext = pinsert; } } } // pinsert->pnext = NULL; } /****************************************************************************** * FunctionName : node_delete_from_list * Description : remove the node from list * Parameters : arg -- Additional argument to pass to the callback function * Returns : none *******************************************************************************/ void ICACHE_FLASH_ATTR node_remove_from_list(list_node **phead, list_node* pdelete) { list_node *plist = NULL; plist = *phead; if (plist == NULL){ *phead = NULL; } else { if (plist == pdelete){ *phead = plist->pnext; pdelete->pnext = NULL; } else { while (plist != NULL) { if (plist->pnext == pdelete){ plist->pnext = pdelete->pnext; pdelete->pnext = NULL; } plist = plist->pnext; } } } } /////////////////////////////////////////////////////////////////////////////////// /* * ��DHCP msg��Ϣ�ṹ���������� * * @param optptr -- DHCP msg��Ϣλ�� * @param type -- Ҫ��ӵ�����option * * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ */ /////////////////////////////////////////////////////////////////////////////////// static uint8_t* ICACHE_FLASH_ATTR add_msg_type(uint8_t *optptr, uint8_t type) { *optptr++ = DHCP_OPTION_MSG_TYPE; *optptr++ = 1; *optptr++ = type; return optptr; } /////////////////////////////////////////////////////////////////////////////////// /* * ��DHCP msg�ṹ������offerӦ������ * * @param optptr -- DHCP msg��Ϣλ�� * * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ */ /////////////////////////////////////////////////////////////////////////////////// static uint8_t* ICACHE_FLASH_ATTR add_offer_options(uint8_t *optptr) { struct ip_addr ipadd; ipadd.addr = *( (uint32_t *) &server_address); #ifdef USE_CLASS_B_NET *optptr++ = DHCP_OPTION_SUBNET_MASK; *optptr++ = 4; //length *optptr++ = 255; *optptr++ = 240; *optptr++ = 0; *optptr++ = 0; #else *optptr++ = DHCP_OPTION_SUBNET_MASK; *optptr++ = 4; *optptr++ = 255; *optptr++ = 255; *optptr++ = 255; *optptr++ = 0; #endif *optptr++ = DHCP_OPTION_LEASE_TIME; *optptr++ = 4; *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF; *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF; *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF; *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF; *optptr++ = DHCP_OPTION_SERVER_ID; *optptr++ = 4; *optptr++ = ip4_addr1( &ipadd); *optptr++ = ip4_addr2( &ipadd); *optptr++ = ip4_addr3( &ipadd); *optptr++ = ip4_addr4( &ipadd); if (dhcps_router_enabled(offer)){ struct ip_info if_ip; os_bzero(&if_ip, sizeof(struct ip_info)); wifi_get_ip_info(SOFTAP_IF, &if_ip); *optptr++ = DHCP_OPTION_ROUTER; *optptr++ = 4; *optptr++ = ip4_addr1( &if_ip.gw); *optptr++ = ip4_addr2( &if_ip.gw); *optptr++ = ip4_addr3( &if_ip.gw); *optptr++ = ip4_addr4( &if_ip.gw); } #ifdef USE_DNS *optptr++ = DHCP_OPTION_DNS_SERVER; *optptr++ = 4; *optptr++ = ip4_addr1( &ipadd); *optptr++ = ip4_addr2( &ipadd); *optptr++ = ip4_addr3( &ipadd); *optptr++ = ip4_addr4( &ipadd); #endif #ifdef CLASS_B_NET *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; *optptr++ = 4; *optptr++ = ip4_addr1( &ipadd); *optptr++ = 255; *optptr++ = 255; *optptr++ = 255; #else *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; *optptr++ = 4; *optptr++ = ip4_addr1( &ipadd); *optptr++ = ip4_addr2( &ipadd); *optptr++ = ip4_addr3( &ipadd); *optptr++ = 255; #endif *optptr++ = DHCP_OPTION_INTERFACE_MTU; *optptr++ = 2; #ifdef CLASS_B_NET *optptr++ = 0x05; *optptr++ = 0xdc; #else *optptr++ = 0x02; *optptr++ = 0x40; #endif *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY; *optptr++ = 1; *optptr++ = 0x00; *optptr++ = 43; *optptr++ = 6; *optptr++ = 0x01; *optptr++ = 4; *optptr++ = 0x00; *optptr++ = 0x00; *optptr++ = 0x00; *optptr++ = 0x02; return optptr; } /////////////////////////////////////////////////////////////////////////////////// /* * ��DHCP msg�ṹ����ӽ����־���� * * @param optptr -- DHCP msg��Ϣλ�� * * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ */ /////////////////////////////////////////////////////////////////////////////////// static uint8_t* ICACHE_FLASH_ATTR add_end(uint8_t *optptr) { *optptr++ = DHCP_OPTION_END; return optptr; } /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR create_msg(struct dhcps_msg *m) { struct ip_addr client; client.addr = client_address.addr; m->op = DHCP_REPLY; m->htype = DHCP_HTYPE_ETHERNET; m->hlen = 6; m->hops = 0; // os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid)); m->secs = 0; m->flags = htons(BOOTP_BROADCAST); os_memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); os_memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); os_memset((char *) m->siaddr, 0, sizeof(m->siaddr)); os_memset((char *) m->giaddr, 0, sizeof(m->giaddr)); os_memset((char *) m->sname, 0, sizeof(m->sname)); os_memset((char *) m->file, 0, sizeof(m->file)); os_memset((char *) m->options, 0, sizeof(m->options)); //For xiaomi crash bug uint32 magic_cookie1 = magic_cookie; os_memcpy((char *) m->options, &magic_cookie1, sizeof(magic_cookie1)); } struct pbuf * dhcps_pbuf_alloc(u16_t len) { u16_t mlen = sizeof(struct dhcps_msg); if (len > mlen) { #if DHCPS_DEBUG DHCPS_LOG("dhcps: len=%d mlen=%d", len, mlen); #endif mlen = len; } return pbuf_alloc(PBUF_TRANSPORT, mlen, PBUF_RAM); } /////////////////////////////////////////////////////////////////////////////////// /* * ����һ��OFFER * * @param -- m ָ����Ҫ���͵�DHCP msg���� */ /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m, u16_t len) { uint8_t *end; struct pbuf *p, *q; u8_t *data; u16_t cnt=0; u16_t i; err_t SendOffer_err_t; create_msg(m); end = add_msg_type(&m->options[4], DHCPOFFER); end = add_offer_options(end); end = add_end(end); p = dhcps_pbuf_alloc(len); #if DHCPS_DEBUG os_printf("udhcp: send_offer>>p->ref = %d\n", p->ref); #endif if(p != NULL){ #if DHCPS_DEBUG os_printf("dhcps: send_offer>>pbuf_alloc succeed\n"); os_printf("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len); os_printf("dhcps: send_offer>>p->len = %d\n", p->len); #endif q = p; while(q != NULL){ data = (u8_t *)q->payload; for(i=0; ilen; i++) { data[i] = ((u8_t *) m)[cnt++]; } q = q->next; } }else{ #if DHCPS_DEBUG os_printf("dhcps: send_offer>>pbuf_alloc failed\n"); #endif return; } SendOffer_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); #if DHCPS_DEBUG os_printf("dhcps: send_offer>>udp_sendto result %x\n",SendOffer_err_t); #endif if(p->ref != 0){ #if DHCPS_DEBUG os_printf("udhcp: send_offer>>free pbuf\n"); #endif pbuf_free(p); } } /////////////////////////////////////////////////////////////////////////////////// /* * ����һ��NAK��Ϣ * * @param m ָ����Ҫ���͵�DHCP msg���� */ /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR send_nak(struct dhcps_msg *m, u16_t len) { u8_t *end; struct pbuf *p, *q; u8_t *data; u16_t cnt=0; u16_t i; err_t SendNak_err_t; create_msg(m); end = add_msg_type(&m->options[4], DHCPNAK); end = add_end(end); p = dhcps_pbuf_alloc(len); #if DHCPS_DEBUG os_printf("udhcp: send_nak>>p->ref = %d\n", p->ref); #endif if(p != NULL){ #if DHCPS_DEBUG os_printf("dhcps: send_nak>>pbuf_alloc succeed\n"); os_printf("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len); os_printf("dhcps: send_nak>>p->len = %d\n", p->len); #endif q = p; while(q != NULL){ data = (u8_t *)q->payload; for(i=0; ilen; i++) { data[i] = ((u8_t *) m)[cnt++]; } q = q->next; } }else{ #if DHCPS_DEBUG os_printf("dhcps: send_nak>>pbuf_alloc failed\n"); #endif return; } SendNak_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); #if DHCPS_DEBUG os_printf("dhcps: send_nak>>udp_sendto result %x\n",SendNak_err_t); #endif if(p->ref != 0){ #if DHCPS_DEBUG os_printf("udhcp: send_nak>>free pbuf\n"); #endif pbuf_free(p); } } /////////////////////////////////////////////////////////////////////////////////// /* * ����һ��ACK��DHCP�ͻ��� * * @param m ָ����Ҫ���͵�DHCP msg���� */ /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m, u16_t len) { u8_t *end; struct pbuf *p, *q; u8_t *data; u16_t cnt=0; u16_t i; err_t SendAck_err_t; create_msg(m); end = add_msg_type(&m->options[4], DHCPACK); end = add_offer_options(end); end = add_end(end); p = dhcps_pbuf_alloc(len); #if DHCPS_DEBUG os_printf("udhcp: send_ack>>p->ref = %d\n", p->ref); #endif if(p != NULL){ #if DHCPS_DEBUG os_printf("dhcps: send_ack>>pbuf_alloc succeed\n"); os_printf("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len); os_printf("dhcps: send_ack>>p->len = %d\n", p->len); #endif q = p; while(q != NULL){ data = (u8_t *)q->payload; for(i=0; ilen; i++) { data[i] = ((u8_t *) m)[cnt++]; } q = q->next; } }else{ #if DHCPS_DEBUG os_printf("dhcps: send_ack>>pbuf_alloc failed\n"); #endif return; } SendAck_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); #if DHCPS_DEBUG os_printf("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t); #endif if(p->ref != 0){ #if DHCPS_DEBUG os_printf("udhcp: send_ack>>free pbuf\n"); #endif pbuf_free(p); } } /////////////////////////////////////////////////////////////////////////////////// /* * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ�� * * @param optptr DHCP msg�е��������� * @param len ��������Ĵ��?(byte) * * @return uint8_t ���ش�����DHCP Server״ֵ̬ */ /////////////////////////////////////////////////////////////////////////////////// static uint8_t ICACHE_FLASH_ATTR parse_options(uint8_t *optptr, sint16_t len) { struct ip_addr client; bool is_dhcp_parse_end = false; struct dhcps_state s; client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP u8_t *end = optptr + len; u16_t type = 0; s.state = DHCPS_STATE_IDLE; while (optptr < end) { #if DHCPS_DEBUG os_printf("dhcps: (sint16_t)*optptr = %d\n", (sint16_t)*optptr); #endif switch ((sint16_t) *optptr) { case DHCP_OPTION_MSG_TYPE: //53 type = *(optptr + 2); break; case DHCP_OPTION_REQ_IPADDR://50 //os_printf("dhcps:0x%08x,0x%08x\n",client.addr,*(uint32*)(optptr+2)); if( os_memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) { #if DHCPS_DEBUG os_printf("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); #endif s.state = DHCPS_STATE_ACK; }else { #if DHCPS_DEBUG os_printf("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); #endif s.state = DHCPS_STATE_NAK; } break; case DHCP_OPTION_END: { is_dhcp_parse_end = true; } break; } if(is_dhcp_parse_end){ break; } optptr += optptr[1] + 2; } switch (type){ case DHCPDISCOVER://1 s.state = DHCPS_STATE_OFFER; #if DHCPS_DEBUG os_printf("dhcps: DHCPD_STATE_OFFER\n"); #endif break; case DHCPREQUEST://3 if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) { if(renew == true) { s.state = DHCPS_STATE_ACK; } else { s.state = DHCPS_STATE_NAK; } #if DHCPS_DEBUG os_printf("dhcps: DHCPD_STATE_NAK\n"); #endif } break; case DHCPDECLINE://4 s.state = DHCPS_STATE_IDLE; #if DHCPS_DEBUG os_printf("dhcps: DHCPD_STATE_IDLE\n"); #endif break; case DHCPRELEASE://7 s.state = DHCPS_STATE_RELEASE; #if DHCPS_DEBUG os_printf("dhcps: DHCPD_STATE_IDLE\n"); #endif break; } #if DHCPS_DEBUG os_printf("dhcps: return s.state = %d\n", s.state); #endif return s.state; } /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// static sint16_t ICACHE_FLASH_ATTR parse_msg(struct dhcps_msg *m, u16_t len) { if(os_memcmp((char *)m->options, &magic_cookie, sizeof(magic_cookie)) == 0){ struct ip_addr ip; os_memcpy(&ip.addr,m->ciaddr,sizeof(ip.addr)); client_address.addr = wifi_softap_dhcps_client_update(m->chaddr,&ip); sint16_t ret = parse_options(&m->options[4], len); if(ret == DHCPS_STATE_RELEASE) { wifi_softap_dhcps_client_leave(m->chaddr,&ip,TRUE); // force to delete client_address.addr = ip.addr; } return ret; } return 0; } /////////////////////////////////////////////////////////////////////////////////// /* * DHCP ��������ݰ���մ���ص�����˺�����LWIP UDPģ������ʱ������ * ��Ҫ����udp_recv()������LWIP����ע��. * * @param arg * @param pcb ���յ�UDP��Ŀ��ƿ�? * @param p ���յ���UDP�е��������? * @param addr ���ʹ�UDP���Դ�����IP��ַ * @param port ���ʹ�UDP���Դ�����UDPͨ���˿ں� */ /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR handle_dhcp(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, uint16_t port) { struct dhcps_msg *pmsg_dhcps = NULL; sint16_t tlen = 0, malloc_len; u16_t i = 0; u16_t dhcps_msg_cnt = 0; u8_t *p_dhcps_msg = NULL; u8_t *data = NULL; #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> receive a packet\n"); #endif if (p==NULL) return; malloc_len = sizeof(struct dhcps_msg); #if DHCPS_DEBUG DHCPS_LOG("dhcps: handle_dhcp malloc_len=%d rx_len=%d", malloc_len, p->tot_len); #endif if (malloc_len < p->tot_len) { malloc_len = p->tot_len; } pmsg_dhcps = (struct dhcps_msg *)os_malloc(malloc_len); if (NULL == pmsg_dhcps){ pbuf_free(p); return; } memset(pmsg_dhcps , 0x00 , malloc_len); p_dhcps_msg = (u8_t *)pmsg_dhcps; tlen = p->tot_len; data = p->payload; #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen); os_printf("dhcps: handle_dhcp-> p->len = %d\n", p->len); #endif for(i=0; ilen; i++){ p_dhcps_msg[dhcps_msg_cnt++] = data[i]; } if(p->next != NULL) { #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> p->next != NULL\n"); os_printf("dhcps: handle_dhcp-> p->next->tot_len = %d\n",p->next->tot_len); os_printf("dhcps: handle_dhcp-> p->next->len = %d\n",p->next->len); #endif data = p->next->payload; for(i=0; inext->len; i++){ p_dhcps_msg[dhcps_msg_cnt++] = data[i]; } } /* * DHCP �ͻ���������Ϣ���� */ #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> parse_msg(p)\n"); #endif switch(parse_msg(pmsg_dhcps, tlen - 240)) { case DHCPS_STATE_OFFER://1 #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n"); #endif send_offer(pmsg_dhcps, malloc_len); break; case DHCPS_STATE_ACK://3 #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n"); #endif send_ack(pmsg_dhcps, malloc_len); wifi_softap_set_station_info(pmsg_dhcps->chaddr, &client_address.addr); break; case DHCPS_STATE_NAK://4 #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n"); #endif send_nak(pmsg_dhcps, malloc_len); break; default : break; } #if DHCPS_DEBUG os_printf("dhcps: handle_dhcp-> pbuf_free(p)\n"); #endif pbuf_free(p); os_free(pmsg_dhcps); pmsg_dhcps = NULL; } /////////////////////////////////////////////////////////////////////////////////// static void ICACHE_FLASH_ATTR wifi_softap_init_dhcps_lease(uint32 ip) { uint32 softap_ip = 0,local_ip = 0; uint32 start_ip = 0; uint32 end_ip = 0; // if (dhcps_lease_flag) { if (dhcps_lease.enable == TRUE) { softap_ip = htonl(ip); start_ip = htonl(dhcps_lease.start_ip.addr); end_ip = htonl(dhcps_lease.end_ip.addr); /*config ip information can't contain local ip*/ if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) { dhcps_lease.enable = FALSE; } else { /*config ip information must be in the same segment as the local ip*/ softap_ip >>= 8; if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip)) || (end_ip - start_ip > DHCPS_MAX_LEASE)) { dhcps_lease.enable = FALSE; } } } if (dhcps_lease.enable == FALSE) { local_ip = softap_ip = htonl(ip); softap_ip &= 0xFFFFFF00; local_ip &= 0xFF; if (local_ip >= 0x80) local_ip -= DHCPS_MAX_LEASE; else local_ip ++; os_bzero(&dhcps_lease, sizeof(dhcps_lease)); dhcps_lease.start_ip.addr = softap_ip | local_ip; dhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1); dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); } // dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); // dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); // os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip); } /////////////////////////////////////////////////////////////////////////////////// void ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info) { struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); if(apnetif->dhcps_pcb != NULL) { udp_remove(apnetif->dhcps_pcb); } pcb_dhcps = udp_new(); if (pcb_dhcps == NULL || info ==NULL) { os_printf("dhcps_start(): could not obtain pcb\n"); } apnetif->dhcps_pcb = pcb_dhcps; IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255); server_address = info->ip; wifi_softap_init_dhcps_lease(server_address.addr); udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT); udp_recv(pcb_dhcps, handle_dhcp, NULL); #if DHCPS_DEBUG os_printf("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n"); #endif } void ICACHE_FLASH_ATTR dhcps_stop(void) { struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); udp_disconnect(pcb_dhcps); // dhcps_lease_flag = true; if(apnetif->dhcps_pcb != NULL) { udp_remove(apnetif->dhcps_pcb); apnetif->dhcps_pcb = NULL; } //udp_remove(pcb_dhcps); list_node *pnode = NULL; list_node *pback_node = NULL; struct dhcps_pool* dhcp_node = NULL; struct ip_addr ip_zero; os_memset(&ip_zero,0x0,sizeof(ip_zero)); pnode = plist; while (pnode != NULL) { pback_node = pnode; pnode = pback_node->pnext; node_remove_from_list(&plist, pback_node); dhcp_node = (struct dhcps_pool*)pback_node->pnode; //wifi_softap_dhcps_client_leave(dhcp_node->mac,&dhcp_node->ip,TRUE); // force to delete wifi_softap_set_station_info(dhcp_node->mac, &ip_zero); os_free(pback_node->pnode); pback_node->pnode = NULL; os_free(pback_node); pback_node = NULL; } } /****************************************************************************** * FunctionName : wifi_softap_set_dhcps_lease * Description : set the lease information of DHCP server * Parameters : please -- Additional argument to set the lease information, * Little-Endian. * Returns : true or false *******************************************************************************/ bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease(struct dhcps_lease *please) { struct ip_info info; uint32 softap_ip = 0; uint32 start_ip = 0; uint32 end_ip = 0; uint8 opmode = wifi_get_opmode(); if (opmode == STATION_MODE || opmode == NULL_MODE) { return false; } if (please == NULL || wifi_softap_dhcps_status() == DHCP_STARTED) return false; if(please->enable) { os_bzero(&info, sizeof(struct ip_info)); wifi_get_ip_info(SOFTAP_IF, &info); softap_ip = htonl(info.ip.addr); start_ip = htonl(please->start_ip.addr); end_ip = htonl(please->end_ip.addr); /*config ip information can't contain local ip*/ if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) return false; /*config ip information must be in the same segment as the local ip*/ softap_ip >>= 8; if ((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip)) { return false; } if (end_ip - start_ip > DHCPS_MAX_LEASE) return false; os_bzero(&dhcps_lease, sizeof(dhcps_lease)); // dhcps_lease.start_ip.addr = start_ip; // dhcps_lease.end_ip.addr = end_ip; dhcps_lease.start_ip.addr = please->start_ip.addr; dhcps_lease.end_ip.addr = please->end_ip.addr; } dhcps_lease.enable = please->enable; // dhcps_lease_flag = false; return true; } /****************************************************************************** * FunctionName : wifi_softap_get_dhcps_lease * Description : get the lease information of DHCP server * Parameters : please -- Additional argument to get the lease information, * Little-Endian. * Returns : true or false *******************************************************************************/ bool ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease(struct dhcps_lease *please) { uint8 opmode = wifi_get_opmode(); if (opmode == STATION_MODE || opmode == NULL_MODE) { return false; } if (NULL == please) return false; // if (dhcps_lease_flag){ if (dhcps_lease.enable == FALSE){ if (wifi_softap_dhcps_status() == DHCP_STOPPED) return false; } else { // os_bzero(please, sizeof(dhcps_lease)); // if (wifi_softap_dhcps_status() == DHCP_STOPPED){ // please->start_ip.addr = htonl(dhcps_lease.start_ip.addr); // please->end_ip.addr = htonl(dhcps_lease.end_ip.addr); // } } // if (wifi_softap_dhcps_status() == DHCP_STARTED){ // os_bzero(please, sizeof(dhcps_lease)); // please->start_ip.addr = dhcps_lease.start_ip.addr; // please->end_ip.addr = dhcps_lease.end_ip.addr; // } please->start_ip.addr = dhcps_lease.start_ip.addr; please->end_ip.addr = dhcps_lease.end_ip.addr; return true; } static void ICACHE_FLASH_ATTR kill_oldest_dhcps_pool(void) { list_node *pre = NULL, *p = NULL; list_node *minpre = NULL, *minp = NULL; struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; pre = plist; p = pre->pnext; minpre = pre; minp = p; while (p != NULL){ pdhcps_pool = p->pnode; pmin_pool = minp->pnode; if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){ minp = p; minpre = pre; } pre = p; p = p->pnext; } minpre->pnext = minp->pnext; os_free(minp->pnode); minp->pnode = NULL; os_free(minp); minp = NULL; } void ICACHE_FLASH_ATTR dhcps_coarse_tmr(void) { uint8 num_dhcps_pool = 0; list_node *pback_node = NULL; list_node *pnode = NULL; struct dhcps_pool *pdhcps_pool = NULL; pnode = plist; while (pnode != NULL) { pdhcps_pool = pnode->pnode; if ( pdhcps_pool->type == DHCPS_TYPE_DYNAMIC) { pdhcps_pool->lease_timer --; } if (pdhcps_pool->lease_timer == 0){ pback_node = pnode; pnode = pback_node->pnext; node_remove_from_list(&plist,pback_node); os_free(pback_node->pnode); pback_node->pnode = NULL; os_free(pback_node); pback_node = NULL; } else { pnode = pnode ->pnext; num_dhcps_pool ++; } } if (num_dhcps_pool >= MAX_STATION_NUM) kill_oldest_dhcps_pool(); } bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg) { bool offer_flag = true; uint8 option = 0; if (optarg == NULL && wifi_softap_dhcps_status() == false) return false; if (level <= OFFER_START || level >= OFFER_END) return false; switch (level){ case OFFER_ROUTER: offer = (*(uint8 *)optarg) & 0x01; offer_flag = true; break; default : offer_flag = false; break; } return offer_flag; } bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease_time(uint32 minute) { uint8 opmode = wifi_get_opmode(); if (opmode == STATION_MODE || opmode == NULL_MODE) { return false; } if (wifi_softap_dhcps_status() == DHCP_STARTED) { return false; } if(minute == 0) { return false; } dhcps_lease_time = minute; return true; } bool ICACHE_FLASH_ATTR wifi_softap_reset_dhcps_lease_time(void) { uint8 opmode = wifi_get_opmode(); if (opmode == STATION_MODE || opmode == NULL_MODE) { return false; } if (wifi_softap_dhcps_status() == DHCP_STARTED) { return false; } dhcps_lease_time = DHCPS_LEASE_TIME_DEF; return true; } uint32 ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease_time(void) // minute { return dhcps_lease_time; } void ICACHE_FLASH_ATTR wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force) { struct dhcps_pool *pdhcps_pool = NULL; list_node *pback_node = NULL; if ((bssid == NULL) || (ip == NULL)) { return; } for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { pdhcps_pool = pback_node->pnode; if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { if ((pdhcps_pool->type == DHCPS_TYPE_STATIC) || (force)) { if(pback_node != NULL) { node_remove_from_list(&plist,pback_node); os_free(pback_node); pback_node = NULL; } if (pdhcps_pool != NULL) { os_free(pdhcps_pool); pdhcps_pool = NULL; } } else { pdhcps_pool->state = DHCPS_STATE_OFFLINE; } struct ip_addr ip_zero; os_memset(&ip_zero,0x0,sizeof(ip_zero)); wifi_softap_set_station_info(bssid, &ip_zero); break; } } } } uint32 ICACHE_FLASH_ATTR wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip) { struct dhcps_pool *pdhcps_pool = NULL; list_node *pback_node = NULL; list_node *pmac_node = NULL; list_node *pip_node = NULL; bool flag = FALSE; uint32 start_ip = dhcps_lease.start_ip.addr; uint32 end_ip = dhcps_lease.end_ip.addr; dhcps_type_t type = DHCPS_TYPE_DYNAMIC; if (bssid == NULL) { return IPADDR_ANY; } if (ip) { if (IPADDR_BROADCAST == ip->addr) { return IPADDR_ANY; } else if (IPADDR_ANY == ip->addr) { ip = NULL; } else { type = DHCPS_TYPE_STATIC; } } renew = FALSE; for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { pdhcps_pool = pback_node->pnode; //os_printf("mac:"MACSTR"bssid:"MACSTR"\r\n",MAC2STR(pdhcps_pool->mac),MAC2STR(bssid)); if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ pmac_node = pback_node; if (ip == NULL) { flag = TRUE; break; } } if (ip != NULL) { if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { pip_node = pback_node; } } else if (flag == FALSE){ if (os_memcmp(&pdhcps_pool->ip.addr, &start_ip, sizeof(pdhcps_pool->ip.addr)) != 0) { flag = TRUE; } else { start_ip = htonl((ntohl(start_ip) + 1)); } } } if ((ip == NULL) && (flag == FALSE)) { if (plist == NULL) { if (start_ip <= end_ip) { flag = TRUE; } else { return IPADDR_ANY; } } else { if (start_ip > end_ip) { return IPADDR_ANY; } //start_ip = htonl((ntohl(start_ip) + 1)); flag = TRUE; } } if (pmac_node != NULL) { // update new ip if (pip_node != NULL){ pdhcps_pool = pip_node->pnode; if (pip_node != pmac_node) { if(pdhcps_pool->state != DHCPS_STATE_OFFLINE) { // ip is used return IPADDR_ANY; } // mac exists and ip exists in other node,delete mac node_remove_from_list(&plist,pmac_node); os_free(pmac_node->pnode); pmac_node->pnode = NULL; os_free(pmac_node); pmac_node = pip_node; os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); } else { renew = true; type = DHCPS_TYPE_DYNAMIC; } pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; pdhcps_pool->type = type; pdhcps_pool->state = DHCPS_STATE_ONLINE; } else { pdhcps_pool = pmac_node->pnode; if (ip != NULL) { pdhcps_pool->ip.addr = ip->addr; } else if (flag == TRUE) { pdhcps_pool->ip.addr = start_ip; } else { // no ip to distribute return IPADDR_ANY; } node_remove_from_list(&plist,pmac_node); pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; pdhcps_pool->type = type; pdhcps_pool->state = DHCPS_STATE_ONLINE; node_insert_to_list(&plist,pmac_node); } } else { // new station if (pip_node != NULL) { // maybe ip has used pdhcps_pool = pip_node->pnode; if (pdhcps_pool->state != DHCPS_STATE_OFFLINE) { return IPADDR_ANY; } os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; pdhcps_pool->type = type; pdhcps_pool->state = DHCPS_STATE_ONLINE; } else { pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool)); if (ip != NULL) { pdhcps_pool->ip.addr = ip->addr; } else if (flag == TRUE) { pdhcps_pool->ip.addr = start_ip; } else { // no ip to distribute os_free(pdhcps_pool); return IPADDR_ANY; } if (pdhcps_pool->ip.addr > end_ip) { os_free(pdhcps_pool); return IPADDR_ANY; } os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; pdhcps_pool->type = type; pdhcps_pool->state = DHCPS_STATE_ONLINE; pback_node = (list_node *)os_zalloc(sizeof(list_node )); pback_node->pnode = pdhcps_pool; pback_node->pnext = NULL; node_insert_to_list(&plist,pback_node); } } return pdhcps_pool->ip.addr; }