Commit 2f3fc13c authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

nsiproxy: Implement IPv4 ipstats get_all_parameters.

parent 1e0f7d64
......@@ -411,6 +411,54 @@ static void test_ndis_index_luid( void )
ok( err == ERROR_FILE_NOT_FOUND, "got %d\n", err );
}
static void test_ip_ipstats( int family )
{
const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
struct nsi_ip_ipstats_dynamic dyn, dyn2;
struct nsi_ip_ipstats_static stat;
MIB_IPSTATS table;
DWORD err;
winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
/* The table appears to consist of a single object without a key. The rw data does exist but
isn't part of GetIpStatisticsEx() and isn't yet tested */
err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0, &dyn, sizeof(dyn), &stat, sizeof(stat) );
todo_wine_if( family == AF_INET6 )
ok( !err, "got %x\n", err );
if (err) goto err;
err = GetIpStatisticsEx( &table, family );
ok( !err, "got %d\n", err );
err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0, &dyn2, sizeof(dyn2), NULL, 0 );
ok( !err, "got %x\n", err );
/* dwForwarding and dwDefaultTTL come from the compartment table */
ok( bounded( table.dwInReceives, dyn.in_recv, dyn2.in_recv ), "mismatch\n" );
ok( bounded( table.dwInHdrErrors, dyn.in_hdr_errs, dyn2.in_hdr_errs ), "mismatch\n" );
ok( bounded( table.dwInAddrErrors, dyn.in_addr_errs, dyn2.in_addr_errs ), "mismatch\n" );
ok( bounded( table.dwForwDatagrams, dyn.fwd_dgrams, dyn2.fwd_dgrams ), "mismatch\n" );
ok( bounded( table.dwInUnknownProtos, dyn.in_unk_protos, dyn2.in_unk_protos ), "mismatch\n" );
ok( bounded( table.dwInDiscards, dyn.in_discards, dyn2.in_discards ), "mismatch\n" );
ok( bounded( table.dwInDelivers, dyn.in_delivers, dyn2.in_delivers ), "mismatch\n" );
ok( bounded( table.dwOutRequests, dyn.out_reqs, dyn2.out_reqs ), "mismatch\n" );
ok( bounded( table.dwRoutingDiscards, dyn.routing_discards, dyn2.routing_discards ), "mismatch\n" );
ok( bounded( table.dwOutDiscards, dyn.out_discards, dyn2.out_discards ), "mismatch\n" );
ok( bounded( table.dwOutNoRoutes, dyn.out_no_routes, dyn2.out_no_routes ), "mismatch\n" );
ok( table.dwReasmTimeout == stat.reasm_timeout, "mismatch\n" );
ok( bounded( table.dwReasmReqds, dyn.reasm_reqds, dyn2.reasm_reqds ), "mismatch\n" );
ok( bounded( table.dwReasmOks, dyn.reasm_oks, dyn2.reasm_oks ), "mismatch\n" );
ok( bounded( table.dwReasmFails, dyn.reasm_fails, dyn2.reasm_fails ), "mismatch\n" );
ok( bounded( table.dwFragOks, dyn.frag_oks, dyn2.frag_oks ), "mismatch\n" );
ok( bounded( table.dwFragFails, dyn.frag_fails, dyn2.frag_fails ), "mismatch\n" );
ok( bounded( table.dwFragCreates, dyn.frag_creates, dyn2.frag_creates ), "mismatch\n" );
/* dwNumIf, dwNumAddr and dwNumRoutes come from the compartment table */
err:
winetest_pop_context();
}
static void test_ip_unicast( int family )
{
DWORD rw_sizes[] = { FIELD_OFFSET(struct nsi_ip_unicast_rw, unk[0]), FIELD_OFFSET(struct nsi_ip_unicast_rw, unk[1]),
......@@ -678,6 +726,8 @@ START_TEST( nsi )
test_ndis_ifinfo();
test_ndis_index_luid();
test_ip_ipstats( AF_INET );
test_ip_ipstats( AF_INET6 );
test_ip_unicast( AF_INET );
test_ip_unicast( AF_INET6 );
test_ip_neighbour( AF_INET );
......
......@@ -120,6 +120,112 @@ static ULONG64 get_boot_time( void )
return ti.BootTime.QuadPart;
}
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 )
{
struct nsi_ip_ipstats_dynamic dyn;
struct nsi_ip_ipstats_static stat;
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 );
memset( &dyn, 0, sizeof(dyn) );
memset( &stat, 0, sizeof(stat) );
#ifdef __linux__
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
static const char hdr[] = "Ip:";
char buf[512], *ptr;
FILE *fp;
if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
while ((ptr = fgets( buf, sizeof(buf), fp )))
{
if (_strnicmp( buf, hdr, sizeof(hdr) - 1 )) continue;
/* last line was a header, get another */
if (!(ptr = fgets( buf, sizeof(buf), fp ))) break;
if (!_strnicmp( buf, hdr, sizeof(hdr) - 1 ))
{
DWORD in_recv, in_hdr_errs, fwd_dgrams, in_delivers, out_reqs;
ptr += sizeof(hdr);
sscanf( ptr, "%*u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
&in_recv,
&in_hdr_errs,
&dyn.in_addr_errs,
&fwd_dgrams,
&dyn.in_unk_protos,
&dyn.in_discards,
&in_delivers,
&out_reqs,
&dyn.out_discards,
&dyn.out_no_routes,
&stat.reasm_timeout,
&dyn.reasm_reqds,
&dyn.reasm_oks,
&dyn.reasm_fails,
&dyn.frag_oks,
&dyn.frag_fails,
&dyn.frag_creates );
/* no routingDiscards */
dyn.in_recv = in_recv;
dyn.in_hdr_errs = in_hdr_errs;
dyn.fwd_dgrams = fwd_dgrams;
dyn.in_delivers = in_delivers;
dyn.out_reqs = out_reqs;
if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
status = STATUS_SUCCESS;
break;
}
}
fclose( fp );
return status;
}
#elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
{
int mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS };
#if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
struct ipstat ip_stat;
#elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
struct ip_stats ip_stat;
#endif
size_t needed;
needed = sizeof(ip_stat);
if (sysctl( mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
dyn.in_recv = ip_stat.ips_total;
dyn.in_hdr_errs = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen +
ip_stat.ips_badvers + ip_stat.ips_badoptions;
/* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
dyn.in_addr_errs = ip_stat.ips_cantforward + ip_stat.ips_badaddr + ip_stat.ips_notmember;
dyn.fwd_dgrams = ip_stat.ips_forward;
dyn.in_unk_protos = ip_stat.ips_noproto;
dyn.in_discards = ip_stat.ips_fragdropped;
dyn.in_delivers = ip_stat.ips_delivered;
dyn.out_reqs = ip_stat.ips_localout;
dyn.out_discards = ip_stat.ips_odropped;
dyn.out_no_routes = ip_stat.ips_noroute;
stat.reasm_timeout = ip_stat.ips_fragtimeout;
dyn.reasm_reqds = ip_stat.ips_fragments;
dyn.reasm_oks = ip_stat.ips_reassembled;
dyn.reasm_fails = ip_stat.ips_fragments - ip_stat.ips_reassembled;
dyn.frag_oks = ip_stat.ips_fragmented;
dyn.frag_fails = ip_stat.ips_cantfrag;
dyn.frag_creates = ip_stat.ips_ofragments;
if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
return STATUS_SUCCESS;
}
#else
FIXME( "not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
#endif
}
static void unicast_fill_entry( struct ifaddrs *entry, void *key, struct nsi_ip_unicast_rw *rw,
struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
{
......@@ -688,6 +794,15 @@ static NTSTATUS ipv6_forward_enumerate_all( void *key_data, DWORD key_size, void
static struct module_table ipv4_tables[] =
{
{
NSI_IP_IPSTATS_TABLE,
{
0, 0,
sizeof(struct nsi_ip_ipstats_dynamic), sizeof(struct nsi_ip_ipstats_static)
},
NULL,
ipv4_ipstats_get_all_parameters,
},
{
NSI_IP_UNICAST_TABLE,
{
sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ip_unicast_rw),
......
......@@ -97,10 +97,45 @@ struct nsi_ndis_ifinfo_static
};
/* Undocumented NSI IP tables */
#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_ipstats_dynamic
{
DWORD unk[4];
ULONGLONG in_recv;
ULONGLONG in_octets;
ULONGLONG fwd_dgrams;
ULONGLONG in_delivers;
ULONGLONG out_reqs;
ULONGLONG unk2;
ULONGLONG unk3;
ULONGLONG out_octets;
ULONGLONG unk4[6];
ULONGLONG in_hdr_errs;
DWORD in_addr_errs;
DWORD in_unk_protos;
DWORD unk5;
DWORD reasm_reqds;
DWORD reasm_oks;
DWORD reasm_fails;
DWORD in_discards;
DWORD out_no_routes;
DWORD out_discards;
DWORD routing_discards;
DWORD frag_oks;
DWORD frag_fails;
DWORD frag_creates;
DWORD unk6[7];
};
struct nsi_ip_ipstats_static
{
DWORD reasm_timeout;
};
struct nsi_ipv4_unicast_key
{
NET_LUID luid;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment