text: /*
   * File      : dhcp_server_raw.c
   *             A simple DHCP server implementation
   *
   * This file is part of RT-Thread RTOS
   * COPYRIGHT (C) 2011-2018, Shanghai Real-Thread Technology Co., Ltd
   * http://www.rt-thread.com
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Change Logs:
   * Date           Author       Notes
   * 2014-04-01     Ren.Haibo    the first version
   * 2018-06-12     aozima       ignore DHCP_OPTION_SERVER_ID.
   */
  
  #include <stdio.h>
  #include <stdint.h>
  
  #include <rtthread.h>
  
  #include <lwip/opt.h>
  #include <lwip/sockets.h>
  #include <lwip/inet_chksum.h>
  #include <netif/etharp.h>
  #include <netif/ethernetif.h>
  #include <lwip/ip.h>
  #include <lwip/init.h>
  
  #if (LWIP_VERSION) < 0x02000000U
      #error "not support old LWIP"
  #endif
  
  #if !LWIP_IPV4
      #error "must enable IPV4"
  #endif
  
  #if (LWIP_VERSION) >= 0x02000000U
      #include <lwip/prot/dhcp.h>
  #endif
  
  /* DHCP server option */
  
  /* allocated client ip range */
  #ifndef DHCPD_CLIENT_IP_MIN
      #define DHCPD_CLIENT_IP_MIN     2
  #endif
  #ifndef DHCPD_CLIENT_IP_MAX
      #define DHCPD_CLIENT_IP_MAX     254
  #endif
  
  /* the DHCP server address */
  #ifndef DHCPD_SERVER_IP
      #define DHCPD_SERVER_IP "192.168.169.1"
  #endif
  
  #define DHCP_DEBUG_PRINTF
  
  #ifdef  DHCP_DEBUG_PRINTF
      #define DEBUG_PRINTF        rt_kprintf("[DHCP] "); rt_kprintf
  #else
      #define DEBUG_PRINTF(...)
  #endif /* DHCP_DEBUG_PRINTF */
  
  /* we need some routines in the DHCP of lwIP */
  #undef  LWIP_DHCP
  #define LWIP_DHCP   1
  #include <lwip/dhcp.h>
  
  /** Mac address length  */
  #define DHCP_MAX_HLEN               6
  /** dhcp default live time */
  #define DHCP_DEFAULT_LIVE_TIME      0x80510100
  
  /** Minimum length for request before packet is parsed */
  #define DHCP_MIN_REQUEST_LEN        44
  
  #define LWIP_NETIF_LOCK(...)
  #define LWIP_NETIF_UNLOCK(...)
  
  /**
  * The dhcp client node struct.
  */
  struct dhcp_client_node
  {
      struct dhcp_client_node *next;
      u8_t chaddr[DHCP_MAX_HLEN];
      ip4_addr_t ipaddr;
      u32_t lease_end;
  };
  
  /**
  * The dhcp server struct.
  */
  struct dhcp_server
  {
      struct dhcp_server *next;
      struct netif *netif;
      struct udp_pcb *pcb;
      struct dhcp_client_node *node_list;
      ip4_addr_t start;
      ip4_addr_t end;
      ip4_addr_t current;
  };
  
  static u8_t *dhcp_server_option_find(u8_t *buf, u16_t len, u8_t option);
  
  /**
  * The dhcp server struct list.
  */
  static struct dhcp_server *lw_dhcp_server;
  
  /**
  * Find a dhcp client node by mac address
  *
  * @param dhcpserver The dhcp server
  * @param chaddr Mac address
  * @param hlen   Mac address length
  * @return dhcp client node
  */
  static struct dhcp_client_node *
  dhcp_client_find_by_mac(struct dhcp_server *dhcpserver, const u8_t *chaddr, u8_t hlen)
  {
      struct dhcp_client_node *node;
  
      for (node = dhcpserver->node_list; node != NULL; node = node->next)
      {
          if (memcmp(node->chaddr, chaddr, hlen) == 0)
          {
              return node;
          }
      }
  
      return NULL;
  }
  
  /**
  * Find a dhcp client node by ip address
  *
  * @param dhcpserver The dhcp server
  * @param chaddr Mac address
  * @param hlen   Mac address length
  * @return dhcp client node
  */
  static struct dhcp_client_node *
  dhcp_client_find_by_ip(struct dhcp_server *dhcpserver, const ip4_addr_t *ip)
  {
      struct dhcp_client_node *node;
  
      for (node = dhcpserver->node_list; node != NULL; node = node->next)
      {
          if (ip4_addr_cmp(&node->ipaddr, ip))
          {
              return node;
          }
      }
  
      return NULL;
  }
  
  /**
  * Find a dhcp client node by ip address
  *
  * @param dhcpserver The dhcp server
  * @param chaddr Mac address
  * @param hlen   Mac address length
  * @return dhcp client node
  */
  static struct dhcp_client_node *
  dhcp_client_find(struct dhcp_server *dhcpserver, struct dhcp_msg *msg,
                   u8_t *opt_buf, u16_t len)
  {
      u8_t *opt;
      //u32_t ipaddr;
      struct dhcp_client_node *node;
  
      node = dhcp_client_find_by_mac(dhcpserver, msg->chaddr, msg->hlen);
      if (node != NULL)
      {
          return node;
      }
  
      opt = dhcp_server_option_find(opt_buf, len, DHCP_OPTION_REQUESTED_IP);
      if (opt != NULL)
      {
          node = dhcp_client_find_by_ip(dhcpserver, (ip4_addr_t *)(&opt[2]));
          if (node != NULL)
          {
              return node;
          }
      }
  
      return NULL;
  }
  
  /**
  * Find a dhcp client node by ip address
  *
  * @param dhcpserver The dhcp server
  * @param chaddr Mac address
  * @param hlen   Mac address length
  * @return dhcp client node
  */
  static struct dhcp_client_node *
  dhcp_client_alloc(struct dhcp_server *dhcpserver, struct dhcp_msg *msg,
                    u8_t *opt_buf, u16_t len)
  {
      u8_t *opt;
      u32_t ipaddr;
      struct dhcp_client_node *node;
  
      node = dhcp_client_find_by_mac(dhcpserver, msg->chaddr, msg->hlen);
      if (node != NULL)
      {
          return node;
      }
  
      opt = dhcp_server_option_find(opt_buf, len, DHCP_OPTION_REQUESTED_IP);
      if (opt != NULL)
      {
          node = dhcp_client_find_by_ip(dhcpserver, (ip4_addr_t *)(&opt[2]));
          if (node != NULL)
          {
              return node;
          }
      }
  
  dhcp_alloc_again:
      node = dhcp_client_find_by_ip(dhcpserver, &dhcpserver->current);
      if (node != NULL)
      {
          ipaddr = (ntohl(dhcpserver->current.addr) + 1);
          if (ipaddr > ntohl(dhcpserver->end.addr))
          {
              ipaddr = ntohl(dhcpserver->start.addr);
          }
          dhcpserver->current.addr = htonl(ipaddr);
          goto dhcp_alloc_again;
      }
      node = (struct dhcp_client_node *)mem_malloc(sizeof(struct dhcp_client_node));
      if (node == NULL)
      {
          return NULL;
      }
      SMEMCPY(node->chaddr, msg->chaddr, msg->hlen);
      node->ipaddr = dhcpserver->current;
  
      node->next = dhcpserver->node_list;
      dhcpserver->node_list = node;
  
      return node;
  }
  
  /**
  * find option from buffer.
  *
  * @param buf The buffer to find option
  * @param len The buffer length
  * @param option Which option to find
  * @return dhcp option buffer
  */
  static u8_t *
  dhcp_server_option_find(u8_t *buf, u16_t len, u8_t option)
  {
      u8_t *end = buf + len;
      while ((buf < end) && (*buf != DHCP_OPTION_END))
      {
          if (*buf == option)
          {
              return buf;
          }
          buf += (buf[1] + 2);
      }
      return NULL;
  }
  
  /**
  * If an incoming DHCP message is in response to us, then trigger the state machine
  */
  static void
  dhcp_server_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *recv_addr, u16_t port)
  {
      struct dhcp_server *dhcp_server = (struct dhcp_server *)arg;
      struct dhcp_msg *msg;
      struct pbuf *q;
      u8_t *opt_buf;
      u8_t *opt;
      struct dhcp_client_node *node;
      u8_t msg_type;
      u16_t length;
      ip_addr_t addr = *recv_addr;
      u32_t tmp;
  
      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("[%s:%d] %c%c recv %d\n", __FUNCTION__, __LINE__, dhcp_server->netif->name[0], dhcp_server->netif->name[1], p->tot_len));
      /* prevent warnings about unused arguments */
      LWIP_UNUSED_ARG(pcb);
      LWIP_UNUSED_ARG(addr);
      LWIP_UNUSED_ARG(port);
  
      if (p->len < DHCP_MIN_REQUEST_LEN)
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP request message or pbuf too short\n"));
          pbuf_free(p);
          return;
      }
  
      q = pbuf_alloc(PBUF_TRANSPORT, 1500, PBUF_RAM);
      if (q == NULL)
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloc dhcp_msg failed!\n"));
          pbuf_free(p);
          return;
      }
      if (q->tot_len < p->tot_len)
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloc dhcp_msg too small %d:%d\n", q->tot_len, p->tot_len));
          pbuf_free(p);
          return;
      }
  
      pbuf_copy(q, p);
      pbuf_free(p);
  
      msg = (struct dhcp_msg *)q->payload;
      if (msg->op != DHCP_BOOTREQUEST)
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP request message, but type %"U16_F"\n", (u16_t)msg->op));
          goto free_pbuf_and_return;
      }
  
      if (msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE))
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("bad DHCP_MAGIC_COOKIE!\n"));
          goto free_pbuf_and_return;
      }
  
      if (msg->hlen > DHCP_MAX_HLEN)
      {
          goto free_pbuf_and_return;
      }
  
      opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
      length = q->tot_len - DHCP_OPTIONS_OFS;
      opt = dhcp_server_option_find(opt_buf, length, DHCP_OPTION_MESSAGE_TYPE);
      if (opt)
      {
          msg_type = *(opt + 2);
          if (msg_type == DHCP_DISCOVER)
          {
              node = dhcp_client_alloc(dhcp_server, msg, opt_buf, length);
              if (node == NULL)
              {
                  goto free_pbuf_and_return;
              }
              node->lease_end = DHCP_DEFAULT_LIVE_TIME;
              /* create dhcp offer and send */
              msg->op = DHCP_BOOTREPLY;
              msg->hops = 0;
              msg->secs = 0;
              SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
              msg->sname[0] = '\0';
              msg->file[0] = '\0';
              msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
              SMEMCPY(&msg->yiaddr, &node->ipaddr, 4);
  
              opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
              /* add msg type */
              *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
              *opt_buf++ = 1;
              *opt_buf++ = DHCP_OFFER;
  
              /* add server id */
              *opt_buf++ = DHCP_OPTION_SERVER_ID;
              *opt_buf++ = 4;
              SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
              opt_buf += 4;
  
              /* add_lease_time */
              *opt_buf++ = DHCP_OPTION_LEASE_TIME;
              *opt_buf++ = 4;
              tmp = PP_HTONL(DHCP_DEFAULT_LIVE_TIME);
              SMEMCPY(opt_buf, &tmp, 4);
              opt_buf += 4;
  
              /* add config */
              *opt_buf++ = DHCP_OPTION_SUBNET_MASK;
              *opt_buf++ = 4;
              SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->netmask)->addr, 4);
              opt_buf += 4;
  
              *opt_buf++ = DHCP_OPTION_DNS_SERVER;
              *opt_buf++ = 4;
  #ifdef DHCP_DNS_SERVER_IP
              {
                  ip_addr_t dns_addr;
                  ipaddr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
                  SMEMCPY(opt_buf, &ip_2_ip4(&dns_addr)->addr, 4);
              }
  #else
              /* default use gatewary dns server */
              SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
  #endif /* DHCP_DNS_SERVER_IP */
              opt_buf += 4;
  
              *opt_buf++ = DHCP_OPTION_ROUTER;
              *opt_buf++ = 4;
              SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->ip_addr)->addr, 4);
              opt_buf += 4;
  
              /* add option end */
              *opt_buf++ = DHCP_OPTION_END;
  
              length = (u32_t)opt_buf - (u32_t)msg;
              if (length < q->tot_len)
              {
                  pbuf_realloc(q, length);
              }
  
              ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
              udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
          }
          else
          {
              if (1)
              {
                  if (msg_type == DHCP_REQUEST)
                  {
                      node = dhcp_client_find(dhcp_server, msg, opt_buf, length);
                      if (node != NULL)
                      {
                          /* Send ack */
                          node->lease_end = DHCP_DEFAULT_LIVE_TIME;
                          /* create dhcp offer and send */
                          msg->op = DHCP_BOOTREPLY;
                          msg->hops = 0;
                          msg->secs = 0;
                          SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
                          msg->sname[0] = '\0';
                          msg->file[0] = '\0';
                          msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
                          SMEMCPY(&msg->yiaddr, &node->ipaddr, 4);
                          opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
  
                          /* add msg type */
                          *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
                          *opt_buf++ = 1;
                          *opt_buf++ = DHCP_ACK;
  
                          /* add server id */
                          *opt_buf++ = DHCP_OPTION_SERVER_ID;
                          *opt_buf++ = 4;
                          SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
                          opt_buf += 4;
  
                          /* add_lease_time */
                          *opt_buf++ = DHCP_OPTION_LEASE_TIME;
                          *opt_buf++ = 4;
                          tmp = PP_HTONL(DHCP_DEFAULT_LIVE_TIME);
                          SMEMCPY(opt_buf, &tmp, 4);
                          opt_buf += 4;
  
                          /* add config */
                          *opt_buf++ = DHCP_OPTION_SUBNET_MASK;
                          *opt_buf++ = 4;
                          SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->netmask)->addr, 4);
                          opt_buf += 4;
  
                          *opt_buf++ = DHCP_OPTION_DNS_SERVER;
                          *opt_buf++ = 4;
  #ifdef DHCP_DNS_SERVER_IP
                          {
                              ip_addr_t dns_addr;
                              ipaddr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
                              SMEMCPY(opt_buf, &ip_2_ip4(&dns_addr)->addr, 4);
                          }
  #else
                          /* default use gatewary dns server */
                          SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
  #endif /* DHCP_DNS_SERVER_IP */
                          opt_buf += 4;
  
                          *opt_buf++ = DHCP_OPTION_ROUTER;
                          *opt_buf++ = 4;
                          SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->ip_addr)->addr, 4);
                          opt_buf += 4;
  
                          /* add option end */
                          *opt_buf++ = DHCP_OPTION_END;
  
                          length = (u32_t)opt_buf - (u32_t)msg;
                          if (length < q->tot_len)
                          {
                              pbuf_realloc(q, length);
                          }
  
                          ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
                          udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
                      }
                      else
                      {
                          /* Send no ack */
                          /* create dhcp offer and send */
                          msg->op = DHCP_BOOTREPLY;
                          msg->hops = 0;
                          msg->secs = 0;
                          SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
                          msg->sname[0] = '\0';
                          msg->file[0] = '\0';
                          msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
                          memset(&msg->yiaddr, 0, 4);
                          opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
  
                          /* add msg type */
                          *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
                          *opt_buf++ = 1;
                          *opt_buf++ = DHCP_NAK;
  
                          /* add server id */
                          *opt_buf++ = DHCP_OPTION_SERVER_ID;
                          *opt_buf++ = 4;
                          SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
                          opt_buf += 4;
  
                          /* add option end */
                          *opt_buf++ = DHCP_OPTION_END;
                          length = (u32_t)opt_buf - (u32_t)msg;
                          if (length < q->tot_len)
                          {
                              pbuf_realloc(q, length);
                          }
  
                          ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
                          udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
                      }
                  }
                  else if (msg_type == DHCP_RELEASE)
                  {
                      struct dhcp_client_node *node_prev = NULL;
  
                      for (node = dhcp_server->node_list; node != NULL; node = node->next)
                      {
                          if (memcmp(node->chaddr, msg->chaddr, msg->hlen) == 0)
                          {
                              if (node == dhcp_server->node_list)
                              {
                                  dhcp_server->node_list = node->next;
                              }
                              else
                              {
                                  node_prev->next = node->next;
                              }
                              break;
                          }
                          node_prev = node;
                          node = node->next;
                      }
  
                      if (node != NULL)
                      {
                          mem_free(node);
                      }
                  }
                  else if (msg_type ==  DHCP_DECLINE)
                  {
                      ;
                  }
                  else if (msg_type == DHCP_INFORM)
                  {
                      ;
                  }
              }
          }
      }
  
  free_pbuf_and_return:
      pbuf_free(q);
  }
  
  /**
  * start dhcp server for a netif
  *
  * @param netif The netif which use dhcp server
  * @param start The Start IP address
  * @param end The netif which use dhcp server
  * @return lwIP error code
  * - ERR_OK - No error
  * - ERR_MEM - Out of memory
  */
  err_t
  dhcp_server_start(struct netif *netif, ip4_addr_t *start, ip4_addr_t *end)
  {
      struct dhcp_server *dhcp_server;
  
      /* If this netif alreday use the dhcp server. */
      for (dhcp_server = lw_dhcp_server; dhcp_server != NULL; dhcp_server = dhcp_server->next)
      {
          if (dhcp_server->netif == netif)
          {
              dhcp_server->start = *start;
              dhcp_server->end = *end;
              dhcp_server->current = *start;
              return ERR_OK;
          }
      }
  
      dhcp_server = NULL;
      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): starting new DHCP server\n"));
      dhcp_server = (struct dhcp_server *)mem_malloc(sizeof(struct dhcp_server));
      if (dhcp_server == NULL)
      {
          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): could not allocate dhcp\n"));
          return ERR_MEM;
      }
  
      /* clear data structure */
      memset(dhcp_server, 0, sizeof(struct dhcp_server));
  
      /* store this dhcp server to list */
      dhcp_server->next = lw_dhcp_server;
      lw_dhcp_server = dhcp_server;
      dhcp_server->netif = netif;
      dhcp_server->node_list = NULL;
      dhcp_server->start = *start;
      dhcp_server->end = *end;
      dhcp_server->current = *start;
  
      /* allocate UDP PCB */
      dhcp_server->pcb = udp_new();
      if (dhcp_server->pcb == NULL)
      {
          LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_server_start(): could not obtain pcb\n"));
          return ERR_MEM;
      }
  
      ip_set_option(dhcp_server->pcb, SOF_BROADCAST);
      /* set up local and remote port for the pcb */
      udp_bind(dhcp_server->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
      //udp_connect(dhcp_server->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
      /* set up the recv callback and argument */
      udp_recv(dhcp_server->pcb, dhcp_server_recv, dhcp_server);
      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): starting DHCP server\n"));
  
      return ERR_OK;
  }
  
  
  void dhcpd_start(const char *netif_name)
  {
      struct netif *netif = netif_list;
      err_t res;
  
      DEBUG_PRINTF("%s: %s\r\n", __FUNCTION__, netif_name);
  
      LWIP_NETIF_LOCK();
      if (strlen(netif_name) > sizeof(netif->name))
      {
          DEBUG_PRINTF("network interface name too long!\r\n");
          goto _exit;
      }
  
      while (netif != RT_NULL)
      {
          if (strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
              break;
  
          netif = netif->next;
          if (netif == RT_NULL)
          {
              DEBUG_PRINTF("network interface: %s not found!\r\n", netif_name);
              break;
          }
      }
  
      if (netif == RT_NULL)
      {
          goto _exit;
      }
  
      if (1)
      {
          extern void set_if(const char *netif_name, const char *ip_addr, const char *gw_addr, const char *nm_addr);
  
          dhcp_stop(netif);
  
          set_if(netif_name, DHCPD_SERVER_IP, "0.0.0.0", "255.255.255.0");
  
          netif_set_up(netif);
      }
  
      {
          char str_tmp[4 * 4 + 4] = DHCPD_SERVER_IP;
          char *p = str_tmp;
          ip4_addr_t ip_start, ip_end;
  
          p = strchr(str_tmp, '.');
          if (p)
          {
              p = strchr(p + 1, '.');
              if (p)
              {
                  p = strchr(p + 1, '.');
              }
          }
          if (!p)
          {
              DEBUG_PRINTF("DHCPD_SERVER_IP: %s error!\r\n", str_tmp);
              goto _exit;
          }
          p = p + 1; /* move to xxx.xxx.xxx.^ */
  
          sprintf(p, "%d", DHCPD_CLIENT_IP_MIN);
          ip4addr_aton(str_tmp, &ip_start);
          DEBUG_PRINTF("ip_start: [%s]\r\n", str_tmp);
          sprintf(p, "%d", DHCPD_CLIENT_IP_MAX);
          ip4addr_aton(str_tmp, &ip_end);
          DEBUG_PRINTF("ip_start: [%s]\r\n", str_tmp);
  
          res = dhcp_server_start(netif, &ip_start, &ip_end);
          if (res != 0)
          {
              DEBUG_PRINTF("dhcp_server_start res: %s.\r\n", res);
          }
      }
  
  _exit:
      LWIP_NETIF_UNLOCK();
      return;
  }
  
  
  