Add ICMP tap support, and add a tshark tap to measure such things as:

* Number of ICMP echo requests, replies, lost replies and percent loss.
  * Min, Max, Average SRT (Service Response Time), and standard deviation.
(This is my first tap, so hopefully I didn't miss something, but we'll see ...)
TODO: Add a Wireshark tap.


svn path=/trunk/; revision=36480
This commit is contained in:
Chris Maynard 2011-04-05 20:21:59 +00:00
parent 4f462b3d09
commit 595e5e1c1d
9 changed files with 350 additions and 25 deletions

View File

@ -548,6 +548,7 @@ set(TSHARK_TAP_SRC
tap-h225counter.c tap-h225counter.c
tap-h225rassrt.c tap-h225rassrt.c
tap-httpstat.c tap-httpstat.c
tap-icmpstat.c
tap-iostat.c tap-iostat.c
tap-iousers.c tap-iousers.c
tap-mgcpstat.c tap-mgcpstat.c

View File

@ -115,6 +115,7 @@ TSHARK_TAP_SRC = \
tap-h225rassrt.c \ tap-h225rassrt.c \
tap-hosts.c \ tap-hosts.c \
tap-httpstat.c \ tap-httpstat.c \
tap-icmpstat.c \
tap-iostat.c \ tap-iostat.c \
tap-iousers.c \ tap-iousers.c \
tap-mgcpstat.c \ tap-mgcpstat.c \

View File

@ -67,7 +67,7 @@ The two functions to start or stop tapping are
register_tap_listener(const char *tapname, void *tapdata, const char *fstring, register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
guint flags, guint flags,
void (*reset)(void *tapdata), void (*reset)(void *tapdata),
gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *<pointer>), gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data),
void (*draw)(void *tapdata)); void (*draw)(void *tapdata));
remove_tap_listener(void *tapdata); remove_tap_listener(void *tapdata);
@ -128,13 +128,15 @@ is a set of flags for the tap listener. The flags that can be set are:
set if your tap listener "packet" routine requires the column set if your tap listener "packet" routine requires the column
strings to be constructed. strings to be constructed.
If no flags are needed, use TL_REQUIRES_NOTHING.
void (*reset)(void *tapdata) void (*reset)(void *tapdata)
This callback is called whenever Wireshark wants to inform your This callback is called whenever Wireshark wants to inform your
listener that it is about to start [re]reading a capture file or a new capture listener that it is about to start [re]reading a capture file or a new capture
from an interface and that your application should reset any state it has from an interface and that your application should reset any state it has
in the *tapdata instance. in the *tapdata instance.
gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, void *data) gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data)
This callback is used whenever a new packet has arrived at the tap and that This callback is used whenever a new packet has arrived at the tap and that
it has passed the filter (if there were a filter). it has passed the filter (if there were a filter).
The *data structure type is specific to each tap. The *data structure type is specific to each tap.

View File

@ -710,6 +710,16 @@ and IPv6 addresses are dumped by default.
Addresses are collected from a number of sources, including standard "hosts" Addresses are collected from a number of sources, including standard "hosts"
files and captured traffic. files and captured traffic.
=item B<-z> icmp,srt[,I<filter>]
Compute total ICMP echo requests, replies, loss, and percent loss, as well as
min, max and average SRT statistics typical of ping statistics.
Example: S<B<-z icmp,srt,ip.src==1.2.3.4>> will collect ICMP SRT statistics
for ICMP echo request packets originating from a specific host.
This option can be used multiple times on the command line.
=item B<-z> io,phs[,I<filter>] =item B<-z> io,phs[,I<filter>]
Create Protocol Hierarchy Statistics listing both number of packets and bytes. Create Protocol Hierarchy Statistics listing both number of packets and bytes.

View File

@ -1148,6 +1148,7 @@ DISSECTOR_INCLUDES = \
packet-http.h \ packet-http.h \
packet-i2c.h \ packet-i2c.h \
packet-iax2.h \ packet-iax2.h \
packet-icmp.h \
packet-idmp.h \ packet-idmp.h \
packet-idp.h \ packet-idp.h \
packet-ieee80211.h \ packet-ieee80211.h \

View File

