[PATCH 4/4] iphlpapi: Implement GetAdaptersAddresses() on top of nsi.

Huw Davies huw at codeweavers.com
Mon Aug 9 04:06:28 CDT 2021


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/iphlpapi/ifenum.c        | 671 +---------------------------------
 dlls/iphlpapi/ifenum.h        |  42 ---
 dlls/iphlpapi/iphlpapi_main.c | 647 ++++++++++++--------------------
 3 files changed, 233 insertions(+), 1127 deletions(-)

diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index 8108c7ff8c2..9cb576f86fd 100644
--- a/dlls/iphlpapi/ifenum.c
+++ b/dlls/iphlpapi/ifenum.c
@@ -122,7 +122,7 @@ static BOOL isLoopbackInterface(int fd, const char *name)
 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
  * bytes are necessary.
  */
-char *getInterfaceNameByIndex(IF_INDEX index, char *name)
+static char *getInterfaceNameByIndex(IF_INDEX index, char *name)
 {
   return if_indextoname(index, name);
 }
@@ -146,7 +146,7 @@ DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
   return ret;
 }
 
-BOOL isIfIndexLoopback(ULONG idx)
+static BOOL isIfIndexLoopback(ULONG idx)
 {
   BOOL ret = FALSE;
   char name[IFNAMSIZ];
@@ -394,670 +394,3 @@ DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
 }
 #endif
 
