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;
|
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.@)
|
* GetIpForwardTable (IPHLPAPI.@)
|
||||||
*
|
*
|
||||||
* Get the route table.
|
* Get the route table.
|
||||||
*
|
*
|
||||||
* PARAMS
|
* PARAMS
|
||||||
* pIpForwardTable [Out] buffer for route table
|
* table [Out] buffer for route 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 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;
|
DWORD err, count, uni_count, needed, i, addr;
|
||||||
PMIB_IPFORWARDTABLE table;
|
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);
|
needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
|
||||||
if (!ret) {
|
|
||||||
DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
|
if (!table || *size < needed)
|
||||||
if (!pIpForwardTable || *pdwSize < size) {
|
{
|
||||||
*pdwSize = size;
|
*size = needed;
|
||||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
err = ERROR_INSUFFICIENT_BUFFER;
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
*pdwSize = size;
|
err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
|
||||||
memcpy(pIpForwardTable, table, size);
|
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,
|
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)
|
static void testGetIpForwardTable(void)
|
||||||
{
|
{
|
||||||
DWORD apiReturn;
|
DWORD err, i, j;
|
||||||
ULONG dwSize = 0;
|
ULONG size = 0;
|
||||||
|
MIB_IPFORWARDTABLE *buf;
|
||||||
|
MIB_IPFORWARD_TABLE2 *table2;
|
||||||
|
MIB_UNICASTIPADDRESS_TABLE *unicast;
|
||||||
|
|
||||||
apiReturn = GetIpForwardTable(NULL, NULL, FALSE);
|
err = GetIpForwardTable( NULL, NULL, FALSE );
|
||||||
if (apiReturn == ERROR_NOT_SUPPORTED) {
|
ok( err == ERROR_INVALID_PARAMETER, "got %d\n", err );
|
||||||
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);
|
|
||||||
|
|
||||||
apiReturn = GetIpForwardTable(buf, &dwSize, FALSE);
|
err = GetIpForwardTable( NULL, &size, FALSE );
|
||||||
ok(apiReturn == NO_ERROR,
|
ok( err == ERROR_INSUFFICIENT_BUFFER, "got %d\n", err );
|
||||||
"GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
|
|
||||||
apiReturn);
|
|
||||||
|
|
||||||
if (apiReturn == NO_ERROR)
|
buf = malloc( size );
|
||||||
{
|
err = GetIpForwardTable( buf, &size, FALSE );
|
||||||
DWORD i;
|
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 );
|
trace( "IP forward table: %u entries\n", buf->dwNumEntries );
|
||||||
for (i = 0; i < buf->dwNumEntries; i++)
|
for (i = 0; i < buf->dwNumEntries; i++)
|
||||||
{
|
{
|
||||||
if (!U1(buf->table[i]).dwForwardDest) /* Default route */
|
MIB_IPFORWARDROW *row = buf->table + i;
|
||||||
{
|
MIB_IPFORWARD_ROW2 *row2 = table2->Table + i;
|
||||||
todo_wine
|
DWORD mask, next_hop;
|
||||||
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. */
|
|
||||||
}
|
|
||||||
|
|
||||||
trace( "%u: dest %s mask %s gw %s if %u type %u proto %u\n", i,
|
winetest_push_context( "%d", i );
|
||||||
ntoa( buf->table[i].dwForwardDest ), ntoa( buf->table[i].dwForwardMask ),
|
|
||||||
ntoa( buf->table[i].dwForwardNextHop ), buf->table[i].dwForwardIfIndex,
|
trace( "dest %s mask %s gw %s if %u type %u proto %u\n",
|
||||||
U1(buf->table[i]).dwForwardType, U1(buf->table[i]).dwForwardProto );
|
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)
|
static void testGetIpNetTable(void)
|
||||||
|
|
Loading…
Reference in New Issue