Signed-off-by: Huw Davies huw@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)