diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c index f36fc99e89..19c3c3c952 100644 --- a/dlls/iphlpapi/ifenum.c +++ b/dlls/iphlpapi/ifenum.c @@ -548,7 +548,7 @@ DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr, return ERROR_INVALID_DATA; } -static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) +DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) { DWORD ret; int fd; @@ -580,7 +580,7 @@ static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) return ret; } -static DWORD getInterfaceStatusByName(const char *name, PDWORD status) +DWORD getInterfaceStatusByName(const char *name, PDWORD status) { DWORD ret; int fd; diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h index d471750866..6835dcad3c 100644 --- a/dlls/iphlpapi/ifenum.h +++ b/dlls/iphlpapi/ifenum.h @@ -112,4 +112,7 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags); */ char *toIPAddressString(unsigned int addr, char string[16]); +DWORD getInterfaceMtuByName(const char *name, PDWORD mtu); +DWORD getInterfaceStatusByName(const char *name, PDWORD status); + #endif /* ndef WINE_IFENUM_H_ */ diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec index 24c4e94f21..794ece2093 100644 --- a/dlls/iphlpapi/iphlpapi.spec +++ b/dlls/iphlpapi/iphlpapi.spec @@ -18,6 +18,7 @@ @ stub FlushIpNetTableFromStack @ stdcall GetAdapterIndex( wstr ptr ) @ stub GetAdapterOrderMap +@ stdcall GetAdaptersAddresses( long long ptr ptr ptr ) @ stdcall GetAdaptersInfo( ptr ptr ) @ stdcall GetBestInterface( long ptr ) @ stdcall GetBestInterfaceEx( ptr ptr ) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 547b6667b4..8490c67990 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -23,6 +23,12 @@ #include #include #include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif #ifdef HAVE_NETINET_IN_H # include #endif @@ -44,11 +50,16 @@ #include "iphlpapi.h" #include "ifenum.h" #include "ipstats.h" +#include "ipifcons.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); +#ifndef IF_NAMESIZE +#define IF_NAMESIZE 16 +#endif + #ifndef INADDR_NONE #define INADDR_NONE ~0UL #endif @@ -586,6 +597,168 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) return ret; } +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 ULONG addressesFromIndex(DWORD index, DWORD **addrs, ULONG *num_addrs) +{ + ULONG ret, i; + 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; + } + for (i = 0; i < at->dwNumEntries; i++) + { + if (at->table[i].dwIndex == index) (*addrs)[i] = at->table[i].dwAddr; + } + HeapFree(GetProcessHeap(), 0, at); + return ERROR_SUCCESS; +} + +static ULONG adapterAddressesFromIndex(DWORD index, IP_ADAPTER_ADDRESSES *aa, ULONG *size) +{ + ULONG ret, i, num_addrs, total_size; + DWORD *addrs; + + if ((ret = addressesFromIndex(index, &addrs, &num_addrs))) return ret; + + total_size = sizeof(IP_ADAPTER_ADDRESSES); + total_size += IF_NAMESIZE; + total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_addrs; + total_size += sizeof(struct sockaddr_in) * num_addrs; + + if (aa && *size >= total_size) + { + char name[IF_NAMESIZE], *ptr = (char *)aa + sizeof(IP_ADAPTER_ADDRESSES); + DWORD buflen, type, status; + + memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES)); + aa->Length = sizeof(IP_ADAPTER_ADDRESSES); + aa->IfIndex = index; + + getInterfaceNameByIndex(index, name); + memcpy(ptr, name, IF_NAMESIZE); + aa->AdapterName = ptr; + ptr += IF_NAMESIZE; + + if (num_addrs) + { + IP_ADAPTER_UNICAST_ADDRESS *ua; + struct sockaddr_in *sa; + + ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr; + for (i = 0; i < num_addrs; i++) + { + memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS)); + ua->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS); + ua->Address.iSockaddrLength = sizeof(struct sockaddr_in); + ua->Address.lpSockaddr = (SOCKADDR *)((char *)ua + ua->Length); + + sa = (struct sockaddr_in *)ua->Address.lpSockaddr; + sa->sin_family = AF_INET; + sa->sin_addr.s_addr = addrs[i]; + sa->sin_port = 0; + + ptr += ua->Length + ua->Address.iSockaddrLength; + if (i < num_addrs - 1) + { + ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr; + ua = ua->Next; + } + } + } + + buflen = MAX_INTERFACE_PHYSADDR; + getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type); + aa->PhysicalAddressLength = buflen; + aa->IfType = typeFromMibType(type); + + getInterfaceMtuByName(name, &aa->Mtu); + + 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; + } + *size = total_size; + HeapFree(GetProcessHeap(), 0, addrs); + return ERROR_SUCCESS; +} + +ULONG WINAPI GetAdaptersAddresses(ULONG family, ULONG flags, PVOID reserved, + PIP_ADAPTER_ADDRESSES aa, PULONG buflen) +{ + InterfaceIndexTable *table; + ULONG i, size, total_size, ret = ERROR_NO_DATA; + + if (!buflen) return ERROR_INVALID_PARAMETER; + + if (family == AF_INET6 || family == AF_UNSPEC) + FIXME("no support for IPv6 addresses\n"); + + if (family != AF_INET && family != AF_UNSPEC) return ERROR_NO_DATA; + + table = getInterfaceIndexTable(); + if (!table || !table->numIndexes) + { + HeapFree(GetProcessHeap(), 0, table); + return ERROR_NO_DATA; + } + total_size = 0; + for (i = 0; i < table->numIndexes; i++) + { + size = 0; + if ((ret = adapterAddressesFromIndex(table->indexes[i], NULL, &size))) + { + HeapFree(GetProcessHeap(), 0, table); + return ret; + } + total_size += size; + } + if (aa && *buflen >= total_size) + { + ULONG bytes_left = size = total_size; + for (i = 0; i < table->numIndexes; i++) + { + if ((ret = adapterAddressesFromIndex(table->indexes[i], aa, &size))) + { + HeapFree(GetProcessHeap(), 0, table); + return ret; + } + if (i < table->numIndexes - 1) + { + aa->Next = (IP_ADAPTER_ADDRESSES *)((char *)aa + size); + aa = aa->Next; + size = bytes_left -= size; + } + } + ret = ERROR_SUCCESS; + } + if (*buflen < total_size) ret = ERROR_BUFFER_OVERFLOW; + *buflen = total_size; + + TRACE("num adapters %u\n", table->numIndexes); + HeapFree(GetProcessHeap(), 0, table); + return ret; +} /****************************************************************** * GetBestInterface (IPHLPAPI.@)