[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