Signed-off-by: Huw Davies huw@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 ) {