-static DWORD getInterfaceBCastAddrByName(const char *name)
-{
-  DWORD ret = INADDR_ANY;
-
-  if (name) {
-    int fd = socket(PF_INET, SOCK_DGRAM, 0);
-
-    if (fd != -1) {
-      struct ifreq ifr;
-
-      lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-      if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
-        memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
-      close(fd);
-    }
-  }
-  return ret;
-}
-
-static DWORD getInterfaceMaskByName(const char *name)
-{
-  DWORD ret = INADDR_NONE;
-
-  if (name) {
-    int fd = socket(PF_INET, SOCK_DGRAM, 0);
-
-    if (fd != -1) {
-      struct ifreq ifr;
-
-      lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-      if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
-        memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
-      close(fd);
-    }
-  }
-  return ret;
-}
-
-#if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
-static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
- PDWORD type)
-{
-  DWORD ret;
-  int fd;
-
-  if (!name || !len || !addr || !type)
-    return ERROR_INVALID_PARAMETER;
-
-  fd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (fd != -1) {
-    struct ifreq ifr;
-
-    memset(&ifr, 0, sizeof(struct ifreq));
-    lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-    if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
-      ret = ERROR_INVALID_DATA;
-    else {
-      unsigned int addrLen;
-
-      switch (ifr.ifr_hwaddr.sa_family)
-      {
-#ifdef ARPHRD_LOOPBACK
-        case ARPHRD_LOOPBACK:
-          addrLen = 0;
-          *type = MIB_IF_TYPE_LOOPBACK;
-          break;
-#endif
-#ifdef ARPHRD_ETHER
-        case ARPHRD_ETHER:
-          addrLen = ETH_ALEN;
-          *type = MIB_IF_TYPE_ETHERNET;
-          break;
-#endif
-#ifdef ARPHRD_FDDI
-        case ARPHRD_FDDI:
-          addrLen = ETH_ALEN;
-          *type = MIB_IF_TYPE_FDDI;
-          break;
-#endif
-#ifdef ARPHRD_IEEE802
-        case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
-          addrLen = ETH_ALEN;
-          *type = MIB_IF_TYPE_TOKENRING;
-          break;
-#endif
-#ifdef ARPHRD_IEEE802_TR
-        case ARPHRD_IEEE802_TR: /* also Token Ring? */
-          addrLen = ETH_ALEN;
-          *type = MIB_IF_TYPE_TOKENRING;
-          break;
-#endif
-#ifdef ARPHRD_SLIP
-        case ARPHRD_SLIP:
-          addrLen = 0;
-          *type = MIB_IF_TYPE_SLIP;
-          break;
-#endif
-#ifdef ARPHRD_PPP
-        case ARPHRD_PPP:
-          addrLen = 0;
-          *type = MIB_IF_TYPE_PPP;
-          break;
-#endif
-        default:
-          addrLen = 0;
-          *type = MIB_IF_TYPE_OTHER;
-      }
-      if (addrLen > *len) {
-        ret = ERROR_INSUFFICIENT_BUFFER;
-        *len = addrLen;
-      }
-      else {
-        if (addrLen > 0)
-          memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
-        /* zero out remaining bytes for broken implementations */
-        memset(addr + addrLen, 0, *len - addrLen);
-        *len = addrLen;
-        ret = NO_ERROR;
-      }
-    }
-    close(fd);
-  }
-  else
-    ret = ERROR_NO_MORE_FILES;
-  return ret;
-}
-#elif defined (SIOCGARP)
-static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
- PDWORD type)
-{
-  DWORD ret;
-  int fd;
-
-  if (!name || !len || !addr || !type)
-    return ERROR_INVALID_PARAMETER;
-
-  fd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (fd != -1) {
-    if (isLoopbackInterface(fd, name)) {
-      *type = MIB_IF_TYPE_LOOPBACK;
-      memset(addr, 0, *len);
-      *len = 0;
-      ret=NOERROR;
-    }
-    else {
-      struct arpreq arp;
-      struct sockaddr_in *saddr;
-      struct ifreq ifr;
-
-      /* get IP addr */
-      lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-      ioctl(fd, SIOCGIFADDR, &ifr);
-      memset(&arp, 0, sizeof(struct arpreq));
-      arp.arp_pa.sa_family = AF_INET;
-      saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
-      saddr->sin_family = AF_INET;
-      memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
-      if ((ioctl(fd, SIOCGARP, &arp)))
-        ret = ERROR_INVALID_DATA;
-      else {
-        /* FIXME:  heh:  who said it was ethernet? */
-        int addrLen = ETH_ALEN;
-
-        if (addrLen > *len) {
-          ret = ERROR_INSUFFICIENT_BUFFER;
-          *len = addrLen;
-        }
-        else {
-          if (addrLen > 0)
-            memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
-          /* zero out remaining bytes for broken implementations */
-          memset(addr + addrLen, 0, *len - addrLen);
-          *len = addrLen;
-          *type = MIB_IF_TYPE_ETHERNET;
-          ret = NO_ERROR;
-        }
-      }
-    }
-    close(fd);
-  }
-    else
-      ret = ERROR_NO_MORE_FILES;
-
-  return ret;
-}
-#elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
-static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
- PDWORD type)
-{
-  DWORD ret;
-  struct if_msghdr *ifm;
-  struct sockaddr_dl *sdl;
-  u_char *p, *buf;
-  size_t mibLen;
-  int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
-  unsigned addrLen;
-  BOOL found = FALSE;
-
-  if (!name || !len || !addr || !type)
-    return ERROR_INVALID_PARAMETER;
-
-  if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
-    return ERROR_NO_MORE_FILES;
-
-  buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
-  if (!buf)
-    return ERROR_NOT_ENOUGH_MEMORY;
-
-  if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
-    HeapFree(GetProcessHeap(), 0, buf);
-    return ERROR_NO_MORE_FILES;
-  }
-
-  ret = ERROR_INVALID_DATA;
-  for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
-    ifm = (struct if_msghdr *)p;
-    sdl = (struct sockaddr_dl *)(ifm + 1);
-
-    if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
-      continue;
-
-    if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
-     memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
-      continue;
-
-    found = TRUE;
-    addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
-    if (addrLen > *len) {
-      ret = ERROR_INSUFFICIENT_BUFFER;
-      *len = addrLen;
-    }
-    else {
-      if (addrLen > 0)
-        memcpy(addr, LLADDR(sdl), addrLen);
-      /* zero out remaining bytes for broken implementations */
-      memset(addr + addrLen, 0, *len - addrLen);
-      *len = addrLen;
-#if defined(HAVE_NET_IF_TYPES_H)
-      switch (sdl->sdl_type)
-      {
-        case IFT_ETHER:
-          *type = MIB_IF_TYPE_ETHERNET;
-          break;
-        case IFT_FDDI:
-          *type = MIB_IF_TYPE_FDDI;
-          break;
-        case IFT_ISO88024: /* Token Bus */
-          *type = MIB_IF_TYPE_TOKENRING;
-          break;
-        case IFT_ISO88025: /* Token Ring */
-          *type = MIB_IF_TYPE_TOKENRING;
-          break;
-        case IFT_PPP:
-          *type = MIB_IF_TYPE_PPP;
-          break;
-        case IFT_SLIP:
-          *type = MIB_IF_TYPE_SLIP;
-          break;
-        case IFT_LOOP:
-          *type = MIB_IF_TYPE_LOOPBACK;
-          break;
-        default:
-          *type = MIB_IF_TYPE_OTHER;
-      }
-#else
-      /* default if we don't know */
-      *type = MIB_IF_TYPE_ETHERNET;
-#endif
-      ret = NO_ERROR;
-    }
-  }
-  HeapFree(GetProcessHeap(), 0, buf);
-  return ret;
-}
-#endif
-
-DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
- PDWORD type)
-{
-  char nameBuf[IF_NAMESIZE];
-  char *name = getInterfaceNameByIndex(index, nameBuf);
-
-  if (name)
-    return getInterfacePhysicalByName(name, len, addr, type);
-  else
-    return ERROR_INVALID_DATA;
-}
-
-DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
-{
-  DWORD ret;
-  int fd;
-
-  if (!name)
-    return ERROR_INVALID_PARAMETER;
-  if (!mtu)
-    return ERROR_INVALID_PARAMETER;
-
-  fd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (fd != -1) {
-    struct ifreq ifr;
-
-    lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-    if ((ioctl(fd, SIOCGIFMTU, &ifr)))
-      ret = ERROR_INVALID_DATA;
-    else {
-#ifndef __sun
-      *mtu = ifr.ifr_mtu;
-#else
-      *mtu = ifr.ifr_metric;
-#endif
-      ret = NO_ERROR;
-    }
-    close(fd);
-  }
-  else
-    ret = ERROR_NO_MORE_FILES;
-  return ret;
-}
-
-DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status)
-{
-  DWORD ret;
-  int fd;
-
-  if (!name)
-    return ERROR_INVALID_PARAMETER;
-  if (!status)
-    return ERROR_INVALID_PARAMETER;
-
-  fd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (fd != -1) {
-    struct ifreq ifr;
-
-    lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-    if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
-      ret = ERROR_INVALID_DATA;
-    else {
-      if (ifr.ifr_flags & IFF_UP)
-        *status = MIB_IF_OPER_STATUS_OPERATIONAL;
-      else
-        *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
-      ret = NO_ERROR;
-    }
-    close(fd);
-  }
-  else
-    ret = ERROR_NO_MORE_FILES;
-  return ret;
-}
-
-static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
- const struct sockaddr *sa)
-{
-  DWORD ret, bcast;
-
-  ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
-  memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
-  ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
-  /* the dwBCastAddr member isn't the broadcast address, it indicates whether
-   * the interface uses the 1's broadcast address (1) or the 0's broadcast
-   * address (0).
-   */
-  bcast = getInterfaceBCastAddrByName(ifName);
-  ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
-  /* FIXME: hardcoded reasm size, not sure where to get it */
-  ipAddrRow->dwReasmSize = 65535;
-  ipAddrRow->unused1 = 0;
-  /* wType is a bit field composed of MIB_IPADDR_* flags. Windows <= XP seems
-   * to like returning undocumented values 0x20 + 0x02 but for our current
-   * needs returning MIB_IPADDR_PRIMARY is enough.
-   */
-  ipAddrRow->wType = MIB_IPADDR_PRIMARY;
-  return ret;
-}
-
-#if defined(HAVE_IFADDRS_H) && defined(HAVE_GETIFADDRS)
-
-/* Counts the IPv4 addresses in the system using the return value from
- * getifaddrs, returning the count.
- */
-static DWORD countIPv4Addresses(struct ifaddrs *ifa)
-{
-  DWORD numAddresses = 0;
-
-  for (; ifa; ifa = ifa->ifa_next)
-    if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
-      numAddresses++;
-  return numAddresses;
-}
-
-DWORD getNumIPAddresses(void)
-{
-  DWORD numAddresses = 0;
-  struct ifaddrs *ifa;
-
-  if (!getifaddrs(&ifa))
-  {
-    numAddresses = countIPv4Addresses(ifa);
-    freeifaddrs(ifa);
-  }
-  return numAddresses;
-}
-
-DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
-{
-  DWORD ret;
-
-  if (!ppIpAddrTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else
-  {
-    struct ifaddrs *ifa;
-
-    if (!getifaddrs(&ifa))
-    {
-      DWORD size = sizeof(MIB_IPADDRTABLE);
-      DWORD numAddresses = countIPv4Addresses(ifa);
-
-      if (numAddresses > 1)
-        size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
-      *ppIpAddrTable = HeapAlloc(heap, flags, size);
-      if (*ppIpAddrTable)
-      {
-        DWORD i = 0;
-        struct ifaddrs *ifp;
-
-        ret = NO_ERROR;
-        (*ppIpAddrTable)->dwNumEntries = numAddresses;
-        for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
-        {
-          if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
-            continue;
-
-          ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
-           ifp->ifa_addr);
-          i++;
-        }
-        if (ret)
-          HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
-      }
-      else
-        ret = ERROR_OUTOFMEMORY;
-      freeifaddrs(ifa);
-    }
-    else
-      ret = ERROR_INVALID_PARAMETER;
-  }
-  return ret;
-}
-
-ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
-{
-  struct ifaddrs *ifa;
-  ULONG ret;
-
-  if (!getifaddrs(&ifa))
-  {
-    struct ifaddrs *p;
-    ULONG n;
-    char name[IFNAMSIZ];
-
-    getInterfaceNameByIndex(index, name);
-    for (p = ifa, n = 0; p; p = p->ifa_next)
-      if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
-          !strcmp(name, p->ifa_name))
-        n++;
-    if (n)
-    {
-      *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
-                         sizeof(struct WS_sockaddr_in6)));
-      *masks = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
-                         sizeof(struct WS_sockaddr_in6)));
-      if (*addrs && *masks)
-      {
-        struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
-            (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
-        struct WS_sockaddr_in6 *mask_addr = (struct WS_sockaddr_in6 *)(
-            (BYTE *)*masks + n * sizeof(SOCKET_ADDRESS));
-
-        for (p = ifa, n = 0; p; p = p->ifa_next)
-        {
-          if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
-              !strcmp(name, p->ifa_name))
-          {
-            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
-            struct sockaddr_in6 *mask = (struct sockaddr_in6 *)p->ifa_netmask;
-
-            next_addr->sin6_family = WS_AF_INET6;
-            next_addr->sin6_port = addr->sin6_port;
-            next_addr->sin6_flowinfo = addr->sin6_flowinfo;
-            memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
-             sizeof(next_addr->sin6_addr));
-            next_addr->sin6_scope_id = addr->sin6_scope_id;
-            (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
-            (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
-            next_addr++;
-
-            mask_addr->sin6_family = WS_AF_INET6;
-            mask_addr->sin6_port = mask->sin6_port;
-            mask_addr->sin6_flowinfo = mask->sin6_flowinfo;
-            memcpy(&mask_addr->sin6_addr, &mask->sin6_addr,
-             sizeof(mask_addr->sin6_addr));
-            mask_addr->sin6_scope_id = mask->sin6_scope_id;
-            (*masks)[n].lpSockaddr = (LPSOCKADDR)mask_addr;
-            (*masks)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
-            mask_addr++;
-            n++;
-          }
-        }
-        *num_addrs = n;
-        ret = ERROR_SUCCESS;
-      }
-      else
-      {
-        HeapFree(GetProcessHeap(), 0, *addrs);
-        HeapFree(GetProcessHeap(), 0, *masks);
-        ret = ERROR_OUTOFMEMORY;
-      }
-    }
-    else
-    {
-      *addrs = NULL;
-      *num_addrs = 0;
-      *masks = NULL;
-      ret = ERROR_SUCCESS;
-    }
-    freeifaddrs(ifa);
-  }
-  else
-    ret = ERROR_NO_DATA;
-  return ret;
-}
-
-#else
-
-/* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
- * the count to you in *pcAddresses.  It also returns to you the struct ifconf
- * used by the call to ioctl, so that you may process the addresses further.
- * Free ifc->ifc_buf using HeapFree.
- * Returns NO_ERROR on success, something else on failure.
- */
-static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
-{
-  DWORD ret;
-  int fd;
-
-  fd = socket(PF_INET, SOCK_DGRAM, 0);
-  if (fd != -1) {
-    int ioctlRet = 0;
-    DWORD guessedNumAddresses = 0, numAddresses = 0;
-    caddr_t ifPtr;
-    int lastlen;
-
-    ret = NO_ERROR;
-    ifc->ifc_len = 0;
-    ifc->ifc_buf = NULL;
-    /* there is no way to know the interface count beforehand,
-       so we need to loop again and again upping our max each time
-       until returned is constant across 2 calls */
-    do {
-      lastlen = ifc->ifc_len;
-      HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
-      if (guessedNumAddresses == 0)
-        guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
-      else
-        guessedNumAddresses *= 2;
-      ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
-      ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
-      ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
-    } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
-
-    if (ioctlRet == 0) {
-      ifPtr = ifc->ifc_buf;
-      while (ifPtr && (char *)ifPtr < ifc->ifc_buf + ifc->ifc_len) {
-        struct ifreq *ifr = (struct ifreq *)ifPtr;
-
-        if (ifr->ifr_addr.sa_family == AF_INET)
-          numAddresses++;
-
-        ifPtr = (char *)ifPtr + ifreq_len((struct ifreq *)ifPtr);
-      }
-    }
-    else
-      ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
-    if (!ret)
-      *pcAddresses = numAddresses;
-    else
-    {
-      HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
-      ifc->ifc_buf = NULL;
-    }
-    close(fd);
-  }
-  else
-    ret = ERROR_NO_SYSTEM_RESOURCES;
-  return ret;
-}
-
-DWORD getNumIPAddresses(void)
-{
-  DWORD numAddresses = 0;
-  struct ifconf ifc;
-
-  if (!enumIPAddresses(&numAddresses, &ifc))
-    HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
-  return numAddresses;
-}
-
-DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
-{
-  DWORD ret;
-
-  if (!ppIpAddrTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else
-  {
-    DWORD numAddresses = 0;
-    struct ifconf ifc;
-
-    ret = enumIPAddresses(&numAddresses, &ifc);
-    if (!ret)
-    {
-      DWORD size = sizeof(MIB_IPADDRTABLE);
-
-      if (numAddresses > 1)
-        size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
-      *ppIpAddrTable = HeapAlloc(heap, flags, size);
-      if (*ppIpAddrTable) {
-        DWORD i = 0;
-        caddr_t ifPtr;
-
-        ret = NO_ERROR;
-        (*ppIpAddrTable)->dwNumEntries = numAddresses;
-        ifPtr = ifc.ifc_buf;
-        while (!ret && ifPtr && (char *)ifPtr < ifc.ifc_buf + ifc.ifc_len) {
-          struct ifreq *ifr = (struct ifreq *)ifPtr;
-
-          ifPtr = (char *)ifPtr + ifreq_len(ifr);
-
-          if (ifr->ifr_addr.sa_family != AF_INET)
-             continue;
-
-          ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
-           &ifr->ifr_addr);
-          i++;
-        }
-        if (ret)
-          HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
-      }
-      else
-        ret = ERROR_OUTOFMEMORY;
-      HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
-    }
-  }
-  return ret;
-}
-
-ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
-{
-  *addrs = NULL;
-  *num_addrs = 0;
-  *masks = NULL;
-  return ERROR_SUCCESS;
-}
-
-#endif
diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h
index d0143eaaf69..710b493ad36 100644
--- a/dlls/iphlpapi/ifenum.h
+++ b/dlls/iphlpapi/ifenum.h
@@ -44,8 +44,6 @@
 #define MAX_INTERFACE_PHYSADDR    8
 #define MAX_INTERFACE_DESCRIPTION 256
 
