[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