@ -40,26 +40,24 @@
#include <epan/in_cksum.h> #include <epan/in_cksum.h>
#include "packet-ip.h" #include "packet-ip.h"
#include "packet-icmp.h"
#include <epan/conversation.h> #include <epan/conversation.h>
#include <epan/emem.h> #include <epan/emem.h>
#include <epan/tap.h>
static int icmp_tap = -1;
/* Conversation related data */ /* Conversation related data */
static int hf_icmp_resp_in = -1; static int hf_icmp_resp_in = -1;
static int hf_icmp_resp_to = -1; static int hf_icmp_resp_to = -1;
static int hf_icmp_resptime = -1; static int hf_icmp_resptime = -1;
typedef struct _icmp_transaction_t {
guint32 rqst_frame;
guint32 resp_frame;
nstime_t rqst_time;
} icmp_transaction_t;
typedef struct _icmp_conv_info_t { typedef struct _icmp_conv_info_t {
emem_tree_t *pdus; emem_tree_t *pdus;
} icmp_conv_info_t; } icmp_conv_info_t;
static void transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key); static icmp_transaction_t *transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key);
static void transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key); static icmp_transaction_t *transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key);
/* Decode the end of the ICMP payload as ICMP MPLS extensions /* Decode the end of the ICMP payload as ICMP MPLS extensions
if the packet in the payload has more than 128 bytes */ if the packet in the payload has more than 128 bytes */
@ -705,7 +703,7 @@ dissect_mpls_extensions(tvbuff_t *tvb, gint offset, proto_tree *tree)
} /* end dissect_mpls_extensions */ } /* end dissect_mpls_extensions */
/* ======================================================================= */ /* ======================================================================= */
static void transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key) static icmp_transaction_t *transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key)
{ {
conversation_t *conversation; conversation_t *conversation;
icmp_conv_info_t *icmp_info; icmp_conv_info_t *icmp_info;
@ -734,13 +732,14 @@ static void transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key
icmp_trans->rqst_frame = PINFO_FD_NUM(pinfo); icmp_trans->rqst_frame = PINFO_FD_NUM(pinfo);
icmp_trans->resp_frame = 0; icmp_trans->resp_frame = 0;
icmp_trans->rqst_time = pinfo->fd->abs_ts; icmp_trans->rqst_time = pinfo->fd->abs_ts;
icmp_trans->resp_time = 0.0;
se_tree_insert32_array(icmp_info->pdus, icmp_key, (void *)icmp_trans); se_tree_insert32_array(icmp_info->pdus, icmp_key, (void *)icmp_trans);
} }
else /* Already visited this frame */ else /* Already visited this frame */
icmp_trans = se_tree_lookup32_array(icmp_info->pdus, icmp_key); icmp_trans = se_tree_lookup32_array(icmp_info->pdus, icmp_key);
if ( icmp_trans == NULL ) if ( icmp_trans == NULL )
return; return (NULL);
/* Print state tracking in the tree */ /* Print state tracking in the tree */
if ( icmp_trans->resp_frame && if ( icmp_trans->resp_frame &&
@ -751,10 +750,12 @@ static void transaction_start(packet_info *pinfo, proto_tree *tree, guint32 *key
PROTO_ITEM_SET_GENERATED(it); PROTO_ITEM_SET_GENERATED(it);
} }
return (icmp_trans);
} /* transaction_start() */ } /* transaction_start() */
/* ======================================================================= */ /* ======================================================================= */
static void transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key) static icmp_transaction_t *transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key)
{ {
conversation_t *conversation; conversation_t *conversation;
icmp_conv_info_t *icmp_info; icmp_conv_info_t *icmp_info;
@ -762,16 +763,15 @@ static void transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key)
emem_tree_key_t icmp_key[2]; emem_tree_key_t icmp_key[2];
proto_item *it; proto_item *it;
nstime_t ns; nstime_t ns;
double resptime;
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
pinfo->ptype, 0, 0, 0); pinfo->ptype, 0, 0, 0);
if ( conversation == NULL ) if ( conversation == NULL )
return; return (NULL);
icmp_info = conversation_get_proto_data(conversation, proto_icmp); icmp_info = conversation_get_proto_data(conversation, proto_icmp);
if ( icmp_info == NULL ) if ( icmp_info == NULL )
return; return (NULL);
icmp_key[0].length = 2; icmp_key[0].length = 2;
icmp_key[0].key = key; icmp_key[0].key = key;
@ -779,12 +779,12 @@ static void transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key)
icmp_key[1].key = NULL; icmp_key[1].key = NULL;
icmp_trans = se_tree_lookup32_array(icmp_info->pdus, icmp_key); icmp_trans = se_tree_lookup32_array(icmp_info->pdus, icmp_key);
if ( icmp_trans == NULL ) if ( icmp_trans == NULL )
return; return (NULL);
/* Print state tracking in the tree */ /* Print state tracking in the tree */
if ( icmp_trans->rqst_frame && if ( icmp_trans->rqst_frame &&
(icmp_trans->rqst_frame < PINFO_FD_NUM(pinfo)) && (icmp_trans->rqst_frame < PINFO_FD_NUM(pinfo)) &&
((icmp_trans->resp_frame == 0) || ((icmp_trans->resp_frame == 0) ||
(icmp_trans->resp_frame == PINFO_FD_NUM(pinfo))) ) (icmp_trans->resp_frame == PINFO_FD_NUM(pinfo))) )
{ {
icmp_trans->resp_frame = PINFO_FD_NUM(pinfo); icmp_trans->resp_frame = PINFO_FD_NUM(pinfo);
@ -793,12 +793,14 @@ static void transaction_end(packet_info *pinfo, proto_tree *tree, guint32 *key)
PROTO_ITEM_SET_GENERATED(it); PROTO_ITEM_SET_GENERATED(it);
nstime_delta(&ns, &pinfo->fd->abs_ts, &icmp_trans->rqst_time); nstime_delta(&ns, &pinfo->fd->abs_ts, &icmp_trans->rqst_time);
resptime = 1000.0 * ns.secs + ns.nsecs/1000000.0; icmp_trans->resp_time = nstime_to_msec(&ns);
it = proto_tree_add_double_format_value(tree, hf_icmp_resptime, it = proto_tree_add_double_format_value(tree, hf_icmp_resptime, NULL,
NULL, 0, 0, resptime, "%.3f ms", resptime); 0, 0, icmp_trans->resp_time, "%.3f ms", icmp_trans->resp_time);
PROTO_ITEM_SET_GENERATED(it); PROTO_ITEM_SET_GENERATED(it);
} }
return (icmp_trans);
} /* transaction_end() */ } /* transaction_end() */
/* /*
@ -824,6 +826,7 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
tvbuff_t *next_tvb; tvbuff_t *next_tvb;
proto_item *item; proto_item *item;
guint32 conv_key[2]; guint32 conv_key[2];
icmp_transaction_t *trans = NULL;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMP"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMP");
col_clear(pinfo->cinfo, COL_INFO); col_clear(pinfo->cinfo, COL_INFO);
@ -1010,11 +1013,12 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
conv_key[0] = (guint32)tvb_get_ntohs(tvb, 2); conv_key[0] = (guint32)tvb_get_ntohs(tvb, 2);
conv_key[1] = (guint32)((tvb_get_ntohs(tvb, 4) << 16) | conv_key[1] = (guint32)((tvb_get_ntohs(tvb, 4) << 16) |
tvb_get_ntohs(tvb, 6)); tvb_get_ntohs(tvb, 6));
transaction_end(pinfo, icmp_tree, conv_key); trans = transaction_end(pinfo, icmp_tree, conv_key);
} }
call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo, call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo,
icmp_tree); icmp_tree);
break; break;
case ICMP_ECHO: case ICMP_ECHO:
if ( !pinfo->in_error_pkt ) { if ( !pinfo->in_error_pkt ) {
guint16 tmp[2]; guint16 tmp[2];
@ -1024,7 +1028,7 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
conv_key[0] = ip_checksum((guint8 *)&tmp, sizeof(tmp)); conv_key[0] = ip_checksum((guint8 *)&tmp, sizeof(tmp));
conv_key[1] = (guint32)((tvb_get_ntohs(tvb, 4) << 16) | conv_key[1] = (guint32)((tvb_get_ntohs(tvb, 4) << 16) |
tvb_get_ntohs(tvb, 6)); tvb_get_ntohs(tvb, 6));
transaction_start(pinfo, icmp_tree, conv_key); trans = transaction_start(pinfo, icmp_tree, conv_key);
} }
call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo, call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo,
icmp_tree); icmp_tree);
@ -1063,6 +1067,9 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
tvb_ip_to_str(tvb, 8), tvb_get_ntohl(tvb, 8)); tvb_ip_to_str(tvb, 8), tvb_get_ntohl(tvb, 8));
break; break;
} }
if (trans)
tap_queue_packet(icmp_tap, pinfo, trans);
} }
void void
@ -1269,6 +1276,7 @@ proto_register_icmp(void)
&favor_icmp_mpls_ext); &favor_icmp_mpls_ext);
register_dissector("icmp", dissect_icmp, proto_icmp); register_dissector("icmp", dissect_icmp, proto_icmp);
icmp_tap = register_tap("icmp");
} }
void void

32
epan/dissectors/packet-icmp.h Executable file
View File

@ -0,0 +1,32 @@
/* packet-icmp.h
* Definitions for ICMP: http://tools.ietf.org/html/rfc792.
*
* $Id$
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PACKET_ICMP_H__
#define __PACKET_ICMP_H__
/* ICMP echo request/reply transaction statistics ... used by ICMP tap(s) */
typedef struct _icmp_transaction_t {
guint32 rqst_frame;
guint32 resp_frame;
nstime_t rqst_time;
double resp_time;
} icmp_transaction_t;
#endif

