int cmd_ifconfig()

in nshlib/nsh_netcmds.c [546:1060]


int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
{
#ifdef CONFIG_NET_IPv4
  struct in_addr addr;
  in_addr_t gip = INADDR_ANY;
  in_addr_t mip;
#endif
#ifdef CONFIG_NET_IPv6
  struct in6_addr addr6;
  struct in6_addr gip6 = IN6ADDR_ANY_INIT;
  FAR char *preflen = NULL;
#  ifdef CONFIG_NETDEV_MULTIPLE_IPv6
  bool remove = false;
#  endif
#endif
  int i;
  FAR char *ifname = NULL;
  FAR char *hostip = NULL;
  FAR char *gwip = NULL;
  FAR char *mask = NULL;
  FAR char *tmp = NULL;
#ifdef HAVE_HWADDR
  FAR char *hw = NULL;
#endif
#ifdef CONFIG_NETDB_DNSCLIENT
  FAR char *dns = NULL;
#endif
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
  bool inet6 = false;
#endif
  bool missingarg = true;
  bool badarg = false;
#ifdef HAVE_HWADDR
  mac_addr_t macaddr;
#endif
  int ret;
  int mtu = 0;

  /* With one or no arguments, ifconfig simply shows the status of the
   * network device:
   *
   *   ifconfig
   *   ifconfig [interface]
   */

  if (argc <= 2)
    {
      if (argc == 2)
        {
          return ifconfig_callback(vtbl, argv[1]);
        }

      ret = nsh_foreach_netdev(ifconfig_callback, vtbl, "ifconfig");
      if (ret < 0)
        {
          return ERROR;
        }

      net_statistics(vtbl);
      return OK;
    }

  /* If both the network interface name and an IP address are supplied as
   * arguments, then ifconfig will set the address of the Ethernet device:
   *
   *    ifconfig ifname [ip_address] [named options]
   */

  if (argc > 2)
    {
      for (i = 1; i < argc; i++)
        {
          if (i == 1)
            {
              ifname = argv[i];
              missingarg = false;
            }
          else
            {
              tmp = argv[i];

              if (!strcmp(tmp, "dr") || !strcmp(tmp, "gw") ||
                  !strcmp(tmp, "gateway"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      gwip = argv[i + 1];
                      i++;
                    }
                  else
                    {
                      badarg = true;
                    }
                }
              else if (!strcmp(tmp, "netmask"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      mask = argv[i + 1];
                      i++;
                    }
                  else
                    {
                      badarg = true;
                    }
                }
              else if (!strcmp(tmp, "inet"))
                {
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
                  inet6 = false;
#elif !defined(CONFIG_NET_IPv4)
                  badarg = true;
#endif
                }
              else if (!strcmp(tmp, "inet6"))
                {
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
                  inet6 = true;
#elif !defined(CONFIG_NET_IPv6)
                  badarg = true;
#endif
                }

#ifdef CONFIG_NET_IPv6
              else if (!strcmp(tmp, "prefixlen"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      preflen = argv[i + 1];
                      i++;
                    }
                  else
                    {
                      badarg = true;
                    }
                }
#endif

#ifdef HAVE_HWADDR
              /* REVISIT: How will we handle Ethernet and SLIP together? */

              else if (!strcmp(tmp, "hw"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      hw = argv[i + 1];
                      i++;

                      badarg = nsh_addrconv(hw, &macaddr);
                    }
                  else
                    {
                      badarg = true;
                    }
                }
#endif

#ifdef CONFIG_NETDB_DNSCLIENT
              else if (!strcmp(tmp, "dns"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      dns = argv[i + 1];
                      i++;
                    }
                  else
                    {
                      badarg = true;
                    }
                }
#endif
              else if (!strcmp(tmp, "add"))
                {
#if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTIPLE_IPv6)
                  remove = false;
                  continue;
                }
              else if (!strcmp(tmp, "del"))
                {
                  remove = true;
#endif
                  continue;
                }
              else if (!strcmp(tmp, "mtu"))
                {
                  if (argc - 1 >= i + 1)
                    {
                      mtu = atoi(argv[i + 1]);
                      i++;
                      if (mtu < 1280)
                        {
                          mtu = 1280;
                        }
                    }
                  else
                    {
                      badarg = true;
                    }
                }
              else if (hostip == NULL && i <= 4)
                {
                  /* Let first non-option be host ip, to support inet/inet6
                   * options before address.
                   */

                  hostip = tmp;
                }
              else
                {
                  badarg = true;
                }
            }
        }
    }

  if (missingarg)
    {
      nsh_error(vtbl, g_fmtargrequired, argv[0]);
      return ERROR;
    }

  if (badarg)
    {
      nsh_error(vtbl, g_fmtarginvalid, argv[0]);
      return ERROR;
    }

#ifdef HAVE_HWADDR
  /* Set Hardware Ethernet MAC address */

  if (hw != NULL)
    {
      ninfo("HW MAC: %s\n", hw);
      nsh_sethwaddr(ifname, &macaddr);
    }
#endif

  if (mtu != 0)
    {
      netlib_set_mtu(ifname, mtu);
      return OK;
    }

  /* Set IP address */

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
  if (inet6)
#endif
    {
      if (hostip != NULL)
        {
          /* REVISIT: Should DHCPC check be used here too? */

          if ((tmp = strchr(hostip, '/')) != NULL)
            {
              *tmp = 0;
              if (preflen == NULL)
                {
                  preflen = tmp + 1;
                }
            }

          ninfo("Host IP: %s\n", hostip);
          ret = inet_pton(AF_INET6, hostip, &addr6);
          if (ret <= 0)
            {
              nsh_error(vtbl, g_fmtarginvalid, argv[0]);
              return ERROR;
            }
        }

#ifndef CONFIG_NETDEV_MULTIPLE_IPv6
      netlib_set_ipv6addr(ifname, &addr6);
#endif
    }
#endif /* CONFIG_NET_IPv6 */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
  else
#endif
    {
      if (hostip != NULL)
        {
#if defined(CONFIG_NETUTILS_DHCPC)
          if (strcmp(hostip, "dhcp") == 0)
            {
              /* Set DHCP addr */

              ninfo("DHCPC Mode\n");
              addr.s_addr = 0;
              gip         = 0;
            }
          else
#endif
            {
              /* Set host IP address */

              ninfo("Host IP: %s\n", hostip);
              addr.s_addr = inet_addr(hostip);
              gip         = addr.s_addr;
            }
        }
      else
        {
          addr.s_addr = 0;
        }

      netlib_set_ipv4addr(ifname, &addr);
    }
#endif /* CONFIG_NET_IPv4 */

  /* Set network mask */

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
  if (inet6)
#endif
    {
      struct in6_addr mask6;
#ifdef CONFIG_NETDEV_MULTIPLE_IPv6
      uint8_t plen;
#endif
      if (mask != NULL)
        {
          ninfo("Netmask: %s\n", mask);
          ret = inet_pton(AF_INET6, mask, &mask6);
          if (ret <= 0)
            {
              nsh_error(vtbl, g_fmtarginvalid, argv[0]);
              return ERROR;
            }
        }
      else if (preflen != NULL)
        {
          ninfo("Prefixlen: %s\n", preflen);
          netlib_prefix2ipv6netmask(atoi(preflen), &mask6);
        }
      else
        {
          ninfo("Netmask: Default\n");
          inet_pton(AF_INET6, "ffff:ffff:ffff:ffff::", &mask6);
        }

#ifdef CONFIG_NETDEV_MULTIPLE_IPv6
      plen = netlib_ipv6netmask2prefix(mask6.in6_u.u6_addr16);
      if (remove)
        {
          ret = netlib_del_ipv6addr(ifname, &addr6, plen);
        }
      else
        {
          ret = netlib_add_ipv6addr(ifname, &addr6, plen);
        }

      if (ret < 0)
        {
          perror("Failed to manage IPv6 address");

          /* REVISIT: Should we return ERROR or just let it go? */

          return ERROR;
        }
#else
      netlib_set_ipv6netmask(ifname, &mask6);
#endif /* CONFIG_NETDEV_MULTIPLE_IPv6 */
    }
#endif /* CONFIG_NET_IPv6 */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
  else
#endif
    {
      if (mask != NULL)
        {
          ninfo("Netmask: %s\n", mask);
          addr.s_addr = inet_addr(mask);
        }
      else
        {
          ninfo("Netmask: Default\n");
          addr.s_addr = inet_addr("255.255.255.0");
        }

      mip = addr.s_addr;
      netlib_set_ipv4netmask(ifname, &addr);
    }
#endif /* CONFIG_NET_IPv4 */

  /* Set gateway */

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
  if (inet6)
#endif
    {
      /* Only set the gateway address if it was explicitly provided. */

      if (gwip != NULL)
        {
          ninfo("Gateway: %s\n", gwip);
          ret = inet_pton(AF_INET6, gwip, &addr6);
          if (ret <= 0)
            {
              nsh_error(vtbl, g_fmtarginvalid, argv[0]);
              return ERROR;
            }

          netlib_set_dripv6addr(ifname, &addr6);
          gip6 = addr6;
        }
    }
#endif /* CONFIG_NET_IPv6 */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
  else
#endif
    {
      if (gwip != NULL)
        {
          ninfo("Gateway: %s\n", gwip);
          gip = addr.s_addr = inet_addr(gwip);
        }
      else
        {
          if (gip != INADDR_ANY)
            {
              ninfo("Gateway: default\n");
              gip  = ntohl(gip);
              gip &= ntohl(mip);
              gip |= 0x00000001;
              gip  = htonl(gip);
            }

          addr.s_addr = gip;
        }

      netlib_set_dripv4addr(ifname, &addr);
    }
#endif /* CONFIG_NET_IPv4 */

  UNUSED(ifname); /* Not used in all configurations */

#ifdef CONFIG_NETDB_DNSCLIENT
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
  if (inet6)
#endif
    {
      if (dns != NULL)
        {
          ninfo("DNS: %s\n", dns);
          ret = inet_pton(AF_INET6, dns, &addr6);
          if (ret <= 0)
            {
              nsh_error(vtbl, g_fmtarginvalid, argv[0]);
              return ERROR;
            }
        }
      else
        {
          ninfo("DNS: Default\n");
          addr6 = gip6;
        }

      netlib_set_ipv6dnsaddr(&addr6);
    }
#endif /* CONFIG_NET_IPv6 */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
  else
#endif
    {
      if (dns != NULL)
        {
          ninfo("DNS: %s\n", dns);
          addr.s_addr = inet_addr(dns);
        }
      else
        {
          ninfo("DNS: Default\n");
          addr.s_addr = gip;
        }

      netlib_set_ipv4dnsaddr(&addr);
    }
#endif /* CONFIG_NET_IPv4 */
#endif /* CONFIG_NETDB_DNSCLIENT */

#if defined(CONFIG_NETUTILS_DHCPC)

  if (!gip)
    {
      netlib_obtain_ipv4addr(ifname);
    }
#endif

#if !defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_IPv6)
  UNUSED(hostip);
  UNUSED(mask);
  UNUSED(gwip);
#endif
#ifdef CONFIG_NET_IPv4
  UNUSED(gip);
#endif
#ifdef CONFIG_NET_IPv6
  UNUSED(gip6);
#endif

  return OK;
}