text: /*
   * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
   * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this list of
   *    conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice, this list
   *    of conditions and the following disclaimer in the documentation and/or other materials
   *    provided with the distribution.
   *
   * 3. Neither the name of the copyright holder nor the names of its contributors may be used
   *    to endorse or promote products derived from this software without specific prior written
   *    permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <lwip/sockets.h>
  #include <lwip/priv/tcpip_priv.h>
  #include <lwip/fixme.h>
  
  #if LWIP_ENABLE_NET_CAPABILITY
  #include "capability_type.h"
  #include "capability_api.h"
  #define BIND_SERVICE_CAP_MIN_PORT 1024
  #endif
  
  #define IOCTL_CMD_CASE_HANDLER() \
      {                                                          \
          err_t  err;                                            \
          struct lwip_ioctl_apimsg msg;                          \
          msg.sock = sock;                                       \
          msg.cmd = cmd;                                         \
          msg.argp = argp;                                       \
                                                                 \
          err = tcpip_api_call(lwip_do_ioctl_impl, &msg.call);   \
          if (err != ENOSYS) {                                   \
              sock_set_errno(sock, err);                         \
              done_socket(sock);                                 \
              return -(err != ERR_OK);                           \
          }                                                      \
      }
  
  struct lwip_ioctl_apimsg {
      struct tcpip_api_call_data call;
      struct lwip_sock *sock;
      long cmd;
      void *argp;
  };
  
  static err_t lwip_do_ioctl_impl(struct tcpip_api_call_data *call);
  
  static void poll_check_waiters(int s, int check_waiters);
  
  static int lwip_socket_wrap(int domain, int type, int protocol);
  int lwip_socket(int domain, int type, int protocol)
  {
      return lwip_socket_wrap(domain, type, protocol);
  }
  
  static int lwip_setsockopt_wrap(int s, int level, int optname, const void *optval, socklen_t optlen);
  int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
  {
      return lwip_setsockopt_wrap(s, level, optname, optval, optlen);
  }
  
  static int lwip_bind_wrap(int s, const struct sockaddr *name, socklen_t namelen);
  int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
  {
      return lwip_bind_wrap(s, name, namelen);
  }
  
  static ssize_t lwip_sendto_wrap(int s, const void *dataptr, size_t size, int flags,
                                  const struct sockaddr *to, socklen_t tolen);
  ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
  {
      return lwip_sendto_wrap(s, dataptr, size, flags, to, tolen);
  }
  
  #ifdef lwip_socket
  #undef lwip_socket
  #endif
  #define lwip_socket static lwip_socket2
  static int lwip_socket2(int domain, int type, int protocol);
  
  #ifdef lwip_setsockopt
  #undef lwip_setsockopt
  #endif
  #define lwip_setsockopt static lwip_setsockopt2
  static int lwip_setsockopt2(int s, int level, int optname, const void *optval, socklen_t optlen);
  
  #ifdef lwip_bind
  #undef lwip_bind
  #endif
  #define lwip_bind static lwip_bind2
  static int lwip_bind2(int s, const struct sockaddr *name, socklen_t namelen);
  
  #ifdef lwip_sendto
  #undef lwip_sendto
  #endif
  #define lwip_sendto lwip_sendto2
  ssize_t lwip_sendto2(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
  
  #include "../api/sockets.c"
  
  #undef lwip_socket
  #undef lwip_setsockopt
  #undef lwip_bind
  #undef lwip_sendto
  
  static int lwip_socket_wrap(int domain, int type, int protocol)
  {
      if (domain != AF_INET && domain != AF_INET6) {
          set_errno(EAFNOSUPPORT);
          return -1;
      }
  #if LWIP_ENABLE_NET_CAPABILITY
      if (type == SOCK_RAW && !IsCapPermit(CAP_NET_RAW)) {
          set_errno(EPERM);
          return -1;
      }
  #endif
      return lwip_socket2(domain, type, protocol);
  }
  
  static int lwip_setsockopt_wrap(int s, int level, int optname, const void *optval, socklen_t optlen)
  {
  #if LWIP_ENABLE_NET_CAPABILITY
      if (level == SOL_SOCKET) {
          switch (optname) {
  #if LWIP_ENABLE_CAP_NET_BROADCAST
              case SO_BROADCAST:
                  if (!IsCapPermit(CAP_NET_BROADCAST)) {
                      set_errno(EPERM);
                      return -1;
                  }
                  break;
  #endif
              case SO_DEBUG:
              case SO_MARK:
              case SO_PRIORITY:
              case SO_RCVBUFFORCE:
              case SO_SNDBUFFORCE:
                  if (!IsCapPermit(CAP_NET_ADMIN)) {
                      set_errno(EPERM);
                      return -1;
                  }
                  break;
              default:
                  break;
          }
      }
  #endif
      return lwip_setsockopt2(s, level, optname, optval, optlen);
  }
  
  #if LWIP_ENABLE_NET_CAPABILITY && LWIP_ENABLE_CAP_NET_BROADCAST
  static int ip_addr_isbroadcast_bysock(const ip_addr_t *ipaddr, int s)
  {
      struct sockaddr sa;
      socklen_t salen = sizeof(sa);
  
      if (ipaddr == NULL) {
          return 0;
      }
  
      if (lwip_getsockname(s, &sa, &salen) == -1) {
          return 0;
      }
  
      ip_addr_t addr;
      u16_t port;
  
      SOCKADDR_TO_IPADDR_PORT(&sa, &addr, port);
  
      struct netif *netif = NULL;
      NETIF_FOREACH(netif) {
          if (ip_addr_cmp(&netif->ip_addr, &addr)) {
              return ip_addr_isbroadcast(ipaddr, netif);
          }
          for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
              if (ip_addr_cmp(&netif->ip6_addr[i], &addr)) {
                  return ip_addr_isbroadcast(ipaddr, netif);
              }
          }
      }
  
      return 0;
  }
  #endif
  
  static int lwip_bind_wrap(int s, const struct sockaddr *name, socklen_t namelen)
  {
  #if LWIP_ENABLE_NET_CAPABILITY
      if ((name->sa_family == AF_INET && namelen >= sizeof(struct sockaddr_in)) ||
          (name->sa_family == AF_INET6 && namelen >= sizeof(struct sockaddr_in6))) {
          ip_addr_t ipaddr;
          u16_t port;
  
          SOCKADDR_TO_IPADDR_PORT(name, &ipaddr, port);
  
          if (port != 0 && port < BIND_SERVICE_CAP_MIN_PORT) {
              LWIP_ERROR("permission deny: NET_BIND_SERVICE\n", IsCapPermit(CAP_NET_BIND_SERVICE),
                         set_errno(EPERM); return -1);
          }
  #if LWIP_ENABLE_CAP_NET_BROADCAST
          if (ip_addr_ismulticast(&ipaddr) || ip_addr_isbroadcast_bysock(&ipaddr, s)) {
              LWIP_ERROR("permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
                         set_errno(EPERM); return -1);
          }
  #endif
      }
  #endif
  
      return lwip_bind2(s, name, namelen);
  }
  
  static ssize_t lwip_sendto_wrap(int s, const void *dataptr, size_t size, int flags,
                                  const struct sockaddr *to, socklen_t tolen)
  {
  #if LWIP_ENABLE_NET_CAPABILITY
      if (to &&
          ((to->sa_family == AF_INET && tolen >= sizeof(struct sockaddr_in)) ||
           (to->sa_family == AF_INET6 && tolen >= sizeof(struct sockaddr_in6)))) {
          ip_addr_t ipaddr;
          u16_t port;
  
          SOCKADDR_TO_IPADDR_PORT(to, &ipaddr, port);
  #if LWIP_ENABLE_CAP_NET_BROADCAST
          if (ip_addr_ismulticast(&ipaddr) || ip_addr_isbroadcast_bysock(&ipaddr, s)) {
              LWIP_ERROR("permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
                         set_errno(EPERM); return -1);
          }
  #endif
      }
  #endif
  
      return lwip_sendto2(s, dataptr, size, flags, to, tolen);
  }
  
  #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
  
  struct file;
  extern void poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p);
  extern void __wake_up_interruptible_poll(wait_queue_head_t *wait, pollevent_t key);
  
  static void poll_check_waiters(int s, int check_waiters)
  {
      unsigned long int_save, wq_empty;
      pollevent_t mask = 0;
      struct lwip_sock *sock;
      SYS_ARCH_DECL_PROTECT(lev);
  
      if (!check_waiters) {
          return;
      }
  
      sock = get_socket(s);
      if (!sock) {
          return;
      }
  
      SYS_ARCH_PROTECT(lev);
  
      mask |= (sock->rcvevent > 0) ? (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) : 0;
      mask |= (sock->sendevent != 0) ? (POLLOUT | POLLWRNORM | POLLWRBAND) : 0;
      mask |= (sock->errevent != 0) ? (POLLERR) : 0;
  
      SYS_ARCH_UNPROTECT(lev);
  
      spin_lock_irqsave(&sock->wq.lock, int_save);
      wq_empty = LOS_ListEmpty(&(sock->wq.poll_queue));
      spin_unlock_irqrestore(&sock->wq.lock, int_save);
  
      if (mask && !wq_empty) {
          __wake_up_interruptible_poll(&sock->wq, mask);
      }
  
      done_socket(sock);
  }
  
  int socks_poll(int s, poll_table *wait)
  {
      int ret;
      pollevent_t mask = 0;
      struct lwip_sock *sock;
      SYS_ARCH_DECL_PROTECT(lev);
  
      LWIP_ERROR("sock_poll: invalid poll_table", (wait != NULL), return -EINVAL;);
  
      sock = get_socket(s);
      if (!sock) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("sock_poll: Invalid socket"));
          set_errno(EBADF);
          return -EBADF; /* compatible with file poll */
      }
  
      SYS_ARCH_PROTECT(lev);
  
      mask |= (sock->rcvevent > 0 || sock->lastdata.pbuf) ? (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) : 0;
      mask |= (sock->sendevent != 0) ? (POLLOUT | POLLWRNORM | POLLWRBAND) : 0;
      mask |= (sock->errevent != 0) ? (POLLERR) : 0;
  
      SYS_ARCH_UNPROTECT(lev);
  
      ret = wait->key & mask;
      if (!ret) {
          poll_wait(NULL, &sock->wq, wait);
      }
  
      done_socket(sock);
      return ret;
  }
  
  #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
  
  #if !LWIP_COMPAT_SOCKETS
  
  #define API_ALIAS(old, new) \
      extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
  
  API_ALIAS(lwip_ioctl, ioctlsocket);
  
  #endif /* !LWIP_COMPAT_SOCKETS */
  
  #if LWIP_ENABLE_LOS_SHELL_CMD
  /* get numbers of unused sockets */
  int get_unused_socket_num(void)
  {
      int unused = 0;
      SYS_ARCH_DECL_PROTECT(lev);
  
      SYS_ARCH_PROTECT(lev);
  
      for (int i = 0; i < NUM_SOCKETS; i++) {
          if (sockets[i].conn == NULL) {
  #if LWIP_NETCONN_FULLDUPLEX
              if (sockets[i].fd_used) {
                  continue;
              }
  #endif
              unused++;
          }
      }
  
      SYS_ARCH_UNPROTECT(lev);
  
      return unused;
  }
  #endif
  
  /**
   * socket ioctl
   */
  
  // Options for lwip ioctl
  #define LWIP_IOCTL_ROUTE                1
  #define LWIP_IOCTL_IF                   1
  #define LWIP_NETIF_ETHTOOL              0
  #define LWIP_IOCTL_IPV6DPCTD            0
  #undef LWIP_IPV6_DUP_DETECT_ATTEMPTS
  #define LWIP_IPV6_DUP_DETECT_ATTEMPTS   0
  
  #ifndef SIOCSIPV6DAD
  #define SIOCSIPV6DAD _IOW('z', 0, unsigned long) /* set DAD enable/disable on netif */
  #endif
  
  #ifndef SIOCGIPV6DAD
  #define SIOCGIPV6DAD _IOR('z', 1, unsigned long) /* get DAD status on netif */
  #endif
  
  #ifndef SIOCSIPV6DPCTD
  #define SIOCSIPV6DPCTD _IOW('z', 2, unsigned long)
  #endif
  
  #ifndef SIOCGIPV6DPCTD
  #define SIOCGIPV6DPCTD _IOR('z', 3, unsigned long)
  #endif
  
  #ifndef SIOCETHTOOL
  #define SIOCETHTOOL 0x8946
  #endif
  
  #if LWIP_NETIF_PROMISC
  #define NETIF_FLAG_PROMISC 0x80U
  #endif /* LWIP_NETIF_PROMISC */
  
  
  #if LWIP_IOCTL_ROUTE
  
  #include <net/route.h>
  
  static u8_t lwip_ioctl_internal_SIOCADDRT(struct rtentry *rmten)
  {
      struct netif *netif = NULL;
      ip_addr_t rtgw_addr;
      u16_t rtgw_port;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      SOCKADDR_TO_IPADDR_PORT(&rmten->rt_gateway, &rtgw_addr, rtgw_port);
  
      if (!IP_IS_V4_VAL(rtgw_addr)) {
          return EINVAL;
      }
  
      /* check if multicast/0/loopback */
      if (ip_addr_ismulticast(&rtgw_addr) || ip_addr_isany(&rtgw_addr) ||
          ip_addr_isloopback(&rtgw_addr)) {
          return EINVAL;
      }
  
      /* check if reachable */
      for (netif = netif_list; netif != NULL; netif = netif->next) {
          if (ip_addr_netcmp(&rtgw_addr, &netif->ip_addr, ip_2_ip4(&netif->netmask))) {
              break;
          }
      }
  
      if (netif == NULL) {
          return EHOSTUNREACH;
      }
  
      /* check if broadcast */
      if (ip_addr_isbroadcast(&rtgw_addr, netif) != 0) {
          return EINVAL;
      }
  
      /* Check flags */
      if ((rmten->rt_flags & RTF_GATEWAY) == 0) {
          return EINVAL;
      }
  
      /* Add validation */
      if ((netif_default != NULL) && (netif_default != netif)) {
          ip_addr_set_zero(&netif_default->gw);
          (void)netif_set_default(netif);
      }
      netif_set_gw(netif, ip_2_ip4(&rtgw_addr));
  
      return 0;
  }
  
  #endif
  
  #if LWIP_IOCTL_IF
  
  static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr)
  {
      struct ifconf *ifc = NULL;
      struct netif *netif = NULL;
      struct ifreq ifreq;
      struct sockaddr_in *sock_in = NULL;
      int pos;
      int len;
      int ret;
  
      /* Format the caller's buffer. */
      ifc = (struct ifconf *)ifr;
      len = ifc->ifc_len;
  
      /* Loop over the interfaces, and write an info block for each. */
      pos = 0;
      for (netif = netif_list; netif != NULL; netif = netif->next) {
          if (ifc->ifc_buf == NULL) {
              pos = (pos + (int)sizeof(struct ifreq));
              continue;
          }
  
          if (len < (int)sizeof(ifreq)) {
              break;
          }
          (void)memset_s(&ifreq, sizeof(struct ifreq), 0, sizeof(struct ifreq));
          if (netif->link_layer_type == LOOPBACK_IF) {
              ret = snprintf_s(ifreq.ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%.2s", netif->name);
              if ((ret <= 0) || (ret >= IFNAMSIZ)) {
                  LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
                  return ENOBUFS;
              }
          } else {
              ret = snprintf_s(ifreq.ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%s", netif_get_name(netif));
              if ((ret <= 0) || (ret >= IFNAMSIZ)) {
                  LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
                  return ENOBUFS;
              }
          }
  
          sock_in = (struct sockaddr_in *)&ifreq.ifr_addr;
          sock_in->sin_family = AF_INET;
          sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
          if (memcpy_s(ifc->ifc_buf + pos, sizeof(struct ifreq), &ifreq, sizeof(struct ifreq)) != EOK) {
              return ENOBUFS;
          }
          pos = pos + (int)sizeof(struct ifreq);
          len = len - (int)sizeof(struct ifreq);
      }
  
      ifc->ifc_len = pos;
  
      return 0;
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      struct sockaddr_in *sock_in = NULL;
  
      /* get netif ipaddr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      } else {
          sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
          sock_in->sin_family = AF_INET;
          sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
          return 0;
      }
  }
  
  #ifndef LWIP_IPV6_PREFIX_LEN
  #define LWIP_IPV6_PREFIX_LEN 64
  #endif
  
  #ifndef LWIP_NETIF_IFINDEX_MAX_EX
  #define LWIP_NETIF_IFINDEX_MAX_EX 255
  #endif
  
  #include "lwip/dhcp.h"
  #include "lwip/dhcp6.h"
  #include "lwip/prot/dhcp.h"
  #include "lwip/prot/dhcp6.h"
  
  static u8_t lwip_ioctl_internal_SIOCSIFADDR_6(struct ifreq *ifr)
  {
      (void)ifr;
      return ENOSYS;
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      struct netif *loc_netif = NULL;
      ip_addr_t taget_addr;
      u16_t taget_port;
      SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      /* set netif ipaddr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif
      else {
          /* check the address is not multicast/broadcast/0/loopback */
          if (!IP_IS_V4(&taget_addr) || ip_addr_ismulticast(&taget_addr) ||
              ip_addr_isbroadcast(&taget_addr, netif) ||
              ip_addr_isany(&taget_addr) ||
              ip_addr_isloopback(&taget_addr)) {
              return EINVAL;
          }
  
          /* reset gateway if new and previous ipaddr not in same net */
          if (ip_addr_netcmp(&taget_addr, &netif->ip_addr, ip_2_ip4(&netif->netmask)) == 0) {
              ip_addr_set_zero(&netif->gw);
              if (netif == netif_default) {
                  (void)netif_set_default(NULL);
              }
          }
  
          /* lwip disallow two netif sit in same net at the same time */
          loc_netif = netif_list;
          while (loc_netif != NULL) {
              if (loc_netif == netif) {
                  loc_netif = loc_netif->next;
                  continue;
              }
              if (ip_addr_cmp(&netif->netmask, &loc_netif->netmask) &&
                  ip_addr_netcmp(&loc_netif->ip_addr, &taget_addr,
                                 ip_2_ip4(&netif->netmask))) {
                  return EINVAL;
              }
              loc_netif = loc_netif->next;
          }
  
  #if LWIP_DHCP
          if ((netif_dhcp_data(netif) != NULL) &&
              (netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
              (void)netif_dhcp_off(netif);
          }
  #endif
  
  #if LWIP_ARP
          /* clear ARP cache when IP address changed */
          if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
              etharp_cleanup_netif(netif);
          }
  #endif /* LWIP_ARP */
  
          netif_set_ipaddr(netif, ip_2_ip4(&taget_addr));
  
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCDIFADDR_6(struct ifreq *ifr)
  {
      (void)ifr;
      return ENOSYS;
  }
  
  static u8_t lwip_ioctl_internal_SIOCDIFADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      ip_addr_t target_addr;
      u16_t target_port;
  
      SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &target_addr, target_port);
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      /* set netif ipaddr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif
  
      /* check the address is not loopback */
      if (!IP_IS_V4(&target_addr) || ip_addr_isloopback(&target_addr)) {
          return EINVAL;
      }
  
  #if LWIP_DHCP
      if ((netif_dhcp_data(netif) != NULL) &&
          (netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
          (void)netif_dhcp_off(netif);
      }
  #endif
  
      ip_addr_set_zero(&netif->gw);
      ip_addr_set_zero(&netif->ip_addr);
      ip_addr_set_zero(&netif->netmask);
      if (netif == netif_default) {
          (void)netif_set_default(NULL);
      }
  
  #if LWIP_IPV4 && LWIP_ARP
      if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
          etharp_cleanup_netif(netif);
      }
  #endif /* LWIP_IPV4 && LWIP_ARP */
  
      return ERR_OK;
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFNETMASK(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      struct sockaddr_in *sock_in = NULL;
  
      /* get netif netmask */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      } else {
          sock_in = (struct sockaddr_in *)&ifr->ifr_netmask;
          sock_in->sin_family = AF_INET;
          sock_in->sin_addr.s_addr = ip_2_ip4(&netif->netmask)->addr;
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFNETMASK(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      struct netif *loc_netif = NULL;
      ip_addr_t taget_addr;
      u16_t taget_port;
      SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      if (!IP_IS_V4(&taget_addr)) {
          return EINVAL;
      }
  
      /* set netif netmask */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif
      else {
          if (ip_addr_cmp(&netif->netmask, &taget_addr)) {
              return 0;
          }
          /* check data valid */
          if (ip_addr_netmask_valid(ip_2_ip4(&taget_addr)) != 0) {
              return EINVAL;
          }
  
          /* lwip disallow two netif sit in same net at the same time */
          loc_netif = netif_list;
          while (loc_netif != NULL) {
              if (loc_netif == netif) {
                  loc_netif = loc_netif->next;
                  continue;
              }
              if (ip_addr_cmp(&loc_netif->netmask, &taget_addr) &&
                  ip_addr_netcmp(&loc_netif->ip_addr,
                                 &netif->ip_addr, ip_2_ip4(&loc_netif->netmask))) {
                  return EINVAL;
              }
              loc_netif = loc_netif->next;
          }
  
  #if LWIP_DHCP
          if ((netif_dhcp_data(netif) != NULL) &&
              (netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
              (void)netif_dhcp_off(netif);
          }
  #endif
  
          netif_set_netmask(netif, ip_2_ip4(&taget_addr));
  
          /* check if gateway still reachable */
          if (!ip_addr_netcmp(&netif->gw, &netif->ip_addr, ip_2_ip4(&taget_addr))) {
              ip_addr_set_zero(&(netif->gw));
              if (netif == netif_default) {
                  (void)netif_set_default(NULL);
              }
          }
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFHWADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      err_t ret;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      /* set netif hw addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif
      else {
  
          /* bring netif down to clear all Neighbor Cache Entry */
          (void)netif_set_down(netif);
  
          ret = netif_set_hwaddr(netif, (const unsigned char *)ifr->ifr_hwaddr.sa_data, netif->hwaddr_len);
  
          if (ret != ERR_OK) {
              (void)netif_set_up(netif);
              return err_to_errno(ret);
          }
  
          /*
           * bring netif up to try to send GARP/IGMP/NA/MLD/RS. GARP and NA would
           * make the neighboring nodes update their Neighbor Cache immediately.
           */
          (void)netif_set_up(netif);
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFHWADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      /* get netif hw addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif /* LWIP_HAVE_LOOPIF */
      else {
          if (memcpy_s((void *)ifr->ifr_hwaddr.sa_data, sizeof(ifr->ifr_hwaddr.sa_data),
                       (void *)netif->hwaddr, netif->hwaddr_len) != EOK) {
              return EINVAL;
          }
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      /* set netif hw addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif /* LWIP_HAVE_LOOPIF */
      else {
          if (((unsigned short)ifr->ifr_flags & IFF_UP) && !(netif->flags & NETIF_FLAG_UP)) {
              (void)netif_set_up(netif);
          } else if (!((unsigned short)ifr->ifr_flags & IFF_UP) && (netif->flags & NETIF_FLAG_UP)) {
              (void)netif_set_down(netif);
          }
          if (((unsigned short)ifr->ifr_flags & IFF_RUNNING) && !(netif->flags & NETIF_FLAG_LINK_UP)) {
              (void)netif_set_link_up(netif);
          } else if (!((unsigned short)ifr->ifr_flags & IFF_RUNNING) && (netif->flags & NETIF_FLAG_LINK_UP)) {
              (void)netif_set_link_down(netif);
          }
  
          if ((unsigned short)ifr->ifr_flags & IFF_BROADCAST) {
              netif->flags |= NETIF_FLAG_BROADCAST;
          } else {
              netif->flags = netif->flags & (~NETIF_FLAG_BROADCAST);
          }
          if ((unsigned short)ifr->ifr_flags & IFF_NOARP) {
              netif->flags = (netif->flags & (~NETIF_FLAG_ETHARP));
          } else {
              netif->flags |= NETIF_FLAG_ETHARP;
          }
  
          if ((unsigned short)ifr->ifr_flags & IFF_MULTICAST) {
  #if LWIP_IGMP
              netif->flags |= NETIF_FLAG_IGMP;
  #endif /* LWIP_IGMP */
  #if LWIP_IPV6 && LWIP_IPV6_MLD
              netif->flags |= NETIF_FLAG_MLD6;
  #endif /* LWIP_IPV6_MLD */
          } else {
  #if LWIP_IGMP
              netif->flags = (netif->flags & ~NETIF_FLAG_IGMP);
  #endif /* LWIP_IGMP */
  #if LWIP_IPV6 && LWIP_IPV6_MLD
              netif->flags = (netif->flags & ~NETIF_FLAG_MLD6);
  #endif /* LWIP_IPV6_MLD */
          }
  
  #if LWIP_DHCP
          if ((unsigned short)ifr->ifr_flags & IFF_DYNAMIC) {
              (void)dhcp_start(netif);
          } else {
              dhcp_stop(netif);
  #if !LWIP_DHCP_SUBSTITUTE
              dhcp_cleanup(netif);
  #endif
          }
  #endif
  
  #if LWIP_NETIF_PROMISC
          if (((unsigned short)ifr->ifr_flags & IFF_PROMISC)) {
              netif->flags |= NETIF_FLAG_PROMISC;
          } else {
              netif->flags &= ~NETIF_FLAG_PROMISC;
          }
          if (netif->drv_config) {
              netif->drv_config(netif, IFF_PROMISC, !!((unsigned short)ifr->ifr_flags & IFF_PROMISC));
          }
  #endif /* LWIP_NETIF_PROMISC */
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      /* set netif hw addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      } else {
          if (netif->flags & NETIF_FLAG_UP) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_UP;
          } else {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_UP;
          }
          if (netif->flags & NETIF_FLAG_LINK_UP) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_RUNNING;
          } else {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_RUNNING;
          }
          if (netif->flags & NETIF_FLAG_BROADCAST) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_BROADCAST;
          } else {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_BROADCAST;
          }
          if (netif->flags & NETIF_FLAG_ETHARP) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_NOARP;
          } else {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_NOARP;
          }
  
  #if LWIP_IGMP || LWIP_IPV6_MLD
          if (
  #if LWIP_IGMP
              (netif->flags & NETIF_FLAG_IGMP)
  #endif /* LWIP_IGMP */
  #if LWIP_IGMP && LWIP_IPV6_MLD
              ||
  #endif /* LWIP_IGMP && LWIP_IPV6_MLD */
  #if LWIP_IPV6_MLD
              (netif->flags & NETIF_FLAG_MLD6)
  #endif /* LWIP_IPV6_MLD */
                  ) {
              ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_MULTICAST);
          } else {
              ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_MULTICAST));
          }
  #endif /* LWIP_IGMP || LWIP_IPV6_MLD */
  
  #if LWIP_DHCP
          //if ((netif->flags & NETIF_FLAG_DHCP) != 0) {
          if (dhcp_supplied_address(netif)) {
              ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_DYNAMIC);
          } else {
              ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_DYNAMIC));
          }
  #endif
  
  #if LWIP_HAVE_LOOPIF
          if (netif->link_layer_type == LOOPBACK_IF) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_LOOPBACK;
          }
  #endif
  
  #if LWIP_NETIF_PROMISC
          if (netif->flags & NETIF_FLAG_PROMISC) {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_PROMISC;
          } else {
              ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_PROMISC;
          }
  #endif /* LWIP_NETIF_PROMISC */
  
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      int ret;
  
      for (netif = netif_list; netif != NULL; netif = netif->next) {
          if (ifr->ifr_ifindex == netif_get_index(netif)) {
              break;
          }
      }
  
      if (netif == NULL) {
          return ENODEV;
      } else {
          if (netif->link_layer_type == LOOPBACK_IF) {
              ret = snprintf_s(ifr->ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%.2s", netif->name);
              if ((ret <= 0) || (ret >= IFNAMSIZ)) {
                  return ENOBUFS;
              }
          } else {
              ret = snprintf_s(ifr->ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%s", netif_get_name(netif));
              if ((ret <= 0) || (ret >= IFNAMSIZ)) {
                  return ENOBUFS;
              }
          }
          return 0;
      }
  }
  
  static bool lwip_validate_ifname(const char *name, u8_t *let_pos)
  {
      unsigned short num_pos = 0;
      unsigned short letter_pos = 0;
      unsigned short pos = 0;
      bool have_num = 0;
  
      /* if the first position of variable name is not letter, such as '6eth2' */
      if (((*name >= 'a') && (*name <= 'z')) || ((*name >= 'A') && (*name <= 'Z'))) {
          return 0;
      }
  
      /* check if the position of letter is bigger than the the position of digital */
      while (*name != '\0') {
          if ((*name >= '0') && (*name <= '9')) {
              num_pos = pos;
              have_num = 1;
          } else if (((*name >= 'a') && (*name <= 'z')) || ((*name >= 'A') && (*name <= 'Z'))) {
              letter_pos = pos;
              if (have_num != 0) {
                  return 0;
              }
          } else {
              return 0;
          }
          pos++;
          name++;
      }
  
      /* for the speacil case as all position of variable name is letter, such as 'ethabc' */
      if (num_pos == 0) {
          return 0;
      }
  
      /* cheak if the digital in the variable name is bigger than 255, such as 'eth266' */
      if (atoi(name - (pos - letter_pos - 1)) > 255) {
          return 0;
      }
  
      *let_pos = (u8_t)letter_pos;
  
      return 1;
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFNAME(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      u8_t letter_pos = 0;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      netif = netif_find(ifr->ifr_name);
  
      if (netif == NULL) {
          return ENODEV;
      } else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      } else if ((netif->flags & IFF_UP) != 0) {
          return EBUSY;
      } else {
          if (strncmp(ifr->ifr_name, ifr->ifr_newname, IFNAMSIZ) == 0) {
              /* not change */
              return 0;
          }
  
          ifr->ifr_newname[IFNAMSIZ - 1] = '\0';
          if ((lwip_validate_ifname(ifr->ifr_newname, &letter_pos) == 0) || (strlen(ifr->ifr_newname) > (IFNAMSIZ - 1))) {
              return EINVAL;
          }
  
          if (strncpy_s(netif->full_name, sizeof(netif->full_name), ifr->ifr_newname, strlen(ifr->ifr_newname)) != EOK) {
              return EINVAL;
          }
      }
  
      return 0;
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      } else {
          ifr->ifr_ifindex = netif_get_index(netif);
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCSIFMTU(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      /* set netif hw addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
  #if LWIP_HAVE_LOOPIF
          /* the mtu of loopif is not used. */
      else if (netif->link_layer_type == LOOPBACK_IF) {
          return EPERM;
      }
  #endif
      else {
          if (ERR_OK != netif_set_mtu(netif, (u16_t)ifr->ifr_mtu)) {
              return EINVAL;
          }
  
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFMTU(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
  
      /* get netif hw addr */
      netif = netif_find(ifr->ifr_name);
  
      if (netif == NULL) {
          return ENODEV;
      } else {
          ifr->ifr_mtu = netif->mtu;
          return 0;
      }
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIFBRDADDR(struct ifreq *ifr)
  {
      struct netif *netif = NULL;
      struct sockaddr_in *sock_in = NULL;
  
      /* get netif subnet broadcast addr */
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      }
      if (ip4_addr_isany_val(*(ip_2_ip4(&netif->netmask)))) {
          return ENXIO;
      }
      sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
      sock_in->sin_family = AF_INET;
      sock_in->sin_addr.s_addr = (ip_2_ip4(&((netif)->ip_addr))->addr | ~(ip_2_ip4(&netif->netmask)->addr));
      return 0;
  }
  
  #endif /* LWIP_IOCTL_IF */
  
  #if LWIP_NETIF_ETHTOOL
  
  static s32_t lwip_ioctl_internal_SIOCETHTOOL(struct ifreq *ifr)
  {
      struct netif *netif;
  
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      netif = netif_find(ifr->ifr_name);
      if (netif == NULL) {
          return ENODEV;
      } else {
          return dev_ethtool(netif, ifr);
      }
  }
  
  #endif
  
  #if LWIP_IPV6
  #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
  
  static u8_t lwip_ioctl_internal_SIOCSIPV6DAD(struct ifreq *ifr)
  {
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      struct netif *tmpnetif = netif_find(ifr->ifr_name);
      if (tmpnetif == NULL) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
          return ENODEV;
      }
  
      if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
          return EBADRQC;
      }
  
      if (ifr->ifr_ifru.ifru_ivalue == 1) {
          tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DAD);
  
          LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned on through ioctl for  %s iface index %u \n",
                  tmpnetif->name, tmpnetif->num));
      } else {
          tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DAD) & 0xffU));
  
          LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned off through ioctl for  %s iface index %u \n",
                  tmpnetif->name, tmpnetif->num));
      }
      return 0;
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIPV6DAD(struct ifreq *ifr)
  {
      struct netif *tmpnetif = netif_find(ifr->ifr_name);
      if (tmpnetif == NULL) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
          return ENODEV;
      }
      ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DAD) ? 1 : 0;
      return 0;
  }
  
  #endif
  
  #if LWIP_IOCTL_IPV6DPCTD
  
  static u8_t lwip_ioctl_internal_SIOCSIPV6DPCTD(struct ifreq *ifr)
  {
  #if LWIP_ENABLE_NET_CAPABILITY
      if (!IsCapPermit(CAP_NET_ADMIN)) {
          return EPERM;
      }
  #endif
  
      struct netif *tmpnetif = netif_find(ifr->ifr_name);
      if (tmpnetif == NULL) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
          return ENODEV;
      }
      if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
          return EBADRQC;
      }
      if (ifr->ifr_ifru.ifru_ivalue == 1) {
          tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DEPRECATED);
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned on through ioctl for  %s iface index %u \n",
                  tmpnetif->name, tmpnetif->num));
      } else {
          tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DEPRECATED) & 0xffU));
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned off through ioctl for  %s iface index %u \n",
                  tmpnetif->name, tmpnetif->num));
      }
      return 0;
  }
  
  static u8_t lwip_ioctl_internal_SIOCGIPV6DPCTD(struct ifreq *ifr)
  {
      struct netif *tmpnetif = netif_find(ifr->ifr_name);
      if (tmpnetif == NULL) {
          LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
          return ENODEV;
      }
  
      ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DEPRECATED) ? 1 : 0;
      return 0;
  }
  
  #endif /* LWIP_IOCTL_IPV6DPCTD */
  #endif
  
  static u8_t lwip_ioctl_impl(const struct lwip_sock *sock, long cmd, void *argp)
  {
      u8_t err = 0;
  #if LWIP_NETIF_ETHTOOL
      s32_t ret;
  #endif
  #if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_IF || LWIP_NETIF_ETHTOOL
      struct ifreq *ifr = (struct ifreq *)argp;
  #endif
  #if LWIP_IOCTL_ROUTE
      struct rtentry *rmten = (struct rtentry *)argp;
  #endif
  #if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_ROUTE || LWIP_IOCTL_IF
      bool is_ipv6 = 0;
  
      /* allow it only on IPv6 sockets... */
      is_ipv6 = NETCONNTYPE_ISIPV6((unsigned int)(sock->conn->type));
  #endif
  
      switch ((u32_t)cmd) {
  #if LWIP_IPV6
  #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
          case SIOCSIPV6DAD:
              /* allow it only on IPv6 sockets... */
              if (is_ipv6 == 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCSIPV6DAD(ifr);
              }
              break;
          case SIOCGIPV6DAD:
              /* allow it only on IPv6 sockets... */
              if (is_ipv6 == 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIPV6DAD(ifr);
              }
              break;
  #endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
  #if LWIP_IOCTL_IPV6DPCTD
          case SIOCSIPV6DPCTD:
              /* allow it only on IPv6 sockets... */
              if (is_ipv6 == 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCSIPV6DPCTD(ifr);
              }
              break;
          case SIOCGIPV6DPCTD:
              /* allow it only on IPv6 sockets... */
              if (is_ipv6 == 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIPV6DPCTD(ifr);
              }
              break;
  #endif
  #endif /* LWIP_IPV6 */
  #if LWIP_IOCTL_ROUTE
          case SIOCADDRT:
              /* Do not allow if socket is AF_INET6 */
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCADDRT(rmten);
              }
              break;
  #endif
  #if LWIP_IOCTL_IF
          case SIOCGIFCONF:
              /* Do not allow if socket is AF_INET6 */
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIFCONF(ifr);
              }
              break;
          case SIOCGIFADDR:
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIFADDR(ifr);
              }
              break;
          case SIOCSIFADDR:
              if (is_ipv6 != 0) {
                  err = lwip_ioctl_internal_SIOCSIFADDR_6(ifr);
              } else {
                  err = lwip_ioctl_internal_SIOCSIFADDR(ifr);
              }
              break;
          case SIOCDIFADDR:
              /* Delete interface address */
              if (is_ipv6 != 0) {
                  err = lwip_ioctl_internal_SIOCDIFADDR_6(ifr);
              } else {
                  err = lwip_ioctl_internal_SIOCDIFADDR(ifr);
              }
              break;
          case SIOCGIFNETMASK:
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIFNETMASK(ifr);
              }
              break;
          case SIOCSIFNETMASK:
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCSIFNETMASK(ifr);
              }
              break;
          case SIOCSIFHWADDR:
              err = lwip_ioctl_internal_SIOCSIFHWADDR(ifr);
              break;
          case SIOCGIFHWADDR:
              err = lwip_ioctl_internal_SIOCGIFHWADDR(ifr);
              break;
          case SIOCSIFFLAGS:
              err = lwip_ioctl_internal_SIOCSIFFLAGS(ifr);
              break;
          case SIOCGIFFLAGS:
              err = lwip_ioctl_internal_SIOCGIFFLAGS(ifr);
              break;
          case SIOCGIFNAME:
              err = lwip_ioctl_internal_SIOCGIFNAME(ifr);
              break;
          case SIOCSIFNAME:
              err = lwip_ioctl_internal_SIOCSIFNAME(ifr);
              break;
              /* Need to support the get index through ioctl
               * As of now the options is restricted to PF_PACKET scenario , so removed the compiler flag Begin
               */
          case SIOCGIFINDEX:
              err = lwip_ioctl_internal_SIOCGIFINDEX(ifr);
              break;
          case SIOCGIFMTU:
              err = lwip_ioctl_internal_SIOCGIFMTU(ifr);
              break;
          case SIOCSIFMTU:
              err = lwip_ioctl_internal_SIOCSIFMTU(ifr);
              break;
          case SIOCGIFBRDADDR:
              if (is_ipv6 != 0) {
                  err = EINVAL;
              } else {
                  err = lwip_ioctl_internal_SIOCGIFBRDADDR(ifr);
              }
              break;
  #endif /* LWIP_IOCTL_IF */
  #if LWIP_NETIF_ETHTOOL
          case SIOCETHTOOL:
              ret = lwip_ioctl_internal_SIOCETHTOOL(ifr);
              if (ret != 0) {
                  /* an IO error happened */
                  err = EIO;
              }
              break;
  #endif
              /* START For cmd = -1 stack has to treat it as Invalid Input and return EINVAL */
          case 0xFFFFFFFF:
              err = EINVAL;
              LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl_impl(INVALID: 0x%lx)\n", cmd));
              break;
          default:
              err = ENOSYS;
              LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(UNIMPL: 0x%lx)\n", cmd));
              break;
      }
  
      return err;
  }
  
  static err_t lwip_do_ioctl_impl(struct tcpip_api_call_data *call)
  {
      struct lwip_ioctl_apimsg *msg = (struct lwip_ioctl_apimsg *)(void *)call;
      return lwip_ioctl_impl(msg->sock, msg->cmd, msg->argp);
  }
  
  #include "los_vm_map.h"
  #include "user_copy.h"
  static int do_ioctl_SIOCGIFCONF(int sockfd, long cmd, void *argp)
  {
      int nbytes;
      struct ifconf ifc;
      char *buf_bak = NULL;
      int ret;
  
      if (LOS_ArchCopyFromUser(&ifc, argp, sizeof(struct ifconf)) != 0) {
          set_errno(EFAULT);
          return -1;
      }
      nbytes = ifc.ifc_len;
      if (nbytes <= 0) {
          set_errno(EINVAL);
          return -1;
      }
      buf_bak = ifc.ifc_buf;
      if (!LOS_IsUserAddress((VADDR_T)(uintptr_t)buf_bak)) {
          set_errno(EFAULT);
          return -1;
      }
      ifc.ifc_buf = malloc(nbytes);
      if (ifc.ifc_buf == NULL) {
          set_errno(ENOMEM);
          return -1;
      }
      (void)memset_s(ifc.ifc_buf, nbytes, 0, nbytes);
  
      ret = lwip_ioctl(sockfd, cmd, &ifc);
      if (ret == 0) {
          if (LOS_ArchCopyToUser(buf_bak, ifc.ifc_buf, nbytes) != 0) {
              set_errno(EFAULT);
              ret = -1;
          }
      }
  
      free(ifc.ifc_buf);
      ifc.ifc_buf = buf_bak;
      if (LOS_ArchCopyToUser(argp, &ifc, sizeof(struct ifconf)) != 0) {
          set_errno(EFAULT);
          ret = -1;
      }
      return ret;
  }
  
  int socks_ioctl(int sockfd, long cmd, void *argp)
  {
      void *argpbak = argp;
      int ret;
      size_t nbytes = 0;
  
      if (LOS_IsUserAddress((VADDR_T)(uintptr_t)argp)) {
          switch (cmd) {
              case FIONREAD:
              case FIONBIO:
                  nbytes = sizeof(int);
                  break;
              case SIOCADDRT:
                  nbytes = sizeof(struct rtentry);
                  break;
              case SIOCGIFCONF:
                  return do_ioctl_SIOCGIFCONF(sockfd, cmd, argp);
              case SIOCSIPV6DAD:
              case SIOCGIPV6DAD:
              case SIOCSIPV6DPCTD:
              case SIOCGIPV6DPCTD:
              case SIOCGIFADDR:
              case SIOCSIFADDR:
              case SIOCDIFADDR:
              case SIOCGIFNETMASK:
              case SIOCSIFNETMASK:
              case SIOCSIFHWADDR:
              case SIOCGIFHWADDR:
              case SIOCSIFFLAGS:
              case SIOCGIFFLAGS:
              case SIOCGIFNAME:
              case SIOCSIFNAME:
              case SIOCGIFINDEX:
              case SIOCGIFMTU:
              case SIOCSIFMTU:
              case SIOCETHTOOL:
              case SIOCGIFBRDADDR:
                  nbytes = sizeof(struct ifreq);
                  break;
              default:
                  nbytes = 0;
          }
          if (argp != NULL && nbytes > 0) {
              argp = malloc(nbytes);
              if (argp == NULL) {
                  set_errno(ENOMEM);
                  return -1;
              }
              if (LOS_ArchCopyFromUser(argp, argpbak, nbytes) != 0) {
                  free(argp);
                  set_errno(EFAULT);
                  return -1;
              }
          }
      }
      ret = lwip_ioctl(sockfd, cmd, argp);
      if (ret == 0 && argp != argpbak) {
          if (LOS_ArchCopyToUser(argpbak, argp, nbytes) != 0) {
              /* how to rollback ioctl ? */
              set_errno(EFAULT);
              ret = -1;
          }
      }
      if (argp != argpbak) {
          free(argp);
      }
      return ret;
  }
  
  void socks_refer(int sockfd)
  {
      struct lwip_sock *sock = NULL;
      SYS_ARCH_DECL_PROTECT(lev);
  
      sock = get_socket(sockfd);
      if (!sock) {
          return;
      }
  
      SYS_ARCH_PROTECT(lev);
  
      sock->s_refcount++;
  
      SYS_ARCH_UNPROTECT(lev);
  
      done_socket(sock);
  }
  
  int socks_close(int sockfd)
  {
      struct lwip_sock *sock = NULL;
      SYS_ARCH_DECL_PROTECT(lev);
  
      sock = get_socket(sockfd);
      if (!sock) {
          return -1;
      }
  
      SYS_ARCH_PROTECT(lev);
  
      if (sock->s_refcount == 0) {
          SYS_ARCH_UNPROTECT(lev);
          done_socket(sock);
          return lwip_close(sockfd);
      }
  
      sock->s_refcount--;
  
      SYS_ARCH_UNPROTECT(lev);
      done_socket(sock);
      return 0;
  }
  