-BOOL isIfIndexLoopback(ULONG idx) DECLSPEC_HIDDEN;
-
 /* A table of interface indexes, see get_interface_indices(). */
 typedef struct _InterfaceIndexTable {
   DWORD numIndexes;
@@ -59,50 +57,10 @@ DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table ) D
 
 /* ByName/ByIndex versions of various getter functions. */
 
-/* can be used as quick check to see if you've got a valid index, returns NULL
- * if not.  Overwrites your buffer, which should be at least of size
- * MAX_ADAPTER_NAME.
- */
-char *getInterfaceNameByIndex(IF_INDEX index, char *name) DECLSPEC_HIDDEN;
-
 /* Fills index with the index of name, if found.  Returns
  * ERROR_INVALID_PARAMETER if name or index is NULL, ERROR_INVALID_DATA if name
  * is not found, and NO_ERROR on success.
  */
 DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index) DECLSPEC_HIDDEN;
 
-/* Gets a few physical characteristics of a device:  MAC addr len, MAC addr,
- * and type as one of the MIB_IF_TYPEs.
- * len's in-out: on in, needs to say how many bytes are available in addr,
- * which to be safe should be MAX_INTERFACE_PHYSADDR.  On out, it's how many
- * bytes were set, or how many were required if addr isn't big enough.
- * Returns ERROR_INVALID_PARAMETER if name, len, addr, or type is NULL.
- * Returns ERROR_INVALID_DATA if name/index isn't valid.
- * Returns ERROR_INSUFFICIENT_BUFFER if addr isn't large enough for the
- * physical address; *len will contain the required size.
- * May return other errors, e.g. ERROR_OUTOFMEMORY or ERROR_NO_MORE_FILES,
- * if internal errors occur.
- * Returns NO_ERROR on success.
- */
-DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
- PDWORD type) DECLSPEC_HIDDEN;
-
-DWORD getNumIPAddresses(void) DECLSPEC_HIDDEN;
-
-/* Gets the configured IP addresses for the system, and sets *ppIpAddrTable to
- * a table of them allocated from heap, or NULL if out of memory.  Returns
- * NO_ERROR on success, something else on failure.  Note there may be more than
- * one IP address may exist per interface.
- */
-DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) DECLSPEC_HIDDEN;
-
-/* Returns the IPv6 addresses for a particular interface index.
- * Returns NO_ERROR on success, something else on failure.
- */
-ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs,
- SOCKET_ADDRESS **masks) DECLSPEC_HIDDEN;
-
-DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) DECLSPEC_HIDDEN;
-DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status) DECLSPEC_HIDDEN;
-
 #endif /* ndef WINE_IFENUM_H_ */
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 22e17e06757..2700ecd3172 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -109,6 +109,15 @@ DWORD WINAPI ConvertStringToGuidW( const WCHAR *str, GUID *guid )
     return RtlNtStatusToDosError( RtlGUIDFromString( &ustr, guid ) );
 }
 
