nsiproxy: Implement IPv4 icmpstats get_all_parameters.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-08-12 10:38:14 +01:00 committed by Alexandre Julliard
parent 2586bbb212
commit 23ee1ebea6
3 changed files with 196 additions and 0 deletions

View File

@ -446,6 +446,48 @@ err:
winetest_pop_context();
}
static void test_ip_icmpstats( int family )
{
const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
struct nsi_ip_icmpstats_dynamic nsi_stats, nsi_stats2;
MIB_ICMP_EX table;
DWORD err, i;
winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
err = NsiGetAllParameters( 1, mod, NSI_IP_ICMPSTATS_TABLE, NULL, 0, NULL, 0, &nsi_stats, sizeof(nsi_stats), NULL, 0 );
todo_wine_if( family == AF_INET6)
ok( !err, "got %d\n", err );
if (err) goto err;
err = GetIcmpStatisticsEx( &table, family );
ok( !err, "got %d\n", err );
if (err) goto err;
err = NsiGetAllParameters( 1, mod, NSI_IP_ICMPSTATS_TABLE, NULL, 0, NULL, 0, &nsi_stats2, sizeof(nsi_stats2), NULL, 0 );
ok( !err, "got %d\n", err );
ok( bounded( table.icmpInStats.dwMsgs, nsi_stats.in_msgs, nsi_stats2.in_msgs ),
"%d vs [%d %d]\n", table.icmpInStats.dwMsgs, nsi_stats.in_msgs, nsi_stats2.in_msgs );
ok( bounded( table.icmpInStats.dwErrors, nsi_stats.in_errors, nsi_stats2.in_errors ),
"%d vs [%d %d]\n", table.icmpInStats.dwErrors, nsi_stats.in_errors, nsi_stats2.in_errors );
ok( bounded( table.icmpOutStats.dwMsgs, nsi_stats.out_msgs, nsi_stats2.out_msgs ),
"%d vs [%d %d]\n", table.icmpOutStats.dwMsgs, nsi_stats.out_msgs, nsi_stats2.out_msgs );
ok( bounded( table.icmpOutStats.dwErrors, nsi_stats.out_errors, nsi_stats2.out_errors ),
"%d vs [%d %d]\n", table.icmpOutStats.dwErrors, nsi_stats.out_errors, nsi_stats2.out_errors );
for (i = 0; i < ARRAY_SIZE(nsi_stats.in_type_counts); i++)
{
winetest_push_context( "%d", i );
ok( bounded( table.icmpInStats.rgdwTypeCount[i], nsi_stats.in_type_counts[i], nsi_stats2.in_type_counts[i] ),
"%d vs [%d %d]\n", table.icmpInStats.rgdwTypeCount[i], nsi_stats.in_type_counts[i], nsi_stats2.in_type_counts[i] );
ok( bounded( table.icmpOutStats.rgdwTypeCount[i], nsi_stats.out_type_counts[i], nsi_stats2.out_type_counts[i] ),
"%d vs [%d %d]\n", table.icmpOutStats.rgdwTypeCount[i], nsi_stats.out_type_counts[i], nsi_stats2.out_type_counts[i] );
winetest_pop_context();
}
err:
winetest_pop_context();
}
static void test_ip_ipstats( int family )
{
@ -763,6 +805,8 @@ START_TEST( nsi )
test_ip_cmpt( AF_INET );
test_ip_cmpt( AF_INET6 );
test_ip_icmpstats( AF_INET );
test_ip_icmpstats( AF_INET6 );
test_ip_ipstats( AF_INET );
test_ip_ipstats( AF_INET6 );
test_ip_unicast( AF_INET );

View File

@ -41,10 +41,26 @@
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#ifdef HAVE_NETINET_IP_ICMP_H
#include <netinet/ip_icmp.h>
#endif
#ifdef HAVE_NETINET_IP_VAR_H
#include <netinet/ip_var.h>
#endif
#ifdef HAVE_NETINET_ICMP_VAR_H
#include <netinet/icmp_var.h>
#endif
#ifdef HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
@ -76,6 +92,7 @@
#include "ws2ipdef.h"
#include "nldef.h"
#include "ifdef.h"
#include "ipmib.h"
#include "netiodef.h"
#include "wine/heap.h"
#include "wine/nsi.h"
@ -223,6 +240,121 @@ static NTSTATUS ipv6_cmpt_get_all_parameters( const void *key, DWORD key_size, v
dynamic_data, dynamic_size, static_data, static_size );
}
static NTSTATUS ipv4_icmpstats_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_icmpstats_dynamic dyn;
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) );
#ifdef __linux__
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
static const char hdr[] = "Icmp:";
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 ))
{
ptr += sizeof(hdr);
sscanf( ptr, "%u %u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
&dyn.in_msgs,
&dyn.in_errors,
&dyn.in_type_counts[ICMP4_DST_UNREACH],
&dyn.in_type_counts[ICMP4_TIME_EXCEEDED],
&dyn.in_type_counts[ICMP4_PARAM_PROB],
&dyn.in_type_counts[ICMP4_SOURCE_QUENCH],
&dyn.in_type_counts[ICMP4_REDIRECT],
&dyn.in_type_counts[ICMP4_ECHO_REQUEST],
&dyn.in_type_counts[ICMP4_ECHO_REPLY],
&dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST],
&dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY],
&dyn.in_type_counts[ICMP4_MASK_REQUEST],
&dyn.in_type_counts[ICMP4_MASK_REPLY],
&dyn.out_msgs,
&dyn.out_errors,
&dyn.out_type_counts[ICMP4_DST_UNREACH],
&dyn.out_type_counts[ICMP4_TIME_EXCEEDED],
&dyn.out_type_counts[ICMP4_PARAM_PROB],
&dyn.out_type_counts[ICMP4_SOURCE_QUENCH],
&dyn.out_type_counts[ICMP4_REDIRECT],
&dyn.out_type_counts[ICMP4_ECHO_REQUEST],
&dyn.out_type_counts[ICMP4_ECHO_REPLY],
&dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST],
&dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY],
&dyn.out_type_counts[ICMP4_MASK_REQUEST],
&dyn.out_type_counts[ICMP4_MASK_REPLY] );
status = STATUS_SUCCESS;
if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
break;
}
}
fclose( fp );
return status;
}
#elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
{
int mib[] = { CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS };
struct icmpstat icmp_stat;
size_t needed = sizeof(icmp_stat);
int i;
if (sysctl( mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
dyn.in_msgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
for (i = 0; i <= ICMP_MAXTYPE; i++)
dyn.in_msgs += icmp_stat.icps_inhist[i];
dyn.in_errors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
dyn.in_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_inhist[ICMP_UNREACH];
dyn.in_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_inhist[ICMP_TIMXCEED];
dyn.in_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_inhist[ICMP_PARAMPROB];
dyn.in_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
dyn.in_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_inhist[ICMP_REDIRECT];
dyn.in_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_inhist[ICMP_ECHO];
dyn.in_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_inhist[ICMP_TSTAMP];
dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
dyn.in_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_inhist[ICMP_MASKREQ];
dyn.in_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_inhist[ICMP_MASKREPLY];
dyn.out_msgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
for (i = 0; i <= ICMP_MAXTYPE; i++)
dyn.out_msgs += icmp_stat.icps_outhist[i];
dyn.out_errors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
dyn.out_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_outhist[ICMP_UNREACH];
dyn.out_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_outhist[ICMP_TIMXCEED];
dyn.out_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_outhist[ICMP_PARAMPROB];
dyn.out_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
dyn.out_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_outhist[ICMP_REDIRECT];
dyn.out_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_outhist[ICMP_ECHO];
dyn.out_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_outhist[ICMP_TSTAMP];
dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
dyn.out_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_outhist[ICMP_MASKREQ];
dyn.out_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_outhist[ICMP_MASKREPLY];
if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
return STATUS_SUCCESS;
}
#else
FIXME( "not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
#endif
}
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 )
{
@ -981,6 +1113,15 @@ static struct module_table ipv4_tables[] =
NULL,
ipv4_cmpt_get_all_parameters,
},
{
NSI_IP_ICMPSTATS_TABLE,
{
0, 0,
sizeof(struct nsi_ip_icmpstats_dynamic), 0
},
NULL,
ipv4_icmpstats_get_all_parameters,
},
{
NSI_IP_IPSTATS_TABLE,
{

View File

@ -98,6 +98,7 @@ struct nsi_ndis_ifinfo_static
/* Undocumented NSI IP tables */
#define NSI_IP_COMPARTMENT_TABLE 2
#define NSI_IP_ICMPSTATS_TABLE 3
#define NSI_IP_IPSTATS_TABLE 6
#define NSI_IP_UNICAST_TABLE 10
#define NSI_IP_NEIGHBOUR_TABLE 11
@ -119,6 +120,16 @@ struct nsi_ip_cmpt_dynamic
DWORD num_addrs;
};
struct nsi_ip_icmpstats_dynamic
{
DWORD in_msgs;
DWORD in_errors;
DWORD in_type_counts[256];
DWORD out_msgs;
DWORD out_errors;
DWORD out_type_counts[256];
};
struct nsi_ip_ipstats_dynamic
{
DWORD unk[4];