[2/3] iphlpapi: Implement GetAdaptersAddresses.
Hans Leidekker
hans at codeweavers.com
Wed Apr 29 04:41:02 CDT 2009
This API is used by some .NET utility classes,
see http://bugs.winehq.org/show_bug.cgi?id=14574
-Hans
diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index f36fc99..19c3c3c 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 d471750..6835dca 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 24c4e94..794ece2 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 547b666..1207fe2 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -23,6 +23,9 @@
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -44,11 +47,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 +594,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.@)
More information about the wine-patches
mailing list