+static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
+{
+    unsigned int copy = src->Length;
+
+    if (copy >= len * sizeof(WCHAR)) copy = 0;
+    memcpy( dst, src->String, copy );
+    memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
+}
+
 /******************************************************************
  *    AddIPAddress (IPHLPAPI.@)
  *
@@ -913,129 +922,6 @@ void adapters_addresses_copy( IP_ADAPTER_ADDRESSES *dst, IP_ADAPTER_ADDRESSES *s
     }
 }
 
-static DWORD typeFromMibType(DWORD mib_type)
-{
-    switch (mib_type)
-    {
-    case MIB_IF_TYPE_ETHERNET:  return IF_TYPE_ETHERNET_CSMACD;
-    case MIB_IF_TYPE_TOKENRING: return IF_TYPE_ISO88025_TOKENRING;
-    case MIB_IF_TYPE_PPP:       return IF_TYPE_PPP;
-    case MIB_IF_TYPE_LOOPBACK:  return IF_TYPE_SOFTWARE_LOOPBACK;
-    default:                    return IF_TYPE_OTHER;
-    }
-}
-
-static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
-{
-    switch (mib_type)
-    {
-    case MIB_IF_TYPE_PPP:       return NET_IF_CONNECTION_DEMAND;
-    case MIB_IF_TYPE_SLIP:      return NET_IF_CONNECTION_DEMAND;
-    default:                    return NET_IF_CONNECTION_DEDICATED;
-    }
-}
-
-static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs, DWORD **masks)
-{
-    ULONG ret, i, j;
-    MIB_IPADDRTABLE *at;
-
-    *num_addrs = 0;
-    if ((ret = getIPAddrTable(&at, GetProcessHeap(), 0))) return ret;
-    for (i = 0; i < at->dwNumEntries; i++)
-    {
-        if (at->table[i].dwIndex == index) (*num_addrs)++;
-    }
-    if (!(*addrs = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
-    {
-        HeapFree(GetProcessHeap(), 0, at);
-        return ERROR_OUTOFMEMORY;
-    }
-    if (!(*masks = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
-    {
-        HeapFree(GetProcessHeap(), 0, *addrs);
-        HeapFree(GetProcessHeap(), 0, at);
-        return ERROR_OUTOFMEMORY;
-    }
-    for (i = 0, j = 0; i < at->dwNumEntries; i++)
-    {
-        if (at->table[i].dwIndex == index)
-        {
-            (*addrs)[j] = at->table[i].dwAddr;
-            (*masks)[j] = at->table[i].dwMask;
-            j++;
-        }
-    }
-    HeapFree(GetProcessHeap(), 0, at);
-    return ERROR_SUCCESS;
-}
-
-static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf)
-{
-    const BYTE *addrp;
-    char *p = buf;
-
-    for (addrp = (const BYTE *)in_addr;
-     addrp - (const BYTE *)in_addr < sizeof(*in_addr);
-     addrp++)
-    {
-        if (addrp == (const BYTE *)in_addr + sizeof(*in_addr) - 1)
-            sprintf(p, "%d", *addrp);
-        else
-            p += sprintf(p, "%d.", *addrp);
-    }
-    return buf;
-}
-
-static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable)
-{
-    DWORD i, num_gateways = 0;
-
-    for (i = 0; i < routeTable->dwNumEntries; i++)
-    {
-        if (routeTable->table[i].dwForwardIfIndex == index &&
-            routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
-            num_gateways++;
-    }
-    return num_gateways;
-}
-
-static DWORD mask_v4_to_prefix(DWORD m)
-{
-#ifdef HAVE___BUILTIN_POPCOUNT
-    return __builtin_popcount(m);
-#else
-    m -= m >> 1 & 0x55555555;
-    m = (m & 0x33333333) + (m >> 2 & 0x33333333);
-    return ((m + (m >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
-#endif
-}
-
-static DWORD mask_v6_to_prefix(SOCKET_ADDRESS *m)
-{
-    const IN6_ADDR *mask = &((struct WS_sockaddr_in6 *)m->lpSockaddr)->sin6_addr;
-    DWORD ret = 0, i;
-
-    for (i = 0; i < 8; i++)
-        ret += mask_v4_to_prefix(mask->u.Word[i]);
-    return ret;
-}
-
-static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
-                                         PMIB_IPFORWARDTABLE routeTable)
-{
-    DWORD i;
-    PMIB_IPFORWARDROW row = NULL;
-
-    for (i = 0; !row && i < routeTable->dwNumEntries; i++)
-    {
-        if (routeTable->table[i].dwForwardIfIndex == index &&
-            routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
-            row = &routeTable->table[i];
-    }
-    return row;
-}
-
 static BOOL sockaddr_is_loopback( SOCKADDR *sock )
 {
     if (sock->sa_family == WS_AF_INET)
@@ -1067,308 +953,211 @@ static BOOL unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS *uni )
         !sockaddr_is_linklocal( uni->Address.lpSockaddr );
 }
 
-static void fill_unicast_addr_data(IP_ADAPTER_ADDRESSES *aa, IP_ADAPTER_UNICAST_ADDRESS *ua)
+static DWORD unicast_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
 {
-    /* Actually this information should be read somewhere from the system
-     * but it doesn't matter much for the bugs found so far.
-     * This information is required for DirectPlay8 games. */
-    if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK)
-    {
-        ua->PrefixOrigin = IpPrefixOriginDhcp;
-        ua->SuffixOrigin = IpSuffixOriginDhcp;
-    }
-    else
-    {
-        ua->PrefixOrigin = IpPrefixOriginManual;
-        ua->SuffixOrigin = IpSuffixOriginManual;
-    }
-
-    /* The address is not duplicated in the network */
-    ua->DadState = IpDadStatePreferred;
-
-    /* Some address life time values, required even for non-dhcp addresses */
-    ua->ValidLifetime = 60000;
-    ua->PreferredLifetime = 60000;
-    ua->LeaseLifetime = 60000;
-
-    if (unicast_is_dns_eligible( ua )) ua->u.s.Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
-}
-
-static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
-                                       IP_ADAPTER_ADDRESSES *aa, char **ptr)
-{
-    ULONG ret = ERROR_SUCCESS, i, j, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0;
-    DWORD *v4addrs = NULL, *v4masks = NULL;
-    SOCKET_ADDRESS *v6addrs = NULL, *v6masks = NULL;
-    PMIB_IPFORWARDTABLE routeTable = NULL;
-    BOOL output_gateways;
-    char name[IF_NAMESIZE], *src;
-    WCHAR *dst;
-    DWORD buflen, type;
-    INTERNAL_IF_OPER_STATUS status;
-    NET_LUID luid;
-    GUID guid;
+    struct nsi_ipv4_unicast_key *key4;
+    struct nsi_ipv6_unicast_key *key6;
+    struct nsi_ip_unicast_rw *rw;
+    struct nsi_ip_unicast_dynamic *dyn;
+    struct nsi_ip_unicast_static *stat;
+    IP_ADAPTER_UNICAST_ADDRESS *addr, **next;
+    DWORD err, count, i, key_size = (family == WS_AF_INET) ? sizeof(*key4) : sizeof(*key6);
+    DWORD sockaddr_size = (family == WS_AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
+    NET_LUID *luid;
+    void *key;
 
-    if ((flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) || !(flags & GAA_FLAG_SKIP_UNICAST))
-    {
-        ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
-        if (ret) return ret;
-        num_v4_gateways = count_v4_gateways(index, routeTable);
-    }
-    output_gateways = (flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) && (family == WS_AF_INET || family == WS_AF_UNSPEC);
+    err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_UNICAST_TABLE, &key, key_size,
+                                  (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
+                                  (void **)&stat, sizeof(*stat), &count, 0 );
+    if (err) return err;
 
-    if (family == WS_AF_INET)
-    {
-        ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
-    }
-    else if (family == WS_AF_INET6)
-    {
-        ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
-    }
-    else if (family == WS_AF_UNSPEC)
-    {
-        ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
-        if (!ret) ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
-    }
-    else
-    {
-        FIXME("address family %u unsupported\n", family);
-        ret = ERROR_NO_DATA;
-    }
-    if (ret)
-    {
-        HeapFree(GetProcessHeap(), 0, v4addrs);
-        HeapFree(GetProcessHeap(), 0, v4masks);
-        HeapFree(GetProcessHeap(), 0, v6addrs);
-        HeapFree(GetProcessHeap(), 0, v6masks);
-        HeapFree(GetProcessHeap(), 0, routeTable);
-        return ret;
-    }
 
-    if (1)
+    while (aa)
     {
-        memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES));
-        aa->u.s.Length  = sizeof(IP_ADAPTER_ADDRESSES);
-        aa->u.s.IfIndex = index;
-
-        ConvertInterfaceIndexToLuid(index, &luid);
-        ConvertInterfaceLuidToGuid(&luid, &guid);
-        ConvertGuidToStringA( &guid, *ptr, CHARS_IN_GUID );
-        aa->AdapterName = *ptr;
-        *ptr += (CHARS_IN_GUID + 1) & ~1;
+        for (next = &aa->FirstUnicastAddress; *next; next = &(*next)->Next)
+            ;
 
-        getInterfaceNameByIndex(index, name);
-        if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
-        {
-            aa->FriendlyName = (WCHAR *)*ptr;
-            for (src = name, dst = (WCHAR *)*ptr; *src; src++, dst++)
-                *dst = *src;
-            *dst++ = 0;
-            *ptr = (char *)dst;
-        }
-        aa->Description = (WCHAR *)ptr;
-        for (src = name, dst = (WCHAR *)*ptr; *src; src++, dst++)
-            *dst = *src;
-        *dst++ = 0;
-        *ptr = (char *)dst;
-
-        TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name, num_v4addrs,
-              num_v6addrs);
-
-        buflen = MAX_INTERFACE_PHYSADDR;
-        getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
-        aa->PhysicalAddressLength = buflen;
-        aa->IfType = typeFromMibType(type);
-        aa->ConnectionType = connectionTypeFromMibType(type);
-        ConvertInterfaceIndexToLuid( index, &aa->Luid );
-
-        if (output_gateways && num_v4_gateways)
-        {
-            PMIB_IPFORWARDROW adapterRow;
-
-            if ((adapterRow = findIPv4Gateway(index, routeTable)))
-            {
-                PIP_ADAPTER_GATEWAY_ADDRESS gw;
-                PSOCKADDR_IN sin;
-
-                gw = heap_alloc( sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN) );
-                aa->FirstGatewayAddress = gw;
-
-                gw->u.s.Length = sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
-                sin = (PSOCKADDR_IN)(gw + 1);
-                sin->sin_family = WS_AF_INET;
-                sin->sin_port = 0;
-                memcpy(&sin->sin_addr, &adapterRow->dwForwardNextHop,
-                       sizeof(DWORD));
-                gw->Address.lpSockaddr = (LPSOCKADDR)sin;
-                gw->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
-                gw->Next = NULL;
-            }
-        }
-        if (num_v4addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
+        for (i = 0; i < count; i++)
         {
-            IP_ADAPTER_UNICAST_ADDRESS *ua;
-            struct WS_sockaddr_in *sa;
-            aa->u1.s1.Ipv4Enabled = TRUE;
-            ua = aa->FirstUnicastAddress = heap_alloc_zero( sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR_IN) );
-            for (i = 0; i < num_v4addrs; i++)
+            key4 = (struct nsi_ipv4_unicast_key *)key + i;
+            key6 = (struct nsi_ipv6_unicast_key *)key + i;
+            luid = (family == WS_AF_INET) ? &key4->luid : &key6->luid;
+            if (luid->Value != aa->Luid.Value) continue;
+            addr = heap_alloc_zero( sizeof(*addr) + sockaddr_size );
+            if (!addr)
             {
-                char addr_buf[16];
-
-                memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
-                ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
-                ua->Address.iSockaddrLength = sizeof(struct sockaddr_in);
-                ua->Address.lpSockaddr      = (SOCKADDR *)(ua + 1);
-
-                sa = (struct WS_sockaddr_in *)ua->Address.lpSockaddr;
-                sa->sin_family           = WS_AF_INET;
-                sa->sin_addr.S_un.S_addr = v4addrs[i];
-                sa->sin_port             = 0;
-                TRACE("IPv4 %d/%d: %s\n", i + 1, num_v4addrs,
-                      debugstr_ipv4(&sa->sin_addr.S_un.S_addr, addr_buf));
-                fill_unicast_addr_data(aa, ua);
-
-                ua->OnLinkPrefixLength = mask_v4_to_prefix(v4masks[i]);
-
-                if (i < num_v4addrs - 1)
-                {
-                    ua->Next = heap_alloc_zero( sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR_IN) );
-                    ua = ua->Next;
-                }
+                err = ERROR_NOT_ENOUGH_MEMORY;
+                goto err;
             }
