iphlpapi: Implement GetIpNetTable() 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:
Huw Davies 2021-08-10 09:20:49 +01:00 committed by Alexandre Julliard
parent ae3e512b77
commit a16697398b
1 changed files with 68 additions and 27 deletions

View File

@ -2230,50 +2230,91 @@ err:
return err; return err;
} }
static int ipnetrow_cmp( const void *a, const void *b )
{
const MIB_IPNETROW *row_a = a;
const MIB_IPNETROW *row_b = b;
return RtlUlongByteSwap( row_a->dwAddr ) - RtlUlongByteSwap( row_b->dwAddr );
}
/****************************************************************** /******************************************************************
* GetIpNetTable (IPHLPAPI.@) * GetIpNetTable (IPHLPAPI.@)
* *
* Get the IP-to-physical address mapping table. * Get the IP-to-physical address mapping table.
* *
* PARAMS * PARAMS
* pIpNetTable [Out] buffer for mapping table * table [Out] buffer for mapping table
* pdwSize [In/Out] length of output buffer * size [In/Out] length of output buffer
* bOrder [In] whether to sort the table * sort [In] whether to sort the table
* *
* RETURNS * RETURNS
* Success: NO_ERROR * Success: NO_ERROR
* Failure: error code from winerror.h * Failure: error code from winerror.h
* *
* NOTES
* If pdwSize is less than required, the function will return
* ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
* size.
* If bOrder is true, the returned table will be sorted by IP address.
*/ */
DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder) DWORD WINAPI GetIpNetTable( MIB_IPNETTABLE *table, ULONG *size, BOOL sort )
{ {
DWORD ret; DWORD err, count, needed, i;
PMIB_IPNETTABLE table; struct nsi_ipv4_neighbour_key *keys;
struct nsi_ip_neighbour_rw *rw;
struct nsi_ip_neighbour_dynamic *dyn;
TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder); TRACE( "table %p, size %p, sort %d\n", table, size, sort );
if (!pdwSize) return ERROR_INVALID_PARAMETER; if (!size) return ERROR_INVALID_PARAMETER;
ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 ); err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_NEIGHBOUR_TABLE, (void **)&keys, sizeof(*keys),
if (!ret) { (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] ); NULL, 0, &count, 0 );
if (!pIpNetTable || *pdwSize < size) { if (err) return err;
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER; needed = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
}
else { if (!table || *size < needed)
*pdwSize = size; {
memcpy(pIpNetTable, table, size); *size = needed;
} err = ERROR_INSUFFICIENT_BUFFER;
HeapFree(GetProcessHeap(), 0, table); goto err;
} }
TRACE("returning %d\n", ret);
return ret; table->dwNumEntries = count;
for (i = 0; i < count; i++)
{
MIB_IPNETROW *row = table->table + i;
ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
row->dwPhysAddrLen = dyn[i].phys_addr_len;
if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
memcpy( row->bPhysAddr, rw[i].phys_addr, row->dwPhysAddrLen );
memset( row->bPhysAddr + row->dwPhysAddrLen, 0,
sizeof(row->bPhysAddr) - row->dwPhysAddrLen );
row->dwAddr = keys[i].addr.WS_s_addr;
switch (dyn->state)
{
case NlnsUnreachable:
case NlnsIncomplete:
row->u.Type = MIB_IPNET_TYPE_INVALID;
break;
case NlnsProbe:
case NlnsDelay:
case NlnsStale:
case NlnsReachable:
row->u.Type = MIB_IPNET_TYPE_DYNAMIC;
break;
case NlnsPermanent:
row->u.Type = MIB_IPNET_TYPE_STATIC;
break;
default:
row->u.Type = MIB_IPNET_TYPE_OTHER;
}
}
if (sort) qsort( table->table, table->dwNumEntries, sizeof(*table->table), ipnetrow_cmp );
err:
NsiFreeTable( keys, rw, dyn, NULL );
return err;
} }
static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw, static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw,