text: #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));
  }
  ///////////////////////////////////////////////////////////////////////////////////
  /*
   * ����һ��OFFER
   *
   * @param -- m ָ����Ҫ���͵�DHCP msg����
   */
  ///////////////////////////////////////////////////////////////////////////////////
  static void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m)
  {
          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 = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
  #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; i<q->len; 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)
  {
  
          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 = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
  #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; i<q->len; 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)
  {
  
          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 = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
  #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; i<q->len; 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;
          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;
  
          pmsg_dhcps = (struct dhcps_msg *)os_zalloc(sizeof(struct dhcps_msg));
          if (NULL == pmsg_dhcps){
              pbuf_free(p);
              return;
          }
          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; i<p->len; 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; i<p->next->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);
                   break;
              case DHCPS_STATE_ACK://3
  #if DHCPS_DEBUG
                   os_printf("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n");
  #endif
                   send_ack(pmsg_dhcps);
                   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);
                   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;pdhcps_pool->state = DHCPS_STATE_OFFLINE;
      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;
  }
  