View File

@ -34,8 +34,9 @@ typedef void (*tap_draw_cb)(void *tapdata);
/* /*
* Flags to indicate what a tap listener's packet routine requires. * Flags to indicate what a tap listener's packet routine requires.
*/ */
#define TL_REQUIRES_PROTO_TREE 0x00000001 /**< full protocol tree */ #define TL_REQUIRES_NOTHING 0x00000000 /**< nothing */
#define TL_REQUIRES_COLUMNS 0x00000002 /**< columns */ #define TL_REQUIRES_PROTO_TREE 0x00000001 /**< full protocol tree */
#define TL_REQUIRES_COLUMNS 0x00000002 /**< columns */
extern void tap_init(void); extern void tap_init(void);
extern int register_tap(const char *name); extern int register_tap(const char *name);

269
tap-icmpstat.c Executable file
View File

@ -0,0 +1,269 @@
/* tap-icmpstat.c
* icmpstat 2011 Christopher Maynard
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This module provides icmp echo request/reply SRT statistics to tshark.
* It is only used by tshark and not wireshark
*
* It was based on tap-rpcstat.c and doc/README.tapping.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <string.h>
#include "epan/packet_info.h"
#include <epan/tap.h>
#include <epan/stat_cmd_args.h>
#include <epan/dissectors/packet-icmp.h>
#include <math.h>
/* used to keep track of the ICMP statistics */
typedef struct _icmpstat_t {
char *filter;
GSList *rt_list;
guint num_rqsts;
guint num_resps;
double min_msecs;
double max_msecs;
double tot_msecs;
} icmpstat_t;
/* This callback is never used by tshark but it is here for completeness. When
* registering below, we could just have left this function as NULL.
*
* When used by wireshark, this function will be called whenever we would need
* to reset all state, such as when wireshark opens a new file, when it starts
* a new capture, when it rescans the packetlist after some prefs have changed,
* etc.
*
* So if your application has some state it needs to clean up in those
* situations, here is a good place to put that code.
*/
static void
icmpstat_reset(void *tapdata)
{
icmpstat_t *icmpstat = tapdata;
g_slist_free(icmpstat->rt_list);
icmpstat->rt_list = NULL;
icmpstat->num_rqsts = 0;
icmpstat->num_resps = 0;
icmpstat->min_msecs = 1.0 * G_MAXUINT;
icmpstat->max_msecs = 0.0;
icmpstat->tot_msecs = 0.0;
}
/* This callback is invoked whenever the tap system has seen a packet we might
* be interested in. The function is to be used to only update internal state
* information in the *tapdata structure, and if there were state changes which
* requires the window to be redrawn, return 1 and (*draw) will be called
* sometime later.
*
* This function should be as lightweight as possible since it executes
* together with the normal wireshark dissectors. Try to push as much
* processing as possible into (*draw) instead since that function executes
* asynchronously and does not affect the main thread's performance.
*
* If it is possible, try to do all "filtering" explicitly since you will get
* MUCH better performance than applying a similar display-filter in the
* register call.
*
* The third parameter is tap dependent. Since we register this one to the
* "icmp" tap, the third parameter type is icmp_transaction_t.
*
* function returns :
* 0: no updates, no need to call (*draw) later
* !0: state has changed, call (*draw) sometime later
*/
static int
icmpstat_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
{
icmpstat_t *icmpstat = tapdata;
const icmp_transaction_t *trans = data;
double *rt;
if (trans == NULL)
return 0;
if (trans->resp_frame) {
rt = g_malloc(sizeof(double));
if (rt == NULL)
return 0;
*rt = trans->resp_time;
icmpstat->rt_list = g_slist_prepend(icmpstat->rt_list, rt);
icmpstat->num_resps++;
if (icmpstat->min_msecs > trans->resp_time)
icmpstat->min_msecs = trans->resp_time;
if (icmpstat->max_msecs < trans->resp_time)
icmpstat->max_msecs = trans->resp_time;
icmpstat->tot_msecs += trans->resp_time;
} else if (trans->rqst_frame)
icmpstat->num_rqsts++;
else
return 0;
return 1;
}
static double compute_sdev(double average, guint num, GSList *slist)
{
double diff;
double sq_diff_sum;
if (num == 0)
return 0.0;
for ( sq_diff_sum = 0.0; slist; slist = g_slist_next(slist)) {
diff = *(double *)slist->data - average;
sq_diff_sum += diff * diff;
}
return sqrt(sq_diff_sum / num);
}
/* This callback is used when tshark wants us to draw/update our data to the
* output device. Since this is tshark, the only output is stdout.
* TShark will only call this callback once, which is when tshark has finished
* reading all packets and exits.
* If used with wireshark this may be called any time, perhaps once every 3
* seconds or so.
* This function may even be called in parallel with (*reset) or (*draw), so
* make sure there are no races. The data in the icmpstat_t can thus change
* beneath us. Beware!
*
* How best to display the data? For now, following other tap statistics
* output, but here are a few other alternatives we might choose from:
*
* -> Windows ping output:
* Ping statistics for <IP>:
* Packets: Sent = <S>, Received = <R>, Lost = <L> (<LP>% loss),
* Approximate round trip times in milli-seconds:
* Minimum = <m>ms, Maximum = <M>ms, Average = <A>ms
*
* -> Cygwin ping output:
* ----<HOST> PING Statistics----
* <S> packets transmitted, <R> packets received, <LP>% packet loss
* round-trip (ms) min/avg/max/med = <m>/<M>/<A>/<D>
*
* -> Linux ping output:
* --- <HOST> ping statistics ---
* <S> packets transmitted, <R> received, <LP>% packet loss, time <T>ms
* rtt min/avg/max/mdev = <m>/<A>/<M>/<D> ms
*/
static void
icmpstat_draw(void *tapdata)
{
icmpstat_t *icmpstat = tapdata;
unsigned int lost;
double average, sdev;
printf("\n");
printf("==========================================================================\n");
printf("ICMP SRT Statistics (all times in ms):\n");
printf("Filter: %s\n", icmpstat->filter ? icmpstat->filter : "");
printf("Requests Replies Lost %% Loss Min SRT Max SRT Avg SRT SDEV\n");
if (icmpstat->num_rqsts) {
lost = icmpstat->num_rqsts - icmpstat->num_resps;
average = icmpstat->tot_msecs / icmpstat->num_resps;
sdev = compute_sdev(average, icmpstat->num_resps, icmpstat->rt_list);
printf("%-10u%-10u%-10u%5.1f%% %-10.3f%-10.3f%-10.3f%-10.3f\n",
icmpstat->num_rqsts, icmpstat->num_resps, lost,
100.0 * lost / icmpstat->num_rqsts,
icmpstat->min_msecs >= G_MAXUINT ? 0.0 : icmpstat->min_msecs,
icmpstat->max_msecs, average, sdev);
} else
printf("0 0 0 0.0%% 0.000 0.000 0.000 0.000\n");
printf("==========================================================================\n");
}
/* When called, this function will create a new instance of icmpstat.
*
* This function is called from tshark when it parses the -z icmp, arguments
* and it creates a new instance to store statistics in and registers this new
* instance for the icmp tap.
*/
static void
icmpstat_init(const char *optarg, void* userdata _U_)
{
icmpstat_t *icmpstat;
const char *filter = NULL;
GString *error_string;
if (strstr(optarg, "icmp,srt,"))
filter = optarg + strlen("icmp,srt,");
icmpstat = g_malloc0(sizeof(icmpstat_t));
icmpstat->min_msecs = 1.0 * G_MAXUINT;
if (icmpstat == NULL) {
fprintf(stderr, "tshark: g_malloc() fatal error.\n");
exit(1);
}
if (filter)
icmpstat->filter = g_strdup(filter);
/* It is possible to create a filter and attach it to the callbacks. Then the
* callbacks would only be invoked if the filter matched.
*
* Evaluating filters is expensive and if we can avoid it and not use them,
* then we gain performance.
*
* In this case we do the filtering for protocol and version inside the
* callback itself but use whatever filter the user provided.
*/
error_string = register_tap_listener("icmp", icmpstat, icmpstat->filter,
TL_REQUIRES_NOTHING, icmpstat_reset, icmpstat_packet, icmpstat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
if (icmpstat->filter)
g_free(icmpstat->filter);
g_free(icmpstat);
fprintf(stderr, "tshark: Couldn't register icmp,srt tap: %s\n",
error_string->str);
g_string_free(error_string, TRUE);
exit(1);
}
}
void
register_tap_listener_icmpstat(void)
{
register_stat_cmd_arg("icmp,srt", icmpstat_init, NULL);
}