iphlpapi: Implement GetAdaptersInfo() on top of nsi.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
fabd9e1f80
commit
2e399e4857
|
@ -608,155 +608,162 @@ static DWORD get_wins_servers( SOCKADDR_INET **servers )
|
|||
return count;
|
||||
}
|
||||
|
||||
static void ip_addr_string_init( IP_ADDR_STRING *s, const IN_ADDR *addr, const IN_ADDR *mask, DWORD ctxt )
|
||||
{
|
||||
s->Next = NULL;
|
||||
|
||||
if (addr) RtlIpv4AddressToStringA( addr, s->IpAddress.String );
|
||||
else s->IpAddress.String[0] = '\0';
|
||||
if (mask) RtlIpv4AddressToStringA( mask, s->IpMask.String );
|
||||
else s->IpMask.String[0] = '\0';
|
||||
s->Context = ctxt;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetAdaptersInfo (IPHLPAPI.@)
|
||||
*
|
||||
* Get information about adapters.
|
||||
*
|
||||
* PARAMS
|
||||
* pAdapterInfo [Out] buffer for adapter infos
|
||||
* pOutBufLen [In] length of output buffer
|
||||
*
|
||||
* RETURNS
|
||||
* Success: NO_ERROR
|
||||
* Failure: error code from winerror.h
|
||||
* info [Out] buffer for adapter infos
|
||||
* size [In] length of output buffer
|
||||
*/
|
||||
DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
|
||||
DWORD WINAPI GetAdaptersInfo( IP_ADAPTER_INFO *info, ULONG *size )
|
||||
{
|
||||
DWORD ret;
|
||||
|
||||
TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
|
||||
if (!pOutBufLen)
|
||||
ret = ERROR_INVALID_PARAMETER;
|
||||
else {
|
||||
DWORD numNonLoopbackInterfaces = get_interface_indices( TRUE, NULL );
|
||||
|
||||
if (numNonLoopbackInterfaces > 0) {
|
||||
DWORD numIPAddresses = getNumIPAddresses();
|
||||
ULONG size;
|
||||
|
||||
/* This may slightly overestimate the amount of space needed, because
|
||||
* the IP addresses include the loopback address, but it's easier
|
||||
* to make sure there's more than enough space than to make sure there's
|
||||
* precisely enough space.
|
||||
*/
|
||||
size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
|
||||
size += numIPAddresses * sizeof(IP_ADDR_STRING);
|
||||
if (!pAdapterInfo || *pOutBufLen < size) {
|
||||
*pOutBufLen = size;
|
||||
ret = ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
else {
|
||||
InterfaceIndexTable *table = NULL;
|
||||
PMIB_IPADDRTABLE ipAddrTable = NULL;
|
||||
PMIB_IPFORWARDTABLE routeTable = NULL;
|
||||
|
||||
ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
|
||||
if (!ret)
|
||||
ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
|
||||
if (!ret)
|
||||
get_interface_indices( TRUE, &table );
|
||||
if (table) {
|
||||
size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
|
||||
size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING);
|
||||
if (*pOutBufLen < size) {
|
||||
*pOutBufLen = size;
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
else {
|
||||
DWORD err, if_count, if_num = 0, uni_count, fwd_count, needed, wins_server_count;
|
||||
DWORD len, i, uni, fwd;
|
||||
NET_LUID *if_keys = NULL;
|
||||
struct nsi_ndis_ifinfo_rw *if_rw = NULL;
|
||||
struct nsi_ndis_ifinfo_dynamic *if_dyn = NULL;
|
||||
struct nsi_ndis_ifinfo_static *if_stat = NULL;
|
||||
struct nsi_ipv4_unicast_key *uni_keys = NULL;
|
||||
struct nsi_ip_unicast_rw *uni_rw = NULL;
|
||||
struct nsi_ipv4_forward_key *fwd_keys = NULL;
|
||||
SOCKADDR_INET *wins_servers = NULL;
|
||||
DWORD ndx, wins_server_count = get_wins_servers( &wins_servers );
|
||||
PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
|
||||
+ numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
|
||||
IP_ADDR_STRING *extra_ip_addrs, *cursor;
|
||||
IN_ADDR gw, mask;
|
||||
|
||||
memset(pAdapterInfo, 0, size);
|
||||
for (ndx = 0; ndx < table->numIndexes; ndx++) {
|
||||
PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
|
||||
DWORD i;
|
||||
PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
|
||||
BOOL firstIPAddr = TRUE;
|
||||
NET_LUID luid;
|
||||
GUID guid;
|
||||
TRACE( "info %p, size %p\n", info, size );
|
||||
if (!size) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
/* on Win98 this is left empty, but whatever */
|
||||
ConvertInterfaceIndexToLuid(table->indexes[ndx], &luid);
|
||||
ConvertInterfaceLuidToGuid(&luid, &guid);
|
||||
ConvertGuidToStringA( &guid, ptr->AdapterName, ARRAY_SIZE(ptr->AdapterName) );
|
||||
getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
|
||||
ptr->AddressLength = sizeof(ptr->Address);
|
||||
getInterfacePhysicalByIndex(table->indexes[ndx],
|
||||
&ptr->AddressLength, ptr->Address, &ptr->Type);
|
||||
ptr->Index = table->indexes[ndx];
|
||||
for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
|
||||
if (ipAddrTable->table[i].dwIndex == ptr->Index) {
|
||||
if (firstIPAddr) {
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwAddr,
|
||||
ptr->IpAddressList.IpAddress.String);
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwMask,
|
||||
ptr->IpAddressList.IpMask.String);
|
||||
firstIPAddr = FALSE;
|
||||
}
|
||||
else {
|
||||
currentIPAddr->Next = nextIPAddr;
|
||||
currentIPAddr = nextIPAddr;
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwAddr,
|
||||
currentIPAddr->IpAddress.String);
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwMask,
|
||||
currentIPAddr->IpMask.String);
|
||||
nextIPAddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no IP was found it probably means that the interface is not
|
||||
* configured. In this case we have to return a zeroed IP and mask. */
|
||||
if (firstIPAddr) {
|
||||
strcpy(ptr->IpAddressList.IpAddress.String, "0.0.0.0");
|
||||
strcpy(ptr->IpAddressList.IpMask.String, "0.0.0.0");
|
||||
}
|
||||
/* Find first router through this interface, which we'll assume
|
||||
* is the default gateway for this adapter */
|
||||
strcpy(ptr->GatewayList.IpAddress.String, "0.0.0.0");
|
||||
strcpy(ptr->GatewayList.IpMask.String, "255.255.255.255");
|
||||
for (i = 0; i < routeTable->dwNumEntries; i++)
|
||||
if (routeTable->table[i].dwForwardIfIndex == ptr->Index
|
||||
&& routeTable->table[i].u1.ForwardType ==
|
||||
MIB_IPROUTE_TYPE_INDIRECT)
|
||||
err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
|
||||
(void **)&if_keys, sizeof(*if_keys), (void **)&if_rw, sizeof(*if_rw),
|
||||
(void **)&if_dyn, sizeof(*if_dyn), (void **)&if_stat, sizeof(*if_stat), &if_count, 0 );
|
||||
if (err) return err;
|
||||
for (i = 0; i < if_count; i++)
|
||||
{
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&routeTable->table[i].dwForwardNextHop,
|
||||
ptr->GatewayList.IpAddress.String);
|
||||
RtlIpv4AddressToStringA((IN_ADDR *)&routeTable->table[i].dwForwardMask,
|
||||
ptr->GatewayList.IpMask.String);
|
||||
if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
|
||||
if_num++;
|
||||
}
|
||||
if (wins_server_count)
|
||||
|
||||
if (!if_num)
|
||||
{
|
||||
ptr->HaveWins = TRUE;
|
||||
RtlIpv4AddressToStringA( &wins_servers[0].Ipv4.sin_addr, ptr->PrimaryWinsServer.IpAddress.String );
|
||||
err = ERROR_NO_DATA;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE,
|
||||
(void **)&uni_keys, sizeof(*uni_keys), (void **)&uni_rw, sizeof(*uni_rw),
|
||||
NULL, 0, NULL, 0, &uni_count, 0 );
|
||||
if (err) goto err;
|
||||
|
||||
/* Slightly overestimate the needed size by assuming that all
|
||||
unicast addresses require a separate IP_ADDR_STRING. */
|
||||
|
||||
needed = if_num * sizeof(*info) + uni_count * sizeof(IP_ADDR_STRING);
|
||||
if (!info || *size < needed)
|
||||
{
|
||||
*size = needed;
|
||||
err = ERROR_BUFFER_OVERFLOW;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE,
|
||||
(void **)&fwd_keys, sizeof(*fwd_keys), NULL, 0,
|
||||
NULL, 0, NULL, 0, &fwd_count, 0 );
|
||||
if (err) goto err;
|
||||
|
||||
wins_server_count = get_wins_servers( &wins_servers );
|
||||
|
||||
extra_ip_addrs = (IP_ADDR_STRING *)(info + if_num);
|
||||
for (i = 0; i < if_count; i++)
|
||||
{
|
||||
if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
|
||||
|
||||
info->Next = info + 1;
|
||||
info->ComboIndex = 0;
|
||||
ConvertGuidToStringA( &if_stat[i].if_guid, info->AdapterName, sizeof(info->AdapterName) );
|
||||
len = WideCharToMultiByte( CP_ACP, 0, if_stat[i].descr.String, if_stat[i].descr.Length / sizeof(WCHAR),
|
||||
info->Description, sizeof(info->Description) - 1, NULL, NULL );
|
||||
info->Description[len] = '\0';
|
||||
info->AddressLength = if_rw[i].phys_addr.Length;
|
||||
if (info->AddressLength > sizeof(info->Address)) info->AddressLength = 0;
|
||||
memcpy( info->Address, if_rw[i].phys_addr.Address, info->AddressLength );
|
||||
memset( info->Address + info->AddressLength, 0, sizeof(info->Address) - info->AddressLength );
|
||||
info->Index = if_stat[i].if_index;
|
||||
info->Type = if_stat[i].type;
|
||||
info->DhcpEnabled = TRUE; /* FIXME */
|
||||
info->CurrentIpAddress = NULL;
|
||||
|
||||
cursor = NULL;
|
||||
for (uni = 0; uni < uni_count; uni++)
|
||||
{
|
||||
if (uni_keys[uni].luid.Value != if_keys[i].Value) continue;
|
||||
if (!cursor) cursor = &info->IpAddressList;
|
||||
else
|
||||
{
|
||||
cursor->Next = extra_ip_addrs++;
|
||||
cursor = cursor->Next;
|
||||
}
|
||||
ConvertLengthToIpv4Mask( uni_rw[uni].on_link_prefix, &mask.WS_s_addr );
|
||||
ip_addr_string_init( cursor, &uni_keys[uni].addr, &mask, 0 );
|
||||
}
|
||||
if (!cursor)
|
||||
{
|
||||
mask.WS_s_addr = INADDR_ANY;
|
||||
ip_addr_string_init( &info->IpAddressList, &mask, &mask, 0 );
|
||||
}
|
||||
|
||||
gw.WS_s_addr = INADDR_ANY;
|
||||
mask.WS_s_addr = INADDR_NONE;
|
||||
for (fwd = 0; fwd < fwd_count; fwd++)
|
||||
{ /* find the first router on this interface */
|
||||
if (fwd_keys[fwd].luid.Value == if_keys[i].Value &&
|
||||
fwd_keys[fwd].next_hop.WS_s_addr != INADDR_ANY &&
|
||||
!fwd_keys[fwd].prefix_len)
|
||||
{
|
||||
gw = fwd_keys[fwd].next_hop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ip_addr_string_init( &info->GatewayList, &gw, &mask, 0 );
|
||||
|
||||
ip_addr_string_init( &info->DhcpServer, NULL, NULL, 0 );
|
||||
|
||||
info->HaveWins = !!wins_server_count;
|
||||
ip_addr_string_init( &info->PrimaryWinsServer, NULL, NULL, 0 );
|
||||
ip_addr_string_init( &info->SecondaryWinsServer, NULL, NULL, 0 );
|
||||
if (info->HaveWins)
|
||||
{
|
||||
mask.WS_s_addr = INADDR_NONE;
|
||||
ip_addr_string_init( &info->PrimaryWinsServer, &wins_servers[0].Ipv4.sin_addr, &mask, 0 );
|
||||
if (wins_server_count > 1)
|
||||
RtlIpv4AddressToStringA( &wins_servers[1].Ipv4.sin_addr, ptr->SecondaryWinsServer.IpAddress.String );
|
||||
ip_addr_string_init( &info->SecondaryWinsServer, &wins_servers[1].Ipv4.sin_addr, &mask, 0 );
|
||||
}
|
||||
if (ndx < table->numIndexes - 1)
|
||||
ptr->Next = &pAdapterInfo[ndx + 1];
|
||||
else
|
||||
ptr->Next = NULL;
|
||||
|
||||
ptr->DhcpEnabled = TRUE;
|
||||
info->LeaseObtained = 0;
|
||||
info->LeaseExpires = 0;
|
||||
|
||||
info++;
|
||||
}
|
||||
info[-1].Next = NULL;
|
||||
|
||||
err:
|
||||
heap_free( wins_servers );
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, table);
|
||||
}
|
||||
else
|
||||
ret = ERROR_OUTOFMEMORY;
|
||||
HeapFree(GetProcessHeap(), 0, routeTable);
|
||||
HeapFree(GetProcessHeap(), 0, ipAddrTable);
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = ERROR_NO_DATA;
|
||||
}
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
NsiFreeTable( fwd_keys, NULL, NULL, NULL );
|
||||
NsiFreeTable( uni_keys, uni_rw, NULL, NULL );
|
||||
NsiFreeTable( if_keys, if_rw, if_dyn, if_stat );
|
||||
return err;
|
||||
}
|
||||
|
||||
static DWORD typeFromMibType(DWORD mib_type)
|
||||
|
|
Loading…
Reference in New Issue