[PATCH 3/4] iphlpapi: Implement GetIpForwardTable() on top of nsi.
Huw Davies
huw at codeweavers.com
Mon Aug 2 03:19:06 CDT 2021
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 107 +++++++++++++++++++++---------
dlls/iphlpapi/tests/iphlpapi.c | 116 +++++++++++++++++++--------------
2 files changed, 146 insertions(+), 77 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index f53c77ba434..7637553780a 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -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;
- }
- else {
- *pdwSize = size;
- memcpy(pIpForwardTable, table, size);
- }
- HeapFree(GetProcessHeap(), 0, table);
+ needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
+
+ if (!table || *size < needed)
+ {
+ *size = needed;
+ err = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
}
- TRACE("returning %d\n", ret);
- return ret;
+
+ 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;
+ }
+ }
+ }
+ 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,
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index 51566034f51..785e4e9fb70 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -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 );
- trace( "IP forward table: %u entries\n", buf->dwNumEntries );
- for (i = 0; i < buf->dwNumEntries; i++)
+ 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++)
+ {
+ MIB_IPFORWARDROW *row = buf->table + i;
+ MIB_IPFORWARD_ROW2 *row2 = table2->Table + i;
+ DWORD mask, next_hop;
+
+ 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 (!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
+ if (unicast->Table[j].InterfaceLuid.Value == row2->InterfaceLuid.Value)
{
- /* 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. */
+ next_hop = unicast->Table[j].Address.Ipv4.sin_addr.s_addr;
+ break;
}
-
- 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 );
}
}
- 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)
--
2.23.0
More information about the wine-devel
mailing list