iphlpapi: Implement GetIpForwardTable() 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
8f207fe7a8
commit
0515480d89
|
@ -2182,51 +2182,100 @@ DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL s
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ipforward_row_cmp( const void *a, const void *b )
|
||||
{
|
||||
const MIB_IPFORWARDROW *rowA = a;
|
||||
const MIB_IPFORWARDROW *rowB = b;
|
||||
int ret;
|
||||
|
||||
if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
|
||||
if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
|
||||
if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
|
||||
return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetIpForwardTable (IPHLPAPI.@)
|
||||
*
|
||||
* Get the route table.
|
||||
*
|
||||
* PARAMS
|
||||
* pIpForwardTable [Out] buffer for route table
|
||||
* pdwSize [In/Out] length of output buffer
|
||||
* bOrder [In] whether to sort the table
|
||||
* table [Out] buffer for route table
|
||||
* size [In/Out] length of output buffer
|
||||
* sort [In] whether to sort the table
|
||||
*
|
||||
* RETURNS
|
||||
* Success: NO_ERROR
|
||||
* 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 the next hop and
|
||||
* an assortment of arbitrary parameters.
|
||||
*/
|
||||
DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
|
||||
DWORD WINAPI GetIpForwardTable( MIB_IPFORWARDTABLE *table, ULONG *size, BOOL sort )
|
||||
{
|
||||
DWORD ret;
|
||||
PMIB_IPFORWARDTABLE table;
|
||||
DWORD err, count, uni_count, needed, i, addr;
|
||||
struct nsi_ipv4_forward_key *keys;
|
||||
struct nsi_ip_forward_rw *rw;
|
||||
struct nsi_ipv4_forward_dynamic *dyn;
|
||||
struct nsi_ip_forward_static *stat;
|
||||
struct nsi_ipv4_unicast_key *uni_keys = NULL;
|
||||
|
||||
TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
|
||||
TRACE( "table %p, size %p, sort %d\n", table, size, sort );
|
||||
if (!size) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!pdwSize) return ERROR_INVALID_PARAMETER;
|
||||
err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, (void **)&keys, sizeof(*keys),
|
||||
(void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
|
||||
(void **)&stat, sizeof(*stat), &count, 0 );
|
||||
if (err) return err;
|
||||
|
||||
ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
|
||||
if (!ret) {
|
||||
DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
|
||||
if (!pIpForwardTable || *pdwSize < size) {
|
||||
*pdwSize = size;
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
|
||||
|
||||
if (!table || *size < needed)
|
||||
{
|
||||
*size = needed;
|
||||
err = ERROR_INSUFFICIENT_BUFFER;
|
||||
goto err;
|
||||
}
|
||||
else {
|
||||
*pdwSize = size;
|
||||
memcpy(pIpForwardTable, table, size);
|
||||
|
||||
err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
|
||||
NULL, 0, NULL, 0, NULL, 0, &uni_count, 0 );
|
||||
if (err) goto err;
|
||||
|
||||
table->dwNumEntries = count;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
MIB_IPFORWARDROW *row = table->table + i;
|
||||
|
||||
row->dwForwardDest = keys[i].prefix.WS_s_addr;
|
||||
ConvertLengthToIpv4Mask( keys[i].prefix_len, &row->dwForwardMask );
|
||||
row->dwForwardPolicy = 0;
|
||||
row->dwForwardNextHop = keys[i].next_hop.WS_s_addr;
|
||||
row->u1.dwForwardType = row->dwForwardNextHop ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
|
||||
if (!row->dwForwardNextHop) /* find the interface's addr */
|
||||
{
|
||||
for (addr = 0; addr < uni_count; addr++)
|
||||
{
|
||||
if (uni_keys[addr].luid.Value == keys[i].luid.Value)
|
||||
{
|
||||
row->dwForwardNextHop = uni_keys[addr].addr.WS_s_addr;
|
||||
break;
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, table);
|
||||
}
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
row->dwForwardIfIndex = stat[i].if_index;
|
||||
row->u2.dwForwardProto = rw[i].protocol;
|
||||
row->dwForwardAge = dyn[i].age;
|
||||
row->dwForwardNextHopAS = 0;
|
||||
row->dwForwardMetric1 = rw[i].metric; /* FIXME: add interface metric */
|
||||
row->dwForwardMetric2 = 0;
|
||||
row->dwForwardMetric3 = 0;
|
||||
row->dwForwardMetric4 = 0;
|
||||
row->dwForwardMetric5 = 0;
|
||||
}
|
||||
|
||||
if (sort) qsort( table->table, count, sizeof(MIB_IPFORWARDROW), ipforward_row_cmp );
|
||||
err:
|
||||
NsiFreeTable( uni_keys, NULL, NULL, NULL );
|
||||
NsiFreeTable( keys, rw, dyn, stat );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
|
||||
|
|
|
@ -286,63 +286,83 @@ static void testGetIfTable(void)
|
|||
|
||||
static void testGetIpForwardTable(void)
|
||||
{
|
||||
DWORD apiReturn;
|
||||
ULONG dwSize = 0;
|
||||
DWORD err, i, j;
|
||||
ULONG size = 0;
|
||||
MIB_IPFORWARDTABLE *buf;
|
||||
MIB_IPFORWARD_TABLE2 *table2;
|
||||
MIB_UNICASTIPADDRESS_TABLE *unicast;
|
||||
|
||||
apiReturn = GetIpForwardTable(NULL, NULL, FALSE);
|
||||
if (apiReturn == ERROR_NOT_SUPPORTED) {
|
||||
skip("GetIpForwardTable is not supported\n");
|
||||
return;
|
||||
}
|
||||
ok(apiReturn == ERROR_INVALID_PARAMETER,
|
||||
"GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
|
||||
apiReturn);
|
||||
apiReturn = GetIpForwardTable(NULL, &dwSize, FALSE);
|
||||
ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
|
||||
"GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
|
||||
apiReturn);
|
||||
if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
|
||||
PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
|
||||
err = GetIpForwardTable( NULL, NULL, FALSE );
|
||||
ok( err == ERROR_INVALID_PARAMETER, "got %d\n", err );
|
||||
|
||||
apiReturn = GetIpForwardTable(buf, &dwSize, FALSE);
|
||||
ok(apiReturn == NO_ERROR,
|
||||
"GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
|
||||
apiReturn);
|
||||
err = GetIpForwardTable( NULL, &size, FALSE );
|
||||
ok( err == ERROR_INSUFFICIENT_BUFFER, "got %d\n", err );
|
||||
|
||||
if (apiReturn == NO_ERROR)
|
||||
{
|
||||
DWORD i;
|
||||
buf = malloc( size );
|
||||
err = GetIpForwardTable( buf, &size, FALSE );
|
||||
ok( !err, "got %d\n", err );
|
||||
|
||||
err = GetIpForwardTable2( AF_INET, &table2 );
|
||||
ok( !err, "got %d\n", err );
|
||||
ok( buf->dwNumEntries == table2->NumEntries, "got %d vs %d\n",
|
||||
buf->dwNumEntries, table2->NumEntries );
|
||||
|
||||
err = GetUnicastIpAddressTable( AF_INET, &unicast );
|
||||
ok( !err, "got %d\n", err );
|
||||
|
||||
trace( "IP forward table: %u entries\n", buf->dwNumEntries );
|
||||
for (i = 0; i < buf->dwNumEntries; i++)
|
||||
{
|
||||
if (!U1(buf->table[i]).dwForwardDest) /* Default route */
|
||||
{
|
||||
todo_wine
|
||||
ok (U1(buf->table[i]).dwForwardProto == MIB_IPPROTO_NETMGMT,
|
||||
"Unexpected dwForwardProto %d\n", U1(buf->table[i]).dwForwardProto);
|
||||
ok (U1(buf->table[i]).dwForwardType == MIB_IPROUTE_TYPE_INDIRECT,
|
||||
"Unexpected dwForwardType %d\n", U1(buf->table[i]).dwForwardType);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In general we should get MIB_IPPROTO_LOCAL but does not work
|
||||
* for Vista, 2008 and 7. */
|
||||
ok (U1(buf->table[i]).dwForwardProto == MIB_IPPROTO_LOCAL ||
|
||||
broken(U1(buf->table[i]).dwForwardProto == MIB_IPPROTO_NETMGMT),
|
||||
"Unexpected dwForwardProto %d\n", U1(buf->table[i]).dwForwardProto);
|
||||
/* The forward type varies depending on the address and gateway
|
||||
* value so it is not worth testing in this case. */
|
||||
}
|
||||
MIB_IPFORWARDROW *row = buf->table + i;
|
||||
MIB_IPFORWARD_ROW2 *row2 = table2->Table + i;
|
||||
DWORD mask, next_hop;
|
||||
|
||||
trace( "%u: dest %s mask %s gw %s if %u type %u proto %u\n", i,
|
||||
ntoa( buf->table[i].dwForwardDest ), ntoa( buf->table[i].dwForwardMask ),
|
||||
ntoa( buf->table[i].dwForwardNextHop ), buf->table[i].dwForwardIfIndex,
|
||||
U1(buf->table[i]).dwForwardType, U1(buf->table[i]).dwForwardProto );
|
||||
winetest_push_context( "%d", i );
|
||||
|
||||
trace( "dest %s mask %s gw %s if %u type %u proto %u\n",
|
||||
ntoa( row->dwForwardDest ), ntoa( row->dwForwardMask ),
|
||||
ntoa( row->dwForwardNextHop ), row->dwForwardIfIndex,
|
||||
row->dwForwardType, row->dwForwardProto );
|
||||
ok( row->dwForwardDest == row2->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr,
|
||||
"got %08x vs %08x\n", row->dwForwardDest, row2->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr );
|
||||
ConvertLengthToIpv4Mask( row2->DestinationPrefix.PrefixLength, &mask );
|
||||
ok( row->dwForwardMask == mask, "got %08x vs %08x\n", row->dwForwardMask, mask );
|
||||
ok( row->dwForwardPolicy == 0, "got %d\n", row->dwForwardPolicy );
|
||||
|
||||
next_hop = row2->NextHop.Ipv4.sin_addr.s_addr;
|
||||
if (!next_hop) /* for direct addresses, dwForwardNextHop is set to the address of the appropriate interface */
|
||||
{
|
||||
for (j = 0; j < unicast->NumEntries; j++)
|
||||
{
|
||||
if (unicast->Table[j].InterfaceLuid.Value == row2->InterfaceLuid.Value)
|
||||
{
|
||||
next_hop = unicast->Table[j].Address.Ipv4.sin_addr.s_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, buf);
|
||||
}
|
||||
ok( row->dwForwardNextHop == next_hop, "got %08x vs %08x\n", row->dwForwardNextHop, next_hop );
|
||||
|
||||
ok( row->dwForwardIfIndex == row2->InterfaceIndex, "got %d vs %d\n", row->dwForwardIfIndex, row2->InterfaceIndex );
|
||||
if (!row2->NextHop.Ipv4.sin_addr.s_addr)
|
||||
ok( buf->table[i].dwForwardType == MIB_IPROUTE_TYPE_DIRECT, "got %d\n", buf->table[i].dwForwardType );
|
||||
else
|
||||
ok( buf->table[i].dwForwardType == MIB_IPROUTE_TYPE_INDIRECT, "got %d\n", buf->table[i].dwForwardType );
|
||||
ok( row->dwForwardProto == row2->Protocol, "got %d vs %d\n", row->dwForwardProto, row2->Protocol );
|
||||
ok( row->dwForwardAge == row2->Age, "got %d vs %d\n", row->dwForwardAge, row2->Age );
|
||||
ok( row->dwForwardNextHopAS == 0, "got %08x\n", row->dwForwardNextHopAS );
|
||||
/* FIXME: need to add the interface's metric from GetIpInterfaceTable() */
|
||||
ok( row->dwForwardMetric1 >= row2->Metric, "got %d vs %d\n", row->dwForwardMetric1, row2->Metric );
|
||||
ok( row->dwForwardMetric2 == 0, "got %d\n", row->dwForwardMetric2 );
|
||||
ok( row->dwForwardMetric3 == 0, "got %d\n", row->dwForwardMetric3 );
|
||||
ok( row->dwForwardMetric4 == 0, "got %d\n", row->dwForwardMetric4 );
|
||||
ok( row->dwForwardMetric5 == 0, "got %d\n", row->dwForwardMetric5 );
|
||||
|
||||
winetest_pop_context();
|
||||
}
|
||||
FreeMibTable( unicast );
|
||||
FreeMibTable( table2 );
|
||||
free( buf );
|
||||
}
|
||||
|
||||
static void testGetIpNetTable(void)
|
||||
|
|
Loading…
Reference in New Issue