-        }
-        if (num_v6addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
-        {
-            IP_ADAPTER_UNICAST_ADDRESS *ua;
-            struct WS_sockaddr_in6 *sa;
-
-            aa->u1.s1.Ipv6Enabled = TRUE;
-            if (aa->FirstUnicastAddress)
+            addr->u.s.Length = sizeof(*addr);
+            addr->Address.lpSockaddr = (SOCKADDR *)(addr + 1);
+            addr->Address.iSockaddrLength = sockaddr_size;
+            addr->Address.lpSockaddr->sa_family = family;
+            if (family == WS_AF_INET)
             {
-                for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
-                    ;
-                ua->Next = heap_alloc_zero( sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR_IN6) );
-                ua = ua->Next;
+                SOCKADDR_IN *in = (SOCKADDR_IN *)addr->Address.lpSockaddr;
+                in->sin_addr = key4->addr;
             }
             else
-                ua = aa->FirstUnicastAddress = heap_alloc_zero( sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR_IN6) );
-            for (i = 0; i < num_v6addrs; i++)
             {
-                char addr_buf[46];
-
-                memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
-                ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
-                ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
-                ua->Address.lpSockaddr      = (SOCKADDR *)(ua + 1);
-
-                sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
-                memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
-                TRACE("IPv6 %d/%d: %s\n", i + 1, num_v6addrs,
-                      debugstr_ipv6(sa, addr_buf));
-                fill_unicast_addr_data(aa, ua);
-
-                ua->OnLinkPrefixLength = mask_v6_to_prefix(&v6masks[i]);
-
-                if (i < num_v6addrs - 1)
-                {
-                    ua->Next = heap_alloc_zero( sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR_IN6) );
-                    ua = ua->Next;
-                }
+                SOCKADDR_IN6 *in6 = (SOCKADDR_IN6 *)addr->Address.lpSockaddr;
+                in6->sin6_addr = key6->addr;
+                in6->sin6_scope_id = dyn[i].scope_id;
             }
