[3/4] iphlpapi: Implement GetIcmpStatisticsEx on Linux
André Hentschel
nerv at dawncrow.de
Wed Sep 19 16:53:37 CDT 2012
This one is different as it uses a different struct as its non-Ex function
---
dlls/iphlpapi/iphlpapi.spec | 2 +-
dlls/iphlpapi/ipstats.c | 172 ++++++++++++++++++++++++++++++++++++++++
dlls/iphlpapi/tests/iphlpapi.c | 6 +-
include/ipmib.h | 36 ++++++++
4 files changed, 214 insertions(+), 2 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec
index d1cf196..368159a 100644
--- a/dlls/iphlpapi/iphlpapi.spec
+++ b/dlls/iphlpapi/iphlpapi.spec
@@ -83,7 +83,7 @@
@ stdcall GetExtendedTcpTable( ptr ptr long long long long )
@ stdcall GetExtendedUdpTable( ptr ptr long long long long )
@ stdcall GetFriendlyIfIndex( long )
-#@ stub GetIcmpStatisticsEx
+@ stdcall GetIcmpStatisticsEx( ptr long )
@ stdcall GetIcmpStatistics( ptr )
@ stub GetIcmpStatsFromStack
@ stdcall GetIfEntry( ptr )
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index f314745..4135f72 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -551,6 +551,178 @@ DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
return ret;
}
+/******************************************************************
+ * GetIcmpStatisticsEx (IPHLPAPI.@)
+ *
+ * Get the IPv4 and IPv6 ICMP statistics for the local computer.
+ *
+ * PARAMS
+ * stats [Out] buffer for ICMP statistics
+ * family [In] specifies wether IPv4 or IPv6 statistics are returned
+ *
+ * RETURNS
+ * Success: NO_ERROR
+ * Failure: error code from winerror.h
+ */
+DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
+{
+ DWORD ret = ERROR_NOT_SUPPORTED;
+ MIB_ICMP ipv4stats;
+
+ if (!stats) return ERROR_INVALID_PARAMETER;
+ if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
+ memset( stats, 0, sizeof(MIB_ICMP_EX) );
+
+ if (family == WS_AF_INET6)
+ {
+#ifdef __linux__
+ {
+ FILE *fp;
+
+ if ((fp = fopen("/proc/net/snmp6", "r")))
+ {
+ struct icmpstatstruct{
+ const char *name;
+ DWORD pos;
+ };
+ static struct icmpstatstruct icmpinstatlist[] = {
+ { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
+ { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
+ { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
+ { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
+ { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
+ { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
+ { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
+ { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
+ { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
+ { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
+ { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
+ { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
+ { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
+ { "Icmp6InRedirects", ND_REDIRECT },
+ { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
+ };
+ static struct icmpstatstruct icmpoutstatlist[] = {
+ { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
+ { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
+ { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
+ { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
+ { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
+ { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
+ { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
+ { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
+ { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
+ { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
+ { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
+ { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
+ { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
+ { "Icmp6OutRedirects", ND_REDIRECT },
+ { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
+ };
+ char buf[512], *ptr, *value;
+ DWORD res, i;
+
+ while ((ptr = fgets(buf, sizeof(buf), fp)))
+ {
+ if (!(value = strchr(buf, ' ')))
+ continue;
+
+ /* terminate the valuename */
+ ptr = value - 1;
+ *(ptr + 1) = '\0';
+
+ /* and strip leading spaces from value */
+ value += 1;
+ while (*value==' ') value++;
+ if ((ptr = strchr(value, '\n')))
+ *ptr='\0';
+
+ if (!strcasecmp(buf, "Icmp6InMsgs"))
+ {
+ if (sscanf(value, "%d", &res)) stats->icmpInStats.dwMsgs = res;
+ continue;
+ }
+
+ if (!strcasecmp(buf, "Icmp6InErrors"))
+ {
+ if (sscanf(value, "%d", &res)) stats->icmpInStats.dwErrors = res;
+ continue;
+ }
+
+ for (i = 0; i < sizeof(icmpinstatlist)/sizeof(icmpinstatlist[0]); i++)
+ {
+ if (!strcasecmp(buf, icmpinstatlist[i].name))
+ {
+ if (sscanf(value, "%d", &res))
+ stats->icmpInStats.rgdwTypeCount[icmpinstatlist[i].pos] = res;
+ break;
+ }
+ }
+
+ if (!strcasecmp(buf, "Icmp6OutMsgs"))
+ {
+ if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwMsgs = res;
+ continue;
+ }
+
+ if (!strcasecmp(buf, "Icmp6OutErrors"))
+ {
+ if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwErrors = res;
+ continue;
+ }
+
+ for (i = 0; i < sizeof(icmpoutstatlist)/sizeof(icmpoutstatlist[0]); i++)
+ {
+ if (!strcasecmp(buf, icmpoutstatlist[i].name))
+ {
+ if (sscanf(value, "%d", &res))
+ stats->icmpOutStats.rgdwTypeCount[icmpoutstatlist[i].pos] = res;
+ break;
+ }
+ }
+
+ }
+ fclose(fp);
+ ret = NO_ERROR;
+ }
+ }
+#else
+ FIXME( "unimplemented for IPv6\n" );
+#endif
+ return ret;
+ }
+
+ ret = GetIcmpStatistics(&ipv4stats);
+ if SUCCEEDED(ret)
+ {
+ stats->icmpInStats.dwMsgs = ipv4stats.stats.icmpInStats.dwMsgs;
+ stats->icmpInStats.dwErrors = ipv4stats.stats.icmpInStats.dwErrors;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpInStats.dwDestUnreachs;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpInStats.dwSrcQuenchs;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpInStats.dwRedirects;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpInStats.dwEchos;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpInStats.dwTimeExcds;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpInStats.dwParmProbs;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpInStats.dwTimestamps;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpInStats.dwTimestampReps;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpInStats.dwAddrMasks;
+ stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpInStats.dwAddrMaskReps;
+
+ stats->icmpOutStats.dwMsgs = ipv4stats.stats.icmpOutStats.dwMsgs;
+ stats->icmpOutStats.dwErrors = ipv4stats.stats.icmpOutStats.dwErrors;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpOutStats.dwDestUnreachs;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpOutStats.dwSrcQuenchs;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpOutStats.dwRedirects;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpOutStats.dwEchos;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpOutStats.dwTimeExcds;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpOutStats.dwParmProbs;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpOutStats.dwTimestamps;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpOutStats.dwTimestampReps;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpOutStats.dwAddrMasks;
+ stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpOutStats.dwAddrMaskReps;
+ }
+ return ret;
+}
/******************************************************************
* GetIpStatisticsEx (IPHLPAPI.@)
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index 02a299f..eb96189 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -530,7 +530,7 @@ static void testGetIcmpStatisticsEx(void)
if (!pGetIcmpStatisticsEx)
{
- skip( "GetIcmpStatisticsEx not available\n" );
+ win_skip( "GetIcmpStatisticsEx not available\n" );
return;
}
@@ -541,6 +541,10 @@ static void testGetIcmpStatisticsEx(void)
"GetIcmpStatisticsEx(NULL, AF_INET) returned %d, expected ERROR_INVALID_PARAMETER\n", apiReturn);
}
+ apiReturn = pGetIcmpStatisticsEx(&stats, AF_BAN);
+ ok(apiReturn == ERROR_INVALID_PARAMETER,
+ "GetIcmpStatisticsEx(&stats, AF_BAN) returned %d, expected ERROR_INVALID_PARAMETER\n", apiReturn);
+
apiReturn = pGetIcmpStatisticsEx(&stats, AF_INET);
ok(apiReturn == NO_ERROR, "GetIcmpStatisticsEx returned %d, expected NO_ERROR\n", apiReturn);
if (apiReturn == NO_ERROR && winetest_debug > 1)
diff --git a/include/ipmib.h b/include/ipmib.h
index bc42c90..65576be 100644
--- a/include/ipmib.h
+++ b/include/ipmib.h
@@ -192,6 +192,42 @@ typedef struct _MIB_ICMP
MIBICMPINFO stats;
} MIB_ICMP, *PMIB_ICMP;
+typedef enum
+{
+ ICMP4_ECHO_REPLY = 0,
+ ICMP4_DST_UNREACH = 3,
+ ICMP4_SOURCE_QUENCH = 4,
+ ICMP4_REDIRECT = 5,
+ ICMP4_ECHO_REQUEST = 8,
+ ICMP4_ROUTER_ADVERT = 9,
+ ICMP4_ROUTER_SOLICIT = 10,
+ ICMP4_TIME_EXCEEDED = 11,
+ ICMP4_PARAM_PROB = 12,
+ ICMP4_TIMESTAMP_REQUEST = 13,
+ ICMP4_TIMESTAMP_REPLY = 14,
+ ICMP4_MASK_REQUEST = 17,
+ ICMP4_MASK_REPLY = 18,
+} ICMP4_TYPE, *PICMP4_TYPE;
+
+typedef enum
+{
+ ICMP6_DST_UNREACH = 1,
+ ICMP6_PACKET_TOO_BIG = 2,
+ ICMP6_TIME_EXCEEDED = 3,
+ ICMP6_PARAM_PROB = 4,
+ ICMP6_ECHO_REQUEST = 128,
+ ICMP6_ECHO_REPLY = 129,
+ ICMP6_MEMBERSHIP_QUERY = 130,
+ ICMP6_MEMBERSHIP_REPORT = 131,
+ ICMP6_MEMBERSHIP_REDUCTION = 132,
+ ND_ROUTER_SOLICIT = 133,
+ ND_ROUTER_ADVERT = 134,
+ ND_NEIGHBOR_SOLICIT = 135,
+ ND_NEIGHBOR_ADVERT = 136,
+ ND_REDIRECT = 137,
+ ICMP6_V2_MEMBERSHIP_REPORT = 143,
+} ICMP6_TYPE, *PICMP6_TYPE;
+
typedef struct _MIBICMPSTATS_EX
{
DWORD dwMsgs;
--
1.7.4.1
--
Best Regards, André Hentschel
More information about the wine-patches
mailing list