[PATCH 2/6] nsiproxy: Implement IPv4 icmpstats get_all_parameters.

Huw Davies huw at codeweavers.com
Thu Aug 12 04:38:14 CDT 2021


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/nsi/tests/nsi.c   |  44 +++++++++++++
 dlls/nsiproxy.sys/ip.c | 141 +++++++++++++++++++++++++++++++++++++++++
 include/wine/nsi.h     |  11 ++++
 3 files changed, 196 insertions(+)

diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 7d9d8e12bac..3b1e757fa23 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -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 );
diff --git a/dlls/nsiproxy.sys/ip.c b/dlls/nsiproxy.sys/ip.c
index 19272861cef..8b7b41a291c 100644
--- a/dlls/nsiproxy.sys/ip.c
+++ b/dlls/nsiproxy.sys/ip.c
@@ -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,
         {
diff --git a/include/wine/nsi.h b/include/wine/nsi.h
index 6a90f5f1203..2c72c16aedc 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_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];
-- 
2.23.0




More information about the wine-devel mailing list