+            addr->PrefixOrigin = rw[i].prefix_origin;
+            addr->SuffixOrigin = rw[i].suffix_origin;
+            addr->DadState = dyn[i].dad_state;
+            addr->ValidLifetime = rw[i].valid_lifetime;
+            addr->PreferredLifetime = rw[i].preferred_lifetime;
+            addr->LeaseLifetime = rw[i].valid_lifetime; /* FIXME */
+            addr->OnLinkPrefixLength = rw[i].on_link_prefix;
+            if (unicast_is_dns_eligible( addr )) addr->u.s.Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
+
+            *next = addr;
+            next = &addr->Next;
         }
-        if (num_v4addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
-        {
-            IP_ADAPTER_PREFIX *prefix;
+        aa = aa->Next;
+    }
 
-            prefix = aa->FirstPrefix = heap_alloc_zero( sizeof(*prefix) + sizeof(SOCKADDR_IN) );
-            for (i = 0; i < num_v4addrs; i++)
-            {
-                char addr_buf[16];
-                struct WS_sockaddr_in *sa;
+err:
+    NsiFreeTable( key, rw, dyn, stat );
+    return err;
+}
 
-                prefix->u.s.Length = sizeof(*prefix);
-                prefix->u.s.Flags  = 0;
-                prefix->Next       = NULL;
-                prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in);
-                prefix->Address.lpSockaddr      = (SOCKADDR *)(prefix + 1);
+static DWORD gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
+{
+    struct nsi_ipv4_forward_key *key4;
+    struct nsi_ipv6_forward_key *key6;
+    IP_ADAPTER_GATEWAY_ADDRESS *gw, **gw_next;
+    IP_ADAPTER_PREFIX *prefix, **prefix_next;
+    DWORD err, count, i, prefix_len, key_size = (family == WS_AF_INET) ? sizeof(*key4) : sizeof(*key6);
+    DWORD sockaddr_size = (family == WS_AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
+    SOCKADDR_INET sockaddr;
+    NET_LUID *luid;
+    void *key;
 
-                sa = (struct WS_sockaddr_in *)prefix->Address.lpSockaddr;
-                sa->sin_family           = WS_AF_INET;
-                sa->sin_addr.S_un.S_addr = v4addrs[i] & v4masks[i];
-                sa->sin_port             = 0;
+    err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_FORWARD_TABLE, &key, key_size,
+                                  NULL, 0, NULL, 0, NULL, 0, &count, 0 );
+    if (err) return err;
 
-                prefix->PrefixLength = mask_v4_to_prefix(v4masks[i]);
+    while (aa)
+    {
+        for (gw_next = &aa->FirstGatewayAddress; *gw_next; gw_next = &(*gw_next)->Next)
+            ;
+        for (prefix_next = &aa->FirstPrefix; *prefix_next; prefix_next = &(*prefix_next)->Next)
+            ;
 
-                TRACE("IPv4 network: %s/%u\n",
-                      debugstr_ipv4((const in_addr_t *)&sa->sin_addr.S_un.S_addr, addr_buf),
-                      prefix->PrefixLength);
+        for (i = 0; i < count; i++)
+        {
+            key4 = (struct nsi_ipv4_forward_key *)key + i;
+            key6 = (struct nsi_ipv6_forward_key *)key + i;
+            luid = (family == WS_AF_INET) ? &key4->luid : &key6->luid;
+            if (luid->Value != aa->Luid.Value) continue;
 
-                if (i < num_v4addrs - 1)
+            if (flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
+            {
+                memset( &sockaddr, 0, sizeof(sockaddr) );
+                if (family == WS_AF_INET)
                 {
-                    prefix->Next = heap_alloc_zero( sizeof(*prefix) + sizeof(SOCKADDR_IN) );
-                    prefix = prefix->Next;
+                    if (key4->next_hop.WS_s_addr != 0)
+                    {
+                        sockaddr.si_family = family;
+                        sockaddr.Ipv4.sin_addr = key4->next_hop;
+                    }
+                }
+                else
+                {
+                    static const IN6_ADDR zero;
+                    if (memcmp( &key6->next_hop, &zero, sizeof(zero) ))
+                    {
+                        sockaddr.si_family = family;
+                        sockaddr.Ipv6.sin6_addr = key6->next_hop;
+                    }
                 }
-            }
-        }
-        if (num_v6addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
-        {
-            IP_ADAPTER_PREFIX *prefix;
 
-            if (aa->FirstPrefix)
-            {
-                for (prefix = aa->FirstPrefix; prefix->Next; prefix = prefix->Next)
-                    ;
-                prefix->Next = heap_alloc_zero( sizeof(*prefix) + sizeof(SOCKADDR_IN6) );
-                prefix = prefix->Next;
+                if (sockaddr.si_family)
+                {
+                    gw = heap_alloc_zero( sizeof(*gw) + sockaddr_size );
+                    if (!gw)
+                    {
+                        err = ERROR_NOT_ENOUGH_MEMORY;
+                        goto err;
+                    }
+                    gw->u.s.Length = sizeof(*gw);
+                    gw->Address.lpSockaddr = (SOCKADDR *)(gw + 1);
+                    gw->Address.iSockaddrLength = sockaddr_size;
+                    memcpy( gw->Address.lpSockaddr, &sockaddr, sockaddr_size );
+                    *gw_next = gw;
+                    gw_next = &gw->Next;
+                }
             }
-            else
-                prefix = aa->FirstPrefix = heap_alloc_zero( sizeof(*prefix) + sizeof(SOCKADDR_IN6) );
-            for (i = 0; i < num_v6addrs; i++)
+
+            if (flags & GAA_FLAG_INCLUDE_PREFIX)
             {
-                char addr_buf[46];
-                struct WS_sockaddr_in6 *sa;
-                const IN6_ADDR *addr, *mask;
-
-                prefix->u.s.Length = sizeof(*prefix);
-                prefix->u.s.Flags  = 0;
-                prefix->Next       = NULL;
-                prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in6);
-                prefix->Address.lpSockaddr      = (SOCKADDR *)(prefix + 1);
-
-                sa = (struct WS_sockaddr_in6 *)prefix->Address.lpSockaddr;
-                sa->sin6_family   = WS_AF_INET6;
-                sa->sin6_port     = 0;
-                sa->sin6_flowinfo = 0;
-                addr = &((struct WS_sockaddr_in6 *)v6addrs[i].lpSockaddr)->sin6_addr;
-                mask = &((struct WS_sockaddr_in6 *)v6masks[i].lpSockaddr)->sin6_addr;
-                for (j = 0; j < 8; j++) sa->sin6_addr.u.Word[j] = addr->u.Word[j] & mask->u.Word[j];
-                sa->sin6_scope_id = 0;
-
-                prefix->PrefixLength = mask_v6_to_prefix(&v6masks[i]);
-
-                TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa, addr_buf), prefix->PrefixLength);
-
-                if (i < num_v6addrs - 1)
+                memset( &sockaddr, 0, sizeof(sockaddr) );
+                if (family == WS_AF_INET)
+                {
+                    if (!key4->next_hop.WS_s_addr)
+                    {
+                        sockaddr.si_family = family;
+                        sockaddr.Ipv4.sin_addr = key4->prefix;
+                        prefix_len = key4->prefix_len;
+                    }
+                }
+                else
                 {
-                    prefix->Next = heap_alloc_zero( sizeof(*prefix) + sizeof(SOCKADDR_IN6) );
-                    prefix = prefix->Next;
+                    static const IN6_ADDR zero;
+                    if (!memcmp( &key6->next_hop, &zero, sizeof(zero) ))
+                    {
+                        sockaddr.si_family = family;
+                        sockaddr.Ipv6.sin6_addr = key6->prefix;
+                        prefix_len = key6->prefix_len;
+                    }
+                }
+
+                if (sockaddr.si_family)
+                {
+                    prefix = heap_alloc_zero( sizeof(*prefix) + sockaddr_size );
+                    if (!prefix)
+                    {
+                        err = ERROR_NOT_ENOUGH_MEMORY;
+                        goto err;
+                    }
+                    prefix->u.s.Length = sizeof(*prefix);
+                    prefix->Address.lpSockaddr = (SOCKADDR *)(prefix + 1);
+                    prefix->Address.iSockaddrLength = sockaddr_size;
+                    memcpy( prefix->Address.lpSockaddr, &sockaddr, sockaddr_size );
+                    prefix->PrefixLength = prefix_len;
+                    *prefix_next = prefix;
+                    prefix_next = &prefix->Next;
                 }
             }
         }
+        aa = aa->Next;
+    }
 
