Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/nsi/tests/nsi.c | 42 ++++++++++ dlls/nsiproxy.sys/ip.c | 121 +++++++++++++++++++++++++++ dlls/nsiproxy.sys/nsiproxy_private.h | 29 +++++++ include/wine/nsi.h | 17 ++++ 4 files changed, 209 insertions(+)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c index feed72a1626..598e7124afd 100644 --- a/dlls/nsi/tests/nsi.c +++ b/dlls/nsi/tests/nsi.c @@ -411,6 +411,46 @@ static void test_ndis_index_luid( void ) ok( err == ERROR_FILE_NOT_FOUND, "got %d\n", err ); }
+static void test_ip_cmpt( int family ) +{ + DWORD rw_sizes[] = { FIELD_OFFSET(struct nsi_ip_cmpt_rw, unk2), sizeof(struct nsi_ip_cmpt_rw) }; + const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID; + struct nsi_ip_cmpt_dynamic dyn; + struct nsi_ip_cmpt_rw rw; + MIB_IPSTATS table; + DWORD err, key, i; + + winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" ); + + /* key = 0 also seems to work, but NsiAllocateAndGetTable returns + a single table with key == 1. Presumably this is the compartment id */ + key = 1; + for (i = 0; i < ARRAY_SIZE(rw_sizes); i++) + { + err = NsiGetAllParameters( 1, mod, 2, &key, sizeof(key), &rw, rw_sizes[i], &dyn, sizeof(dyn), NULL, 0 ); + if (!err) break; + } + ok( !err, "got %x\n", err ); + + err = GetIpStatisticsEx( &table, family ); + ok( !err, "got %d\n", err ); + if (err) goto err; + +todo_wine_if(family == AF_INET6 && table.dwForwarding - 1 != rw.not_forwarding) + ok( table.dwForwarding - 1 == rw.not_forwarding, "%x vs %x\n", table.dwForwarding, rw.not_forwarding ); +todo_wine_if(family == AF_INET6 && table.dwDefaultTTL != rw.default_ttl) + ok( table.dwDefaultTTL == rw.default_ttl, "%x vs %x\n", table.dwDefaultTTL, rw.default_ttl ); + ok( table.dwNumIf == dyn.num_ifs, "%x vs %x\n", table.dwNumIf, dyn.num_ifs ); +todo_wine_if(table.dwNumAddr != dyn.num_addrs) + ok( table.dwNumAddr == dyn.num_addrs, "%x vs %x\n", table.dwNumAddr, dyn.num_addrs ); +todo_wine_if(family == AF_INET6 && table.dwNumRoutes != dyn.num_routes) + ok( table.dwNumRoutes == dyn.num_routes, "%x vs %x\n", table.dwNumRoutes, dyn.num_routes ); + +err: + winetest_pop_context(); +} + + static void test_ip_ipstats( int family ) { const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID; @@ -725,6 +765,8 @@ START_TEST( nsi ) test_ndis_ifinfo(); test_ndis_index_luid();
+ test_ip_cmpt( AF_INET ); + test_ip_cmpt( AF_INET6 ); test_ip_ipstats( AF_INET ); test_ip_ipstats( AF_INET6 ); test_ip_unicast( AF_INET ); diff --git a/dlls/nsiproxy.sys/ip.c b/dlls/nsiproxy.sys/ip.c index 7d9af08c711..64a223ab3fb 100644 --- a/dlls/nsiproxy.sys/ip.c +++ b/dlls/nsiproxy.sys/ip.c @@ -120,6 +120,109 @@ static ULONG64 get_boot_time( void ) return ti.BootTime.QuadPart; }
+#if __linux__ +static NTSTATUS read_sysctl_int( const char *file, int *val ) +{ + FILE *fp; + char buf[128], *endptr = buf; + + fp = fopen( file, "r" ); + if (!fp) return STATUS_NOT_SUPPORTED; + + if (fgets( buf, sizeof(buf), fp )) + *val = strtol( buf, &endptr, 10 ); + + fclose( fp ); + return (endptr == buf) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS; +} +#endif + +static NTSTATUS ip_cmpt_get_all_parameters( DWORD fam, const DWORD *key, DWORD key_size, + struct nsi_ip_cmpt_rw *rw_data, DWORD rw_size, + struct nsi_ip_cmpt_dynamic *dynamic_data, DWORD dynamic_size, + void *static_data, DWORD static_size ) +{ + const NPI_MODULEID *ip_mod = (fam == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID; + struct nsi_ip_cmpt_rw rw; + struct nsi_ip_cmpt_dynamic dyn; + DWORD count; + + memset( &rw, 0, sizeof(rw) ); + memset( &dyn, 0, sizeof(dyn) ); + + if (*key != 1) return STATUS_NOT_SUPPORTED; + +#if __linux__ + { + const char *fwd = (fam == AF_INET) ? "/proc/sys/net/ipv4/conf/default/forwarding" : + "/proc/sys/net/ipv6/conf/default/forwarding"; + const char *ttl = (fam == AF_INET) ? "/proc/sys/net/ipv4/ip_default_ttl" : + "/proc/sys/net/ipv6/conf/default/hop_limit"; + int value; + + if (!read_sysctl_int( fwd, &value )) rw.not_forwarding = !value; + if (!read_sysctl_int( ttl, &value )) rw.default_ttl = value; + } +#elif defined(HAVE_SYS_SYSCTL_H) + { + int fwd_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING }; + int fwd_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING }; + int ttl_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; + int ttl_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; + int value; + size_t needed; + + needed = sizeof(value); + if (!sysctl( (fam == AF_INET) ? fwd_4 : fwd_6, ARRAY_SIZE(fwd_4), &value, &needed, NULL, 0 )) + rw.not_forwarding = value; + + needed = sizeof(value); + if (!sysctl( (fam == AF_INET) ? ttl_4 : ttl_6, ARRAY_SIZE(ttl_4), &value, &needed, NULL, 0 )) + rw.default_ttl = value; + } +#else + FIXME( "forwarding and default ttl not implemented\n" ); +#endif + + count = 0; + if (!nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, &count )) + dyn.num_ifs = count; + + count = 0; + if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_FORWARD_TABLE, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, &count )) + dyn.num_routes = count; + + count = 0; + if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_UNICAST_TABLE, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, &count )) + dyn.num_addrs = count; + + if (rw_data) *rw_data = rw; + if (dynamic_data) *dynamic_data = dyn; + + return STATUS_SUCCESS; +} + +static NTSTATUS ipv4_cmpt_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size, + void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size ) +{ + TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size, + static_data, static_size ); + return ip_cmpt_get_all_parameters( AF_INET, key, key_size, rw_data, rw_size, + dynamic_data, dynamic_size, static_data, static_size ); +} + +static NTSTATUS ipv6_cmpt_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size, + void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size ) +{ + TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size, + static_data, static_size ); + return ip_cmpt_get_all_parameters( AF_INET6, key, key_size, rw_data, rw_size, + dynamic_data, dynamic_size, static_data, static_size ); +} + static NTSTATUS ipv4_ipstats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size, void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size ) { @@ -869,6 +972,15 @@ static NTSTATUS ipv6_forward_enumerate_all( void *key_data, DWORD key_size, void
static struct module_table ipv4_tables[] = { + { + NSI_IP_COMPARTMENT_TABLE, + { + sizeof(DWORD), sizeof(struct nsi_ip_cmpt_rw), + sizeof(struct nsi_ip_cmpt_dynamic), 0 + }, + NULL, + ipv4_cmpt_get_all_parameters, + }, { NSI_IP_IPSTATS_TABLE, { @@ -916,6 +1028,15 @@ const struct module ipv4_module =
static struct module_table ipv6_tables[] = { + { + NSI_IP_COMPARTMENT_TABLE, + { + sizeof(DWORD), sizeof(struct nsi_ip_cmpt_rw), + sizeof(struct nsi_ip_cmpt_dynamic), 0 + }, + NULL, + ipv6_cmpt_get_all_parameters, + }, { NSI_IP_IPSTATS_TABLE, { diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h index 44409ae159e..24f40e184a4 100644 --- a/dlls/nsiproxy.sys/nsiproxy_private.h +++ b/dlls/nsiproxy.sys/nsiproxy_private.h @@ -22,6 +22,35 @@ NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params ) DECLSPEC_HI NTSTATUS nsi_get_all_parameters_ex( struct nsi_get_all_parameters_ex *params ) DECLSPEC_HIDDEN; NTSTATUS nsi_get_parameter_ex( struct nsi_get_parameter_ex *params ) DECLSPEC_HIDDEN;
+static inline NTSTATUS nsi_enumerate_all( DWORD unk, DWORD unk2, const NPI_MODULEID *module, DWORD table, + 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 *count ) +{ + struct nsi_enumerate_all_ex params; + NTSTATUS status; + + params.unknown[0] = 0; + params.unknown[1] = 0; + params.module = module; + params.table = table; + params.first_arg = unk; + params.second_arg = unk2; + params.key_data = key_data; + params.key_size = key_size; + params.rw_data = rw_data; + params.rw_size = rw_size; + params.dynamic_data = dynamic_data; + params.dynamic_size = dynamic_size; + params.static_data = static_data; + params.static_size = static_size; + params.count = *count; + + status = nsi_enumerate_all_ex( ¶ms ); + *count = params.count; + return status; +} + 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;
diff --git a/include/wine/nsi.h b/include/wine/nsi.h index f3edef9f3fd..6a90f5f1203 100644 --- a/include/wine/nsi.h +++ b/include/wine/nsi.h @@ -97,11 +97,28 @@ struct nsi_ndis_ifinfo_static };
/* Undocumented NSI IP tables */ +#define NSI_IP_COMPARTMENT_TABLE 2 #define NSI_IP_IPSTATS_TABLE 6 #define NSI_IP_UNICAST_TABLE 10 #define NSI_IP_NEIGHBOUR_TABLE 11 #define NSI_IP_FORWARD_TABLE 16
+struct nsi_ip_cmpt_rw +{ + DWORD not_forwarding; + DWORD unk; + DWORD default_ttl; + DWORD unk2; +}; + +struct nsi_ip_cmpt_dynamic +{ + DWORD num_ifs; + DWORD num_routes; + DWORD unk; + DWORD num_addrs; +}; + struct nsi_ip_ipstats_dynamic { DWORD unk[4];