Wine-Devel
By message
wine-devel@list.winehq.org
By month
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2021
- 78 participants
- 929 discussions
Aug. 2, 2021
Signed-off-by: Huw Davies <huw(a)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
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 128 +++++++++++++++++++++++++++++++---
dlls/nsi/tests/nsi.c | 2 -
2 files changed, 117 insertions(+), 13 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index b2d597fd9ab..f53c77ba434 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -2229,6 +2229,123 @@ DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSi
return ret;
}
+static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
+ void *dyn, struct nsi_ip_forward_static *stat )
+{
+ struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key;
+ struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key;
+ struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn;
+ struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn;
+
+ if (fam == WS_AF_INET)
+ {
+ row->InterfaceLuid = key4->luid;
+ row->DestinationPrefix.Prefix.Ipv4.sin_family = fam;
+ row->DestinationPrefix.Prefix.Ipv4.sin_port = 0;
+ row->DestinationPrefix.Prefix.Ipv4.sin_addr = key4->prefix;
+ memset( &row->DestinationPrefix.Prefix.Ipv4.sin_zero, 0, sizeof(row->DestinationPrefix.Prefix.Ipv4.sin_zero) );
+ row->DestinationPrefix.PrefixLength = key4->prefix_len;
+ row->NextHop.Ipv4.sin_family = fam;
+ row->NextHop.Ipv4.sin_port = 0;
+ row->NextHop.Ipv4.sin_addr = key4->next_hop;
+ memset( &row->NextHop.Ipv4.sin_zero, 0, sizeof(row->NextHop.Ipv4.sin_zero) );
+
+ row->Age = dyn4->age;
+ }
+ else
+ {
+ row->InterfaceLuid = key6->luid;
+
+ row->DestinationPrefix.Prefix.Ipv6.sin6_family = fam;
+ row->DestinationPrefix.Prefix.Ipv6.sin6_port = 0;
+ row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo = 0;
+ row->DestinationPrefix.Prefix.Ipv6.sin6_addr = key6->prefix;
+ row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id = 0;
+ row->DestinationPrefix.PrefixLength = key6->prefix_len;
+ row->NextHop.Ipv6.sin6_family = fam;
+ row->NextHop.Ipv6.sin6_port = 0;
+ row->NextHop.Ipv6.sin6_flowinfo = 0;
+ row->NextHop.Ipv6.sin6_addr = key6->next_hop;
+ row->NextHop.Ipv6.sin6_scope_id = 0;
+
+ row->Age = dyn6->age;
+ }
+
+ row->InterfaceIndex = stat->if_index;
+
+ row->SitePrefixLength = rw->site_prefix_len;
+ row->ValidLifetime = rw->valid_lifetime;
+ row->PreferredLifetime = rw->preferred_lifetime;
+ row->Metric = rw->metric;
+ row->Protocol = rw->protocol;
+ row->Loopback = rw->loopback;
+ row->AutoconfigureAddress = rw->autoconf;
+ row->Publish = rw->publish;
+ row->Immortal = rw->immortal;
+
+ row->Origin = stat->origin;
+}
+
+/******************************************************************
+ * GetIpForwardTable2 (IPHLPAPI.@)
+ */
+DWORD WINAPI GetIpForwardTable2( ADDRESS_FAMILY family, MIB_IPFORWARD_TABLE2 **table )
+{
+ void *key[2] = { NULL, NULL };
+ struct nsi_ip_forward_rw *rw[2] = { NULL, NULL };
+ void *dyn[2] = { NULL, NULL };
+ struct nsi_ip_forward_static *stat[2] = { NULL, NULL };
+ static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
+ static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ipv6_forward_key) };
+ static const DWORD dyn_size[2] = { sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ipv6_forward_dynamic) };
+ DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
+
+ TRACE( "%u, %p\n", family, table );
+
+ if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
+ return ERROR_INVALID_PARAMETER;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (family != WS_AF_UNSPEC && family != fam[i]) continue;
+
+ err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_FORWARD_TABLE, key + i, key_size[i],
+ (void **)rw + i, sizeof(**rw), dyn + i, dyn_size[i],
+ (void **)stat + i, sizeof(**stat), count + i, 0 );
+ if (err) count[i] = 0;
+ }
+
+ size = FIELD_OFFSET(MIB_IPFORWARD_TABLE2, Table[ count[0] + count[1] ]);
+ *table = heap_alloc( size );
+ if (!*table)
+ {
+ err = ERROR_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+
+ (*table)->NumEntries = count[0] + count[1];
+ for (i = 0; i < count[0]; i++)
+ {
+ MIB_IPFORWARD_ROW2 *row = (*table)->Table + i;
+ struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key[0];
+ struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn[0];
+
+ forward_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn4 + i, stat[0] + i );
+ }
+
+ for (i = 0; i < count[1]; i++)
+ {
+ MIB_IPFORWARD_ROW2 *row = (*table)->Table + count[0] + i;
+ struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key[1];
+ struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn[1];
+
+ forward_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn6 + i, stat[1] + i );
+ }
+
+err:
+ for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
+ return err;
+}
/******************************************************************
* GetIpNetTable (IPHLPAPI.@)
@@ -3556,17 +3673,6 @@ char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
return name;
}
-/******************************************************************
- * GetIpForwardTable2 (IPHLPAPI.@)
- */
-DWORD WINAPI GetIpForwardTable2(ADDRESS_FAMILY family, PMIB_IPFORWARD_TABLE2 *table)
-{
- static int once;
-
- if (!once++) FIXME("(%u %p): stub\n", family, table);
- return ERROR_NOT_SUPPORTED;
-}
-
/******************************************************************
* GetIpNetTable2 (IPHLPAPI.@)
*/
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 9f6349bd0e7..c689aca6754 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -531,9 +531,7 @@ todo_wine_if (family == AF_INET6)
dyn_size = dyn_sizes[i];
err = GetIpForwardTable2( family, &table );
-todo_wine
ok( !err, "got %d\n", err );
- if (err) { winetest_pop_context(); return; }
ok( table->NumEntries == count, "table entries %d count %d\n", table->NumEntries, count );
for (i = 0; i < count; i++)
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsi/tests/nsi.c | 117 ++++++++++++
dlls/nsiproxy.sys/ip.c | 268 +++++++++++++++++++++++++++
dlls/nsiproxy.sys/nsiproxy_private.h | 38 ++++
include/netioapi.h | 2 +
include/wine/nsi.h | 62 +++++++
5 files changed, 487 insertions(+)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 869fa255bb2..9f6349bd0e7 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -485,6 +485,121 @@ static void test_ip_unicast( int family )
winetest_pop_context();
}
+static void test_ip_forward( int family )
+{
+ DWORD rw_sizes[] = { FIELD_OFFSET(struct nsi_ip_forward_rw, unk),
+ FIELD_OFFSET(struct nsi_ip_forward_rw, unk2), sizeof(struct nsi_ip_forward_rw) };
+ DWORD dyn_sizes4[] = { sizeof(struct nsi_ipv4_forward_dynamic) - 3 * sizeof(DWORD),
+ sizeof(struct nsi_ipv4_forward_dynamic) };
+ DWORD dyn_sizes6[] = { sizeof(struct nsi_ipv6_forward_dynamic) - 3 * sizeof(DWORD),
+ sizeof(struct nsi_ipv6_forward_dynamic) };
+ DWORD *dyn_sizes = family == AF_INET ? dyn_sizes4 : dyn_sizes6;
+ struct nsi_ipv4_forward_key *key_tbl, *key4;
+ struct nsi_ipv6_forward_key *key6;
+ struct nsi_ip_forward_rw *rw_tbl, *rw;
+ struct nsi_ipv4_forward_dynamic *dyn_tbl, *dyn4;
+ struct nsi_ipv6_forward_dynamic *dyn6;
+ struct nsi_ip_forward_static *stat_tbl, *stat;
+ MIB_IPFORWARD_TABLE2 *table;
+ const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
+ DWORD key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
+ DWORD err, count, i, rw_size, dyn_size;
+
+ winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
+
+ for (i = 0; i < ARRAY_SIZE(rw_sizes); i++)
+ {
+ err = NsiAllocateAndGetTable( 1, mod, NSI_IP_FORWARD_TABLE, (void **)&key_tbl, key_size,
+ (void **)&rw_tbl, rw_sizes[i], NULL, 0,
+ NULL, 0, &count, 0 );
+ if (!err) break;
+ }
+todo_wine_if (family == AF_INET6)
+ ok( !err, "got %d\n", err );
+ if (err) { winetest_pop_context(); return; }
+ rw_size = rw_sizes[i];
+ NsiFreeTable( key_tbl, rw_tbl, NULL, NULL );
+
+ for (i = 0; i < ARRAY_SIZE(dyn_sizes4); i++)
+ {
+ err = NsiAllocateAndGetTable( 1, mod, NSI_IP_FORWARD_TABLE, (void **)&key_tbl, key_size,
+ (void **)&rw_tbl, rw_size, (void **)&dyn_tbl, dyn_sizes[i],
+ (void **)&stat_tbl, sizeof(*stat_tbl), &count, 0 );
+ if (!err) break;
+ }
+ ok( !err, "got %d\n", err );
+ dyn_size = dyn_sizes[i];
+
+ err = GetIpForwardTable2( family, &table );
+todo_wine
+ ok( !err, "got %d\n", err );
+ if (err) { winetest_pop_context(); return; }
+ ok( table->NumEntries == count, "table entries %d count %d\n", table->NumEntries, count );
+
+ for (i = 0; i < count; i++)
+ {
+ MIB_IPFORWARD_ROW2 *row = table->Table + i;
+ rw = (struct nsi_ip_forward_rw *)((BYTE *)rw_tbl + i * rw_size);
+ stat = stat_tbl + i;
+ winetest_push_context( "%d", i );
+
+ ok( row->DestinationPrefix.Prefix.si_family == family, "mismatch\n" );
+
+ if (family == AF_INET)
+ {
+ key4 = key_tbl + i;
+ dyn4 = (struct nsi_ipv4_forward_dynamic *)((BYTE *)dyn_tbl + i * dyn_size);
+
+ ok( row->InterfaceLuid.Value == key4->luid.Value, "mismatch\n" );
+ ok( row->InterfaceLuid.Value == key4->luid2.Value, "mismatch\n" );
+ ok( row->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr == key4->prefix.s_addr, "mismatch\n" );
+ ok( row->DestinationPrefix.Prefix.Ipv4.sin_port == 0, "mismatch\n" );
+ ok( row->DestinationPrefix.PrefixLength == key4->prefix_len, "mismatch\n" );
+ ok( row->NextHop.Ipv4.sin_addr.s_addr == key4->next_hop.s_addr, "mismatch\n" );
+ ok( row->NextHop.Ipv4.sin_port == 0, "mismatch\n" );
+ ok( row->Age == dyn4->age, "mismatch\n" );
+ }
+ else
+ {
+ key6 = (struct nsi_ipv6_forward_key *)key_tbl + i;
+ dyn6 = (struct nsi_ipv6_forward_dynamic *)((BYTE *)dyn_tbl + i * dyn_size);
+
+ ok( row->InterfaceLuid.Value == key6->luid.Value, "mismatch\n" );
+ ok( row->InterfaceLuid.Value == key6->luid2.Value, "mismatch\n" );
+ ok( !memcmp( &row->DestinationPrefix.Prefix.Ipv6.sin6_addr, &key6->prefix, sizeof(key6->prefix) ),
+ "mismatch\n" );
+ ok( row->DestinationPrefix.Prefix.Ipv6.sin6_port == 0, "mismatch\n" );
+ ok( row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo == 0, "mismatch\n" );
+ ok( row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id == 0, "mismatch\n" );
+ ok( row->DestinationPrefix.PrefixLength == key6->prefix_len, "mismatch\n" );
+ ok( !memcmp( &row->NextHop.Ipv6.sin6_addr, &key6->next_hop, sizeof(key6->next_hop) ), "mismatch\n" );
+ ok( row->NextHop.Ipv6.sin6_port == 0, "mismatch\n" );
+ ok( row->NextHop.Ipv6.sin6_flowinfo == 0, "mismatch\n" );
+ ok( row->NextHop.Ipv6.sin6_scope_id == 0, "mismatch\n" );
+ ok( row->Age == dyn6->age, "mismatch\n" );
+ }
+
+ ok( row->InterfaceIndex == stat->if_index, "mismatch\n" );
+ ok( row->SitePrefixLength == rw->site_prefix_len, "mismatch\n" );
+ ok( row->ValidLifetime == rw->valid_lifetime, "mismatch\n" );
+ ok( row->PreferredLifetime == rw->preferred_lifetime, "mismatch\n" );
+
+ ok( row->Metric == rw->metric, "mismatch\n" );
+ ok( row->Protocol == rw->protocol, "mismatch\n" );
+ ok( row->Loopback == rw->loopback, "mismatch\n" );
+ ok( row->AutoconfigureAddress == rw->autoconf, "mismatch\n" );
+ ok( row->Publish == rw->publish, "mismatch\n" );
+ ok( row->Immortal == rw->immortal, "mismatch\n" );
+ ok( row->Origin == stat->origin, "mismatch\n" );
+
+ winetest_pop_context();
+ }
+
+ FreeMibTable( table );
+ NsiFreeTable( key_tbl, rw_tbl, dyn_tbl, stat_tbl );
+ winetest_pop_context();
+}
+
START_TEST( nsi )
{
test_nsi_api();
@@ -494,4 +609,6 @@ START_TEST( nsi )
test_ip_unicast( AF_INET );
test_ip_unicast( AF_INET6 );
+ test_ip_forward( AF_INET );
+ test_ip_forward( AF_INET6 );
}
diff --git a/dlls/nsiproxy.sys/ip.c b/dlls/nsiproxy.sys/ip.c
index 93fdefa24cc..dbd019c8442 100644
--- a/dlls/nsiproxy.sys/ip.c
+++ b/dlls/nsiproxy.sys/ip.c
@@ -25,6 +25,14 @@
#include <sys/socket.h>
#endif
+#ifdef HAVE_NET_ROUTE_H
+#include <net/route.h>
+#endif
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -45,6 +53,7 @@
#include "nldef.h"
#include "ifdef.h"
#include "netiodef.h"
+#include "wine/heap.h"
#include "wine/nsi.h"
#include "wine/debug.h"
@@ -221,6 +230,249 @@ static NTSTATUS ip_unicast_get_all_parameters( const void *key, DWORD key_size,
return status;
}
+struct ipv4_route_data
+{
+ NET_LUID luid;
+ DWORD if_index;
+ struct in_addr prefix;
+ DWORD prefix_len;
+ struct in_addr next_hop;
+ DWORD metric;
+ DWORD protocol;
+ BYTE loopback;
+};
+
+static void ipv4_forward_fill_entry( struct ipv4_route_data *entry, struct nsi_ipv4_forward_key *key,
+ struct nsi_ip_forward_rw *rw, struct nsi_ipv4_forward_dynamic *dyn,
+ struct nsi_ip_forward_static *stat )
+{
+ if (key)
+ {
+ key->unk = 0;
+ key->prefix.WS_s_addr = entry->prefix.s_addr;
+ key->prefix_len = entry->prefix_len;
+ memset( key->unk2, 0, sizeof(key->unk2) );
+ memset( key->unk3, 0, sizeof(key->unk3) );
+ key->luid = entry->luid;
+ key->luid2 = entry->luid;
+ key->next_hop.WS_s_addr = entry->next_hop.s_addr;
+ key->pad = 0;
+ }
+
+ if (rw)
+ {
+ rw->site_prefix_len = 0;
+ rw->valid_lifetime = ~0u;
+ rw->preferred_lifetime = ~0u;
+ rw->metric = entry->metric;
+ rw->protocol = entry->protocol;
+ rw->loopback = entry->loopback;
+ rw->autoconf = 1;
+ rw->publish = 0;
+ rw->immortal = 1;
+ memset( rw->unk, 0, sizeof(rw->unk) );
+ rw->unk2 = 0;
+ }
+
+ if (dyn)
+ {
+ memset( dyn, 0, sizeof(*dyn) );
+ }
+
+ if (stat)
+ {
+ stat->origin = NlroManual;
+ stat->if_index = entry->if_index;
+ }
+}
+
+static NTSTATUS ipv4_forward_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ DWORD num = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOL want_data = key_size || rw_size || dynamic_size || static_size;
+ struct ipv4_route_data entry;
+
+ TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+
+#ifdef __linux__
+ {
+ char buf[512], *ptr;
+ struct in_addr mask;
+ DWORD rtf_flags;
+ FILE *fp;
+
+ if (!(fp = fopen( "/proc/net/route", "r" ))) return STATUS_NOT_SUPPORTED;
+
+ /* skip header line */
+ fgets( buf, sizeof(buf), fp );
+ while ((ptr = fgets( buf, sizeof(buf), fp )))
+ {
+ while (!isspace( *ptr )) ptr++;
+ *ptr++ = '\0';
+
+ if (!convert_unix_name_to_luid( buf, &entry.luid )) continue;
+ if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
+
+ entry.prefix.s_addr = strtoul( ptr, &ptr, 16 );
+ entry.next_hop.s_addr = strtoul( ptr + 1, &ptr, 16 );
+ rtf_flags = strtoul( ptr + 1, &ptr, 16 );
+ strtoul( ptr + 1, &ptr, 16 ); /* refcount, skip */
+ strtoul( ptr + 1, &ptr, 16 ); /* use, skip */
+ entry.metric = strtoul( ptr + 1, &ptr, 16 );
+ mask.s_addr = strtoul( ptr + 1, &ptr, 16 );
+ entry.prefix_len = mask_v4_to_prefix( &mask );
+ entry.protocol = (rtf_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
+ entry.loopback = entry.protocol == MIB_IPPROTO_LOCAL && entry.prefix_len == 32;
+
+ if (num < *count)
+ {
+ ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
+ key_data = (BYTE *)key_data + key_size;
+ rw_data = (BYTE *)rw_data + rw_size;
+ dynamic_data = (BYTE *)dynamic_data + dynamic_size;
+ static_data = (BYTE *)static_data + static_size;
+ }
+ num++;
+ }
+ fclose( fp );
+ }
+#elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
+ {
+ int mib[6] = { CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0 };
+ size_t needed;
+ char *buf = NULL, *lim, *next, *addr_ptr;
+ struct rt_msghdr *rtm;
+
+ if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) < 0) return STATUS_NOT_SUPPORTED;
+
+ buf = heap_alloc( needed );
+ if (!buf) return STATUS_NO_MEMORY;
+
+ if (sysctl( mib, 6, buf, &needed, NULL, 0 ) < 0)
+ {
+ heap_free( buf );
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen)
+ {
+ int i;
+ sa_family_t dst_family = AF_UNSPEC;
+
+ rtm = (struct rt_msghdr *)next;
+
+ if (rtm->rtm_type != RTM_GET)
+ {
+ WARN( "Got unexpected message type 0x%x!\n", rtm->rtm_type );
+ continue;
+ }
+
+ /* Ignore gateway routes which are multicast */
+ if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST)) continue;
+
+ entry.if_index = rtm->rtm_index;
+ if (!convert_index_to_luid( entry.if_index, &entry.luid )) continue;
+ entry.protocol = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
+ entry.metric = rtm->rtm_rmx.rmx_hopcount;
+
+ addr_ptr = (char *)(rtm + 1);
+
+ for (i = 1; i; i <<= 1)
+ {
+ struct sockaddr *sa;
+ struct in_addr addr;
+
+ if (!(i & rtm->rtm_addrs)) continue;
+
+ sa = (struct sockaddr *)addr_ptr;
+ if (addr_ptr + sa->sa_len > next + rtm->rtm_msglen)
+ {
+ ERR( "struct sockaddr extends beyond the route message, %p > %p\n",
+ addr_ptr + sa->sa_len, next + rtm->rtm_msglen );
+ }
+
+ if (sa->sa_len) addr_ptr += (sa->sa_len + sizeof(int)-1) & ~(sizeof(int)-1);
+ else addr_ptr += sizeof(int);
+ /* Apple's netstat prints the netmask together with the destination
+ * and only looks at the destination's address family. The netmask's
+ * sa_family sometimes contains the non-existent value 0xff. */
+ switch (i == RTA_NETMASK ? dst_family : sa->sa_family)
+ {
+ case AF_INET:
+ {
+ /* Netmasks (and possibly other addresses) have only enough size
+ * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
+ * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
+ * byte of sin_addr). */
+ struct sockaddr_in sin = {0};
+ memcpy( &sin, sa, sa->sa_len );
+ addr = sin.sin_addr;
+ break;
+ }
+#ifdef AF_LINK
+ case AF_LINK:
+ if (i == RTA_GATEWAY && entry.protocol == MIB_IPPROTO_NETMGMT)
+ {
+ /* For direct route we may simply use dest addr as next hop */
+ C_ASSERT(RTA_DST < RTA_GATEWAY);
+ addr = entry.prefix;
+ break;
+ }
+ /* fallthrough */
+#endif
+ default:
+ WARN( "Received unsupported sockaddr family 0x%x\n", sa->sa_family );
+ addr.s_addr = 0;
+ }
+ switch (i)
+ {
+ case RTA_DST:
+ entry.prefix = addr;
+ dst_family = sa->sa_family;
+ break;
+ case RTA_GATEWAY: entry.next_hop = addr; break;
+ case RTA_NETMASK: entry.prefix_len = mask_v4_to_prefix( &addr ); break;
+ default:
+ WARN( "Unexpected address type 0x%x\n", i );
+ }
+ }
+
+ if (num < *count)
+ {
+ ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
+ key_data = (BYTE *)key_data + key_size;
+ rw_data = (BYTE *)rw_data + rw_size;
+ dynamic_data = (BYTE *)dynamic_data + dynamic_size;
+ static_data = (BYTE *)static_data + static_size;
+ }
+ num++;
+ }
+ HeapFree( GetProcessHeap (), 0, buf );
+ }
+#else
+ FIXME( "not implemented\n" );
+ return STATUS_NOT_IMPLEMENTED;
+#endif
+
+ if (!want_data || num <= *count) *count = num;
+ else status = STATUS_MORE_ENTRIES;
+
+ return status;
+}
+
+static NTSTATUS ipv6_forward_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ FIXME( "not implemented\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
static struct module_table ipv4_tables[] =
{
{
@@ -232,6 +484,14 @@ static struct module_table ipv4_tables[] =
ip_unicast_enumerate_all,
ip_unicast_get_all_parameters,
},
+ {
+ NSI_IP_FORWARD_TABLE,
+ {
+ sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ip_forward_rw),
+ sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ip_forward_static)
+ },
+ ipv4_forward_enumerate_all,
+ },
{
~0u
}
@@ -254,6 +514,14 @@ static struct module_table ipv6_tables[] =
ip_unicast_enumerate_all,
ip_unicast_get_all_parameters,
},
+ {
+ NSI_IP_FORWARD_TABLE,
+ {
+ sizeof(struct nsi_ipv6_forward_key), sizeof(struct nsi_ip_forward_rw),
+ sizeof(struct nsi_ipv6_forward_dynamic), sizeof(struct nsi_ip_forward_static)
+ },
+ ipv6_forward_enumerate_all,
+ },
{
~0u
}
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h
index 0f6e7b05c59..44409ae159e 100644
--- a/dlls/nsiproxy.sys/nsiproxy_private.h
+++ b/dlls/nsiproxy.sys/nsiproxy_private.h
@@ -25,6 +25,44 @@ NTSTATUS nsi_get_parameter_ex( struct nsi_get_parameter_ex *params ) DECLSPEC_HI
BOOL convert_luid_to_unix_name( const NET_LUID *luid, const char **unix_name ) DECLSPEC_HIDDEN;
BOOL convert_unix_name_to_luid( const char *unix_name, NET_LUID *luid ) DECLSPEC_HIDDEN;
+static inline BOOL convert_luid_to_index( const NET_LUID *luid, DWORD *index )
+{
+ struct nsi_get_parameter_ex params;
+ params.unknown[0] = 0;
+ params.unknown[1] = 0;
+ params.first_arg = 1;
+ params.unknown2 = 0;
+ params.module = &NPI_MS_NDIS_MODULEID;
+ params.table = NSI_NDIS_IFINFO_TABLE;
+ params.key = luid;
+ params.key_size = sizeof(*luid);
+ params.param_type = NSI_PARAM_TYPE_STATIC;
+ params.data = index;
+ params.data_size = sizeof(*index);
+ params.data_offset = FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index);
+
+ return !nsi_get_parameter_ex( ¶ms );
+}
+
+static inline BOOL convert_index_to_luid( DWORD index, NET_LUID *luid )
+{
+ struct nsi_get_parameter_ex params;
+ params.unknown[0] = 0;
+ params.unknown[1] = 0;
+ params.first_arg = 1;
+ params.unknown2 = 0;
+ params.module = &NPI_MS_NDIS_MODULEID;
+ params.table = NSI_NDIS_INDEX_LUID_TABLE;
+ params.key = &index;
+ params.key_size = sizeof(index);
+ params.param_type = NSI_PARAM_TYPE_STATIC;
+ params.data = luid;
+ params.data_size = sizeof(*luid);
+ params.data_offset = 0;
+
+ return !nsi_get_parameter_ex( ¶ms );
+}
+
struct module_table
{
DWORD table;
diff --git a/include/netioapi.h b/include/netioapi.h
index 4735620dedb..44d877ae3c3 100644
--- a/include/netioapi.h
+++ b/include/netioapi.h
@@ -254,6 +254,8 @@ DWORD WINAPI GetIfEntry2(MIB_IF_ROW2*);
DWORD WINAPI GetIfEntry2Ex(MIB_IF_TABLE_LEVEL,MIB_IF_ROW2*);
DWORD WINAPI GetIfTable2(MIB_IF_TABLE2**);
DWORD WINAPI GetIfTable2Ex(MIB_IF_TABLE_LEVEL,MIB_IF_TABLE2**);
+DWORD WINAPI GetIpForwardEntry2(MIB_IPFORWARD_ROW2*);
+DWORD WINAPI GetIpForwardTable2(ADDRESS_FAMILY,MIB_IPFORWARD_TABLE2**);
DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY,MIB_IPINTERFACE_TABLE**);
DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW*);
DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY,MIB_UNICASTIPADDRESS_TABLE**);
diff --git a/include/wine/nsi.h b/include/wine/nsi.h
index bba5be11e50..dd18c7c7511 100644
--- a/include/wine/nsi.h
+++ b/include/wine/nsi.h
@@ -98,6 +98,7 @@ struct nsi_ndis_ifinfo_static
/* Undocumented NSI IP tables */
#define NSI_IP_UNICAST_TABLE 10
+#define NSI_IP_FORWARD_TABLE 16
struct nsi_ipv4_unicast_key
{
@@ -133,6 +134,67 @@ struct nsi_ip_unicast_static
ULONG64 creation_time;
};
+struct nsi_ipv4_forward_key
+{
+ DWORD unk;
+ IN_ADDR prefix;
+ BYTE prefix_len;
+ BYTE unk2[3];
+ DWORD unk3[3];
+ NET_LUID luid;
+ NET_LUID luid2;
+ IN_ADDR next_hop;
+ DWORD pad;
+};
+
+struct nsi_ipv6_forward_key
+{
+ DWORD unk;
+ IN6_ADDR prefix;
+ BYTE prefix_len;
+ BYTE unk2[3];
+ DWORD unk3[3];
+ DWORD pad;
+ NET_LUID luid;
+ NET_LUID luid2;
+ IN6_ADDR next_hop;
+};
+
+struct nsi_ip_forward_rw
+{
+ DWORD site_prefix_len;
+ DWORD valid_lifetime;
+ DWORD preferred_lifetime;
+ DWORD metric;
+ DWORD protocol;
+ BYTE loopback;
+ BYTE autoconf;
+ BYTE publish;
+ BYTE immortal;
+ BYTE unk[4];
+ DWORD unk2;
+};
+
+struct nsi_ipv4_forward_dynamic
+{
+ DWORD age;
+ DWORD unk[3];
+ IN_ADDR addr2; /* often a repeat of prefix */
+};
+
+struct nsi_ipv6_forward_dynamic
+{
+ DWORD age;
+ DWORD unk[3];
+ IN6_ADDR addr2; /* often a repeat of prefix */
+};
+
+struct nsi_ip_forward_static
+{
+ DWORD origin;
+ DWORD if_index;
+};
+
/* Wine specific ioctl interface */
#define IOCTL_NSIPROXY_WINE_ENUMERATE_ALL CTL_CODE(FILE_DEVICE_NETWORK, 0x400, METHOD_BUFFERED, 0)
--
2.23.0
1
0
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 3 +++
include/mftransform.idl | 3 +++
2 files changed, 6 insertions(+)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index bcad90c29da..7fd713261fc 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -1687,6 +1687,7 @@ const char *debugstr_attr(const GUID *guid)
X(MF_BYTESTREAM_DLNA_PROFILE_ID),
X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ROLE),
X(MF_MT_MAJOR_TYPE),
+ X(MF_SA_REQUIRED_SAMPLE_COUNT_PROGRESSIVE),
X(MF_MT_IN_BAND_PARAMETER_SET),
X(MF_EVENT_SOURCE_CHARACTERISTICS),
X(MF_EVENT_SOURCE_CHARACTERISTICS_OLD),
@@ -1717,6 +1718,7 @@ const char *debugstr_attr(const GUID *guid)
X(MF_EVENT_STREAM_METADATA_KEYDATA),
X(MF_READER_WRITER_D3D_MANAGER),
X(MFSampleExtension_3DVideo),
+ X(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE),
X(MF_MT_H264_USAGE),
X(MF_MEDIA_ENGINE_EME_CALLBACK),
X(MF_EVENT_SOURCE_FAKE_START),
@@ -1775,6 +1777,7 @@ const char *debugstr_attr(const GUID *guid)
X(MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT),
X(MFSampleExtension_DecodeTimestamp),
X(MF_MEDIA_ENGINE_COMPATIBILITY_MODE),
+ X(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT),
X(MF_MT_VIDEO_H264_NO_FMOASO),
X(MF_MT_AVG_BIT_ERROR_RATE),
X(MF_MT_VIDEO_PRIMARIES),
diff --git a/include/mftransform.idl b/include/mftransform.idl
index e49c7200185..0dd83a70f7d 100644
--- a/include/mftransform.idl
+++ b/include/mftransform.idl
@@ -208,6 +208,9 @@ cpp_quote("EXTERN_GUID(MF_SA_D3D11_SHARED, 0x7b8f32c3, 0x6d96, 0x4
cpp_quote("EXTERN_GUID(MF_SA_D3D11_SHARED_WITHOUT_MUTEX, 0x39dbd44d, 0x2e44, 0x4931, 0xa4, 0xc8, 0x35, 0x2d, 0x3d, 0xc4, 0x21, 0x15);")
cpp_quote("EXTERN_GUID(MF_SA_D3D11_USAGE, 0xe85fe442, 0x2ca3, 0x486e, 0xa9, 0xc7, 0x10, 0x9d, 0xda, 0x60, 0x98, 0x80);")
cpp_quote("EXTERN_GUID(MF_SA_REQUIRED_SAMPLE_COUNT, 0x18802c61, 0x324b, 0x4952, 0xab, 0xd0, 0x17, 0x6f, 0xf5, 0xc6, 0x96, 0xff);")
+cpp_quote("EXTERN_GUID(MF_SA_REQUIRED_SAMPLE_COUNT_PROGRESSIVE, 0xb172d58e, 0xfa77, 0x4e48, 0x8d, 0x2a, 0x1d, 0xf2, 0xd8, 0x50, 0xea, 0xc2);")
+cpp_quote("EXTERN_GUID(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, 0x851745d5, 0xc3d6, 0x476d, 0x95, 0x27, 0x49, 0x8e, 0xf2, 0xd1, 0x0d, 0x18);")
+cpp_quote("EXTERN_GUID(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE, 0x0f5523a5, 0x1cb2, 0x47c5, 0xa5, 0x50, 0x2e, 0xeb, 0x84, 0xb4, 0xd1, 0x4a);")
cpp_quote("EXTERN_GUID(MF_TRANSFORM_ASYNC, 0xf81a699a, 0x649a, 0x497d, 0x8c, 0x73, 0x29, 0xf8, 0xfe, 0xd6, 0xad, 0x7a);")
cpp_quote("EXTERN_GUID(MF_TRANSFORM_ASYNC_UNLOCK, 0xe5666d6b, 0x3422, 0x4eb6, 0xa4, 0x21, 0xda, 0x7d, 0xb1, 0xf8, 0xe2, 0x07);")
cpp_quote("EXTERN_GUID(MF_TRANSFORM_CATEGORY_Attribute, 0xceabba49, 0x506d, 0x4757, 0xa6, 0xff, 0x66, 0xc1, 0x84, 0x98, 0x7e, 0x4e);")
--
2.30.2
2
1