-        getInterfaceMtuByName(name, &aa->Mtu);
+err:
+    NsiFreeTable( key, NULL, NULL, NULL );
+    return err;
+}
 
-        getInterfaceStatusByName(name, &status);
-        if (status == MIB_IF_OPER_STATUS_OPERATIONAL) aa->OperStatus = IfOperStatusUp;
-        else if (status == MIB_IF_OPER_STATUS_NON_OPERATIONAL) aa->OperStatus = IfOperStatusDown;
-        else aa->OperStatus = IfOperStatusUnknown;
+static DWORD call_families( DWORD (*fn)( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags ),
+                            IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
+{
+    DWORD err;
+
+    if (family != WS_AF_INET)
+    {
+        err = fn( aa, WS_AF_INET6, flags );
+        if (err) return err;
     }
-    HeapFree(GetProcessHeap(), 0, routeTable);
-    HeapFree(GetProcessHeap(), 0, v6addrs);
-    HeapFree(GetProcessHeap(), 0, v6masks);
-    HeapFree(GetProcessHeap(), 0, v4addrs);
-    HeapFree(GetProcessHeap(), 0, v4masks);
-    return ERROR_SUCCESS;
+
+    if (family != WS_AF_INET6)
+    {
+        err = fn( aa, WS_AF_INET, flags );
+        if (err) return err;
+    }
+    return err;
 }
 
 static DWORD dns_servers_query_code( ULONG family )
@@ -1461,20 +1250,21 @@ err:
 static DWORD adapters_addresses_alloc( ULONG family, ULONG flags, IP_ADAPTER_ADDRESSES **info )
 {
     IP_ADAPTER_ADDRESSES *aa;
+    NET_LUID *luids;
+    struct nsi_ndis_ifinfo_rw *rw;
+    struct nsi_ndis_ifinfo_dynamic *dyn;
+    struct nsi_ndis_ifinfo_static *stat;
     DWORD err, i, count, needed;
+    GUID guid;
     char *str_ptr;
-    InterfaceIndexTable *table;
 
-    get_interface_indices( FALSE, &table );
-    if (!table || !table->numIndexes)
-    {
-        HeapFree(GetProcessHeap(), 0, table);
-        return ERROR_NO_DATA;
-    }
-    count = table->numIndexes;
+    err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&luids, sizeof(*luids),
+                                  (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
+                                  (void **)&stat, sizeof(*stat), &count, 0 );
+    if (err) return err;
 
-    needed = count * (sizeof(*aa) + ((CHARS_IN_GUID + 1) & ~1) + sizeof(IF_COUNTED_STRING));
-    if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) needed += count * sizeof(IF_COUNTED_STRING);
+    needed = count * (sizeof(*aa) + ((CHARS_IN_GUID + 1) & ~1) + sizeof(stat->descr.String));
+    if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) needed += count * sizeof(rw->alias.String);
 
     aa = heap_alloc_zero( needed );
     if (!aa)
@@ -1486,18 +1276,52 @@ static DWORD adapters_addresses_alloc( ULONG family, ULONG flags, IP_ADAPTER_ADD
     str_ptr = (char *)(aa + count);
     for (i = 0; i < count; i++)
     {
-        if ((err = adapterAddressesFromIndex(family, flags, table->indexes[i], aa + i, &str_ptr)))
+        aa[i].u.s.Length = sizeof(*aa);
+        aa[i].u.s.IfIndex = stat[i].if_index;
+        if (i < count - 1) aa[i].Next = aa + i + 1;
+        ConvertInterfaceLuidToGuid( luids + i, &guid );
+        ConvertGuidToStringA( &guid, str_ptr, CHARS_IN_GUID );
+        aa[i].AdapterName = str_ptr;
+        str_ptr += (CHARS_IN_GUID + 1) & ~1;
+        if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(stat[i].descr.String), &stat[i].descr );
+        aa[i].Description = (WCHAR *)str_ptr;
+        str_ptr += sizeof(stat[i].descr.String);
+        if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
         {
-            HeapFree(GetProcessHeap(), 0, table);
-            return err;
+            if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(rw[i].alias.String), &rw[i].alias );
+            aa[i].FriendlyName = (WCHAR *)str_ptr;
+            str_ptr += sizeof(rw[i].alias.String);
         }
-        if (i < count - 1) aa[i].Next = aa + i + 1;
+        aa[i].PhysicalAddressLength = rw->phys_addr.Length;
+        if (aa[i].PhysicalAddressLength > sizeof(aa[i].PhysicalAddress)) aa[i].PhysicalAddressLength = 0;
+        memcpy( aa[i].PhysicalAddress, rw->phys_addr.Address, aa[i].PhysicalAddressLength );
+        aa[i].Mtu = dyn[i].mtu;
+        aa[i].IfType = stat[i].type;
+        aa[i].OperStatus = dyn[i].oper_status;
+        aa[i].TransmitLinkSpeed = dyn[i].xmit_speed;
+        aa[i].ReceiveLinkSpeed = dyn[i].rcv_speed;
+        aa[i].Luid = luids[i];
+        aa[i].NetworkGuid = rw[i].network_guid;
+        aa[i].ConnectionType = stat[i].conn_type;
+    }
+
+    if (!(flags & GAA_FLAG_SKIP_UNICAST))
+    {
+        err = call_families( unicast_addresses_alloc, aa, family, flags );
+        if (err) goto err;
+    }
+
+    if (flags & (GAA_FLAG_INCLUDE_ALL_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX))
+    {
+        err = call_families( gateway_and_prefix_addresses_alloc, aa, family, flags );
+        if (err) goto err;
     }
 
     err = dns_info_alloc( aa, family, flags );
+    if (err) goto err;
 
 err:
-    HeapFree(GetProcessHeap(), 0, table);
+    NsiFreeTable( luids, rw, dyn, stat );
     if (!err) *info = aa;
     else adapters_addresses_free( aa );
     return err;
@@ -1861,15 +1685,6 @@ err:
     return err;
 }
 
-static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
-{
-    unsigned int copy = src->Length;
-
-    if (copy >= len * sizeof(WCHAR)) copy = 0;
-    memcpy( dst, src->String, copy );
-    memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
-}
-
 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
                           struct nsi_ndis_ifinfo_static *stat )
 {
-- 
2.23.0




More information about the wine-devel mailing list