aboutsummaryrefslogtreecommitdiffstats
path: root/ui/cli
diff options
context:
space:
mode:
authorJörg Mayer <jmayer@loplof.de>2012-02-17 12:30:27 +0000
committerJörg Mayer <jmayer@loplof.de>2012-02-17 12:30:27 +0000
commit35508464b20bcf32ad548bb9f8c5424eddf5887a (patch)
tree80f16acb51d81ce613bf7741f6db62b4f73534f3 /ui/cli
parentcdc504ac3fb9121856263c6f2b6e9c6816256ea8 (diff)
Start moving files to ui/ and ui/cli/
svn path=/trunk/; revision=41047
Diffstat (limited to 'ui/cli')
-rw-r--r--ui/cli/dftest.c199
-rw-r--r--ui/cli/tap-afpstat.c164
-rw-r--r--ui/cli/tap-ansi_astat.c166
-rw-r--r--ui/cli/tap-bootpstat.c186
-rw-r--r--ui/cli/tap-camelcounter.c133
-rw-r--r--ui/cli/tap-camelsrt.c255
-rw-r--r--ui/cli/tap-comparestat.c583
-rw-r--r--ui/cli/tap-dcerpcstat.c300
-rw-r--r--ui/cli/tap-diameter-avp.c286
-rw-r--r--ui/cli/tap-expert.c279
-rw-r--r--ui/cli/tap-follow.c869
-rw-r--r--ui/cli/tap-funnel.c195
-rw-r--r--ui/cli/tap-gsm_astat.c353
-rw-r--r--ui/cli/tap-h225counter.c384
-rw-r--r--ui/cli/tap-h225rassrt.c246
-rw-r--r--ui/cli/tap-hosts.c183
-rw-r--r--ui/cli/tap-httpstat.c329
-rw-r--r--ui/cli/tap-icmpstat.c319
-rw-r--r--ui/cli/tap-icmpv6stat.c320
-rw-r--r--ui/cli/tap-iostat.c984
-rw-r--r--ui/cli/tap-iousers.c780
-rw-r--r--ui/cli/tap-macltestat.c527
-rw-r--r--ui/cli/tap-megacostat.c148
-rw-r--r--ui/cli/tap-mgcpstat.c230
-rw-r--r--ui/cli/tap-protocolinfo.c144
-rw-r--r--ui/cli/tap-protohierstat.c220
-rw-r--r--ui/cli/tap-radiusstat.c243
-rw-r--r--ui/cli/tap-rlcltestat.c411
-rw-r--r--ui/cli/tap-rpcprogs.c240
-rw-r--r--ui/cli/tap-rpcstat.c355
-rw-r--r--ui/cli/tap-rtp.c162
-rw-r--r--ui/cli/tap-rtspstat.c282
-rw-r--r--ui/cli/tap-scsistat.c264
-rw-r--r--ui/cli/tap-sctpchunkstat.c254
-rw-r--r--ui/cli/tap-sipstat.c443
-rw-r--r--ui/cli/tap-smbsids.c100
-rw-r--r--ui/cli/tap-smbstat.c260
-rw-r--r--ui/cli/tap-stats_tree.c145
-rw-r--r--ui/cli/tap-sv.c87
-rw-r--r--ui/cli/tap-wspstat.c286
40 files changed, 12314 insertions, 0 deletions
diff --git a/ui/cli/dftest.c b/ui/cli/dftest.c
new file mode 100644
index 0000000000..939f77be11
--- /dev/null
+++ b/ui/cli/dftest.c
@@ -0,0 +1,199 @@
+/* dftest.c
+ * Shows display filter byte-code, for debugging dfilter routines.
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <epan/epan.h>
+
+#include <epan/timestamp.h>
+#include <epan/plugins.h>
+#include <epan/filesystem.h>
+#include <wsutil/privileges.h>
+#include <epan/prefs.h>
+#include "ui/util.h"
+#include "epan/dfilter/dfilter.h"
+#include "register.h"
+
+static void failure_message(const char *msg_format, va_list ap);
+static void open_failure_message(const char *filename, int err,
+ gboolean for_writing);
+static void read_failure_message(const char *filename, int err);
+static void write_failure_message(const char *filename, int err);
+
+int
+main(int argc, char **argv)
+{
+ char *init_progfile_dir_error;
+ char *text;
+ char *gpf_path, *pf_path;
+ int gpf_open_errno, gpf_read_errno;
+ int pf_open_errno, pf_read_errno;
+ dfilter_t *df;
+
+ /*
+ * Get credential information for later use.
+ */
+ init_process_policies();
+
+ /*
+ * Attempt to get the pathname of the executable file.
+ */
+ init_progfile_dir_error = init_progfile_dir(argv[0], main);
+ if (init_progfile_dir_error != NULL) {
+ fprintf(stderr, "dftest: Can't get pathname of dftest program: %s.\n",
+ init_progfile_dir_error);
+ }
+
+ timestamp_set_type(TS_RELATIVE);
+ timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
+
+ /* Register all dissectors; we must do this before checking for the
+ "-g" flag, as the "-g" flag dumps a list of fields registered
+ by the dissectors, and we must do it before we read the preferences,
+ in case any dissectors register preferences. */
+ epan_init(register_all_protocols,
+ register_all_protocol_handoffs, NULL, NULL,
+ failure_message, open_failure_message, read_failure_message,
+ write_failure_message);
+
+ /* now register the preferences for any non-dissector modules.
+ we must do that before we read the preferences as well. */
+ prefs_register_modules();
+
+ /* set the c-language locale to the native environment. */
+ setlocale(LC_ALL, "");
+
+ read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
+ &pf_open_errno, &pf_read_errno, &pf_path);
+ if (gpf_path != NULL) {
+ if (gpf_open_errno != 0) {
+ fprintf(stderr,
+ "can't open global preferences file \"%s\": %s.\n",
+ pf_path, g_strerror(gpf_open_errno));
+ }
+ if (gpf_read_errno != 0) {
+ fprintf(stderr,
+ "I/O error reading global preferences file \"%s\": %s.\n",
+ pf_path, g_strerror(gpf_read_errno));
+ }
+ }
+ if (pf_path != NULL) {
+ if (pf_open_errno != 0) {
+ fprintf(stderr,
+ "can't open your preferences file \"%s\": %s.\n",
+ pf_path, g_strerror(pf_open_errno));
+ }
+ if (pf_read_errno != 0) {
+ fprintf(stderr,
+ "I/O error reading your preferences file \"%s\": %s.\n",
+ pf_path, g_strerror(pf_read_errno));
+ }
+ }
+
+ /* notify all registered modules that have had any of their preferences
+ changed either from one of the preferences file or from the command
+ line that its preferences have changed. */
+ prefs_apply_all();
+
+ /* Check for filter on command line */
+ if (argc <= 1) {
+ fprintf(stderr, "Usage: dftest <filter>\n");
+ exit(1);
+ }
+
+ /* Get filter text */
+ text = get_args_as_string(argc, argv, 1);
+
+ printf("Filter: \"%s\"\n", text);
+
+ /* Compile it */
+ if (!dfilter_compile(text, &df)) {
+ fprintf(stderr, "dftest: %s\n", dfilter_error_msg);
+ epan_cleanup();
+ exit(2);
+ }
+ printf("dfilter ptr = 0x%08x\n", GPOINTER_TO_INT(df));
+
+ printf("\n\n");
+
+ if (df == NULL)
+ printf("Filter is empty\n");
+ else
+ dfilter_dump(df);
+
+ dfilter_free(df);
+ epan_cleanup();
+ exit(0);
+}
+
+/*
+ * General errors are reported with an console message in "dftest".
+ */
+static void
+failure_message(const char *msg_format, va_list ap)
+{
+ fprintf(stderr, "dftest: ");
+ vfprintf(stderr, msg_format, ap);
+ fprintf(stderr, "\n");
+}
+
+/*
+ * Open/create errors are reported with an console message in "dftest".
+ */
+static void
+open_failure_message(const char *filename, int err, gboolean for_writing)
+{
+ fprintf(stderr, "dftest: ");
+ fprintf(stderr, file_open_error_message(err, for_writing), filename);
+ fprintf(stderr, "\n");
+}
+
+/*
+ * Read errors are reported with an console message in "dftest".
+ */
+static void
+read_failure_message(const char *filename, int err)
+{
+ fprintf(stderr, "dftest: An error occurred while reading from the file \"%s\": %s.\n",
+ filename, g_strerror(err));
+}
+
+/*
+ * Write errors are reported with an console message in "dftest".
+ */
+static void
+write_failure_message(const char *filename, int err)
+{
+ fprintf(stderr, "dftest: An error occurred while writing to the file \"%s\": %s.\n",
+ filename, g_strerror(err));
+}
diff --git a/ui/cli/tap-afpstat.c b/ui/cli/tap-afpstat.c
new file mode 100644
index 0000000000..e1960f474d
--- /dev/null
+++ b/ui/cli/tap-afpstat.c
@@ -0,0 +1,164 @@
+/* tap-afpstat.c
+ * Based on
+ * smbstat 2003 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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/value_string.h>
+#include <epan/dissectors/packet-afp.h>
+#include "timestats.h"
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _afpstat_t {
+ char *filter;
+ timestat_t proc[256];
+} afpstat_t;
+
+static int
+afpstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
+{
+ afpstat_t *ss=(afpstat_t *)pss;
+ const afp_request_val *request_val=prv;
+ nstime_t t, deltat;
+ timestat_t *sp=NULL;
+
+ /* if we havnt seen the request, just ignore it */
+ if(!request_val){
+ return 0;
+ }
+
+ sp=&(ss->proc[request_val->command]);
+
+ /* calculate time delta between request and reply */
+ t=pinfo->fd->abs_ts;
+ nstime_delta(&deltat, &t, &request_val->req_time);
+
+ if(sp){
+ time_stat_update(sp,&deltat, pinfo);
+ }
+
+ return 1;
+}
+
+static void
+afpstat_draw(void *pss)
+{
+ afpstat_t *ss=(afpstat_t *)pss;
+ guint32 i;
+ guint64 td;
+ printf("\n");
+ printf("===================================================================\n");
+ printf("AFP SRT Statistics:\n");
+ printf("Filter: %s\n",ss->filter?ss->filter:"");
+ printf("Commands Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0;i<256;i++){
+ /* nothing seen, nothing to do */
+ if(ss->proc[i].num==0){
+ continue;
+ }
+
+ /* scale it to units of 10us.*/
+ td=ss->proc[i].tot.secs;
+ td=td*100000+(int)ss->proc[i].tot.nsecs/10000;
+ if(ss->proc[i].num){
+ td/=ss->proc[i].num;
+ } else {
+ td=0;
+ }
+
+ printf("%-25s %6d %3d.%05d %3d.%05d %3" G_GINT64_MODIFIER "u.%05" G_GINT64_MODIFIER "u\n",
+ val_to_str_ext(i, &CommandCode_vals_ext, "Unknown (%u)"),
+ ss->proc[i].num,
+ (int)ss->proc[i].min.secs,ss->proc[i].min.nsecs/10000,
+ (int)ss->proc[i].max.secs,ss->proc[i].max.nsecs/10000,
+ td/100000, td%100000
+ );
+ }
+ printf("===================================================================\n");
+}
+
+
+static void
+afpstat_init(const char *optarg, void* userdata _U_)
+{
+ afpstat_t *ss;
+ guint32 i;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if(!strncmp(optarg,"afp,srt,",8)){
+ filter=optarg+8;
+ } else {
+ filter=NULL;
+ }
+
+ ss=g_malloc(sizeof(afpstat_t));
+ if(filter){
+ ss->filter=g_strdup(filter);
+ } else {
+ ss->filter=NULL;
+ }
+
+ for(i=0;i<256;i++){
+ ss->proc[i].num=0;
+ ss->proc[i].min_num=0;
+ ss->proc[i].max_num=0;
+ ss->proc[i].min.secs=0;
+ ss->proc[i].min.nsecs=0;
+ ss->proc[i].max.secs=0;
+ ss->proc[i].max.nsecs=0;
+ ss->proc[i].tot.secs=0;
+ ss->proc[i].tot.nsecs=0;
+ }
+
+ error_string=register_tap_listener("afp", ss, filter, 0, NULL, afpstat_packet, afpstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ss->filter);
+ g_free(ss);
+
+ fprintf(stderr, "tshark: Couldn't register afp,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+void
+register_tap_listener_afpstat(void)
+{
+ register_stat_cmd_arg("afp,srt", afpstat_init,NULL);
+}
diff --git a/ui/cli/tap-ansi_astat.c b/ui/cli/tap-ansi_astat.c
new file mode 100644
index 0000000000..ee368abb74
--- /dev/null
+++ b/ui/cli/tap-ansi_astat.c
@@ -0,0 +1,166 @@
+/* tap-ansi_astat.c
+ *
+ * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
+ * In association with Telos Technology Inc.
+ *
+ * $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 TAP provides statistics for the ANSI A Interface:
+ */
+
+#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/value_string.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-bssap.h>
+#include <epan/dissectors/packet-ansi_a.h>
+
+
+typedef struct _ansi_a_stat_t {
+ int bsmap_message_type[0xff];
+ int dtap_message_type[0xff];
+} ansi_a_stat_t;
+
+
+static int
+ansi_a_stat_packet(
+ void *tapdata,
+ packet_info *pinfo _U_,
+ epan_dissect_t *edt _U_,
+ const void *data)
+{
+ ansi_a_stat_t *stat_p = tapdata;
+ const ansi_a_tap_rec_t *tap_p = data;
+
+
+ switch (tap_p->pdu_type)
+ {
+ case BSSAP_PDU_TYPE_BSMAP:
+ stat_p->bsmap_message_type[tap_p->message_type]++;
+ break;
+
+ case BSSAP_PDU_TYPE_DTAP:
+ stat_p->dtap_message_type[tap_p->message_type]++;
+ break;
+
+ default:
+ /*
+ * unknown PDU type !!!
+ */
+ return(0);
+ }
+
+ return(1);
+}
+
+
+static void
+ansi_a_stat_draw(
+ void *tapdata)
+{
+ ansi_a_stat_t *stat_p = tapdata;
+ guint8 i;
+
+
+ printf("\n");
+ printf("=========== ANSI A-i/f Statistics ============================\n");
+ printf("BSMAP\n");
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (ansi_a_ios401_bsmap_strings[i].strptr)
+ {
+ if (stat_p->bsmap_message_type[ansi_a_ios401_bsmap_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ ansi_a_ios401_bsmap_strings[i].value,
+ ansi_a_ios401_bsmap_strings[i].strptr,
+ stat_p->bsmap_message_type[ansi_a_ios401_bsmap_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP\n");
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (ansi_a_ios401_dtap_strings[i].strptr)
+ {
+ if (stat_p->dtap_message_type[ansi_a_ios401_dtap_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ ansi_a_ios401_dtap_strings[i].value,
+ ansi_a_ios401_dtap_strings[i].strptr,
+ stat_p->dtap_message_type[ansi_a_ios401_dtap_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("==============================================================\n");
+}
+
+
+static void
+ansi_a_stat_init(const char *optarg _U_, void* userdata _U_)
+{
+ ansi_a_stat_t *stat_p;
+ GString *err_p;
+
+ stat_p = g_malloc(sizeof(ansi_a_stat_t));
+
+ memset(stat_p, 0, sizeof(ansi_a_stat_t));
+
+ err_p =
+ register_tap_listener("ansi_a", stat_p, NULL, 0,
+ NULL,
+ ansi_a_stat_packet,
+ ansi_a_stat_draw);
+
+ if (err_p != NULL)
+ {
+ g_free(stat_p);
+ g_string_free(err_p, TRUE);
+
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_ansi_astat(void)
+{
+ register_stat_cmd_arg("ansi_a,", ansi_a_stat_init,NULL);
+}
diff --git a/ui/cli/tap-bootpstat.c b/ui/cli/tap-bootpstat.c
new file mode 100644
index 0000000000..041364955d
--- /dev/null
+++ b/ui/cli/tap-bootpstat.c
@@ -0,0 +1,186 @@
+/* tap-bootpstat.c
+ * boop_stat 2003 Jean-Michel FAYARD
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+
+
+typedef const char* bootp_info_value_t;
+
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _dhcp_stats_t {
+ char *filter;
+ GHashTable *hash;
+ guint index; /* Number of to display */
+} dhcpstat_t;
+/* used to keep track of a single DHCP message type */
+typedef struct _dhcp_message_type_t {
+ const char *name;
+ guint32 packets;
+ dhcpstat_t *sp; /* entire program interface */
+} dhcp_message_type_t;
+
+
+/* Not used anywhere at this moment */
+/*
+static void
+dhcp_free_hash( gpointer key _U_ , gpointer value, gpointer user_data _U_ )
+{
+ g_free(value);
+}
+*/
+
+static void
+dhcp_reset_hash(gchar *key _U_ , dhcp_message_type_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+
+/* Update the entry corresponding to the number of packets of a special DHCP Message Type
+ * or create it if it don't exist.
+ */
+static void
+dhcp_draw_message_type(gchar *key _U_, dhcp_message_type_t *data, gchar * format )
+{
+ if ((data==NULL) || (data->packets==0))
+ return;
+ printf( format, data->name, data->packets);
+}
+static void
+dhcpstat_reset(void *psp)
+{
+ dhcpstat_t *sp=psp;
+ g_hash_table_foreach( sp->hash, (GHFunc)dhcp_reset_hash, NULL);
+}
+static int
+dhcpstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ dhcpstat_t *sp=psp;
+ const bootp_info_value_t value=pri;
+ dhcp_message_type_t *sc;
+
+ if (sp==NULL)
+ return 0;
+ sc = g_hash_table_lookup(
+ sp->hash,
+ value);
+ if (!sc) {
+ sc = g_malloc( sizeof(dhcp_message_type_t) );
+ sc -> packets = 1;
+ sc -> name = value;
+ sc -> sp = sp;
+ g_hash_table_insert(
+ sp->hash,
+ (gpointer) value,
+ sc);
+ } else {
+ /*g_warning("sc(%s)->packets++", sc->name);*/
+ sc->packets++;
+ }
+ return 1;
+}
+
+
+static void
+dhcpstat_draw(void *psp)
+{
+ dhcpstat_t *sp=psp;
+
+ printf("\n");
+ printf("===================================================================\n");
+
+ if (sp->filter==NULL)
+ printf("BOOTP Statistics\n");
+ else
+ printf("BOOTP Statistics with filter %s\n", sp->filter);
+ printf("BOOTP Option 53: DHCP Messages Types:\n");
+ printf("DHCP Message Type Packets nb\n" );
+ g_hash_table_foreach( sp->hash, (GHFunc) dhcp_draw_message_type,
+ "%23s %-9d\n" );
+ printf("===================================================================\n");
+
+}
+
+
+
+
+/* When called, this function will create a new instance of tap-boopstat.
+ */
+static void
+dhcpstat_init(const char *optarg, void* userdata _U_)
+{
+ dhcpstat_t *sp;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if (!strncmp (optarg, "bootp,stat,", 11)){
+ filter=optarg+11;
+ } else {
+ filter=NULL;
+ }
+
+ sp = g_malloc( sizeof(dhcpstat_t) );
+ sp->hash = g_hash_table_new( g_str_hash, g_str_equal);
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ sp->index = 0; /* Nothing to display yet */
+
+ error_string = register_tap_listener(
+ "bootp",
+ sp,
+ filter,
+ 0,
+ dhcpstat_reset,
+ dhcpstat_packet,
+ dhcpstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->filter);
+ g_free(sp);
+ fprintf(stderr, "tshark: Couldn't register dhcp,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+
+void
+register_tap_listener_gtkdhcpstat(void)
+{
+ register_stat_cmd_arg("bootp,stat,", dhcpstat_init,NULL);
+}
+
diff --git a/ui/cli/tap-camelcounter.c b/ui/cli/tap-camelcounter.c
new file mode 100644
index 0000000000..c922f19860
--- /dev/null
+++ b/ui/cli/tap-camelcounter.c
@@ -0,0 +1,133 @@
+/* tap_camelcounter.c
+ * camel message counter for tshark
+ * Copyright 2006 Florent DROUIN
+ *
+ * $Id$
+ *
+ * This part of code is extracted from tap-h225counter.c from Lars Roland
+ *
+ * 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.
+ */
+
+#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.h"
+#include "epan/packet_info.h"
+#include "epan/tap.h"
+#include "epan/value_string.h"
+#include "epan/stat_cmd_args.h"
+#include "epan/asn1.h"
+#include "epan/camel-persistentdata.h"
+
+void register_tap_listener_camelcounter(void);
+
+/* used to keep track of the statistics for an entire program interface */
+struct camelcounter_t {
+ char *filter;
+ guint32 camel_msg[camel_MAX_NUM_OPR_CODES];
+};
+
+
+static void camelcounter_reset(void *phs)
+{
+ struct camelcounter_t * p_counter= ( struct camelcounter_t *) phs;
+ memset(p_counter,0,sizeof(struct camelcounter_t));
+}
+
+static int camelcounter_packet(void *phs,
+ packet_info *pinfo _U_,
+ epan_dissect_t *edt _U_,
+ const void *phi)
+{
+ struct camelcounter_t * p_counter =(struct camelcounter_t *)phs;
+ const struct camelsrt_info_t * pi=phi;
+ if (pi->opcode != 255)
+ p_counter->camel_msg[pi->opcode]++;
+
+ return 1;
+}
+
+
+static void camelcounter_draw(void *phs)
+{
+ struct camelcounter_t * p_counter= (struct camelcounter_t *)phs;
+ int i;
+ printf("\n");
+ printf("CAMEL Message and Response Status Counter:\n");
+ printf("------------------------------------------\n");
+
+ for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) {
+ /* Message counter */
+ if(p_counter->camel_msg[i]!=0) {
+ printf("%30s ", val_to_str(i,camel_opr_code_strings,"Unknown message "));
+ printf("%6d\n", p_counter->camel_msg[i]);
+ }
+ } /* Message Type */
+ printf("------------------------------------------\n");
+}
+
+static void camelcounter_init(const char *optarg, void* userdata _U_)
+{
+ struct camelcounter_t *p_camelcounter;
+ GString *error_string;
+
+ p_camelcounter = g_malloc(sizeof(struct camelcounter_t));
+ if(!strncmp(optarg,"camel,counter,",13)){
+ p_camelcounter->filter=g_strdup(optarg+13);
+ } else {
+ p_camelcounter->filter=NULL;
+ }
+
+ camelcounter_reset(p_camelcounter);
+
+ error_string=register_tap_listener("CAMEL",
+ p_camelcounter,
+ p_camelcounter->filter,
+ 0,
+ NULL,
+ camelcounter_packet,
+ camelcounter_draw);
+
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(p_camelcounter->filter);
+ g_free(p_camelcounter);
+
+ fprintf(stderr, "tshark: Couldn't register camel,counter tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void /* Next line mandatory */
+register_tap_listener_camelcounter(void)
+{
+ register_stat_cmd_arg("camel,counter", camelcounter_init, NULL);
+}
diff --git a/ui/cli/tap-camelsrt.c b/ui/cli/tap-camelsrt.c
new file mode 100644
index 0000000000..d4c16589ec
--- /dev/null
+++ b/ui/cli/tap-camelsrt.c
@@ -0,0 +1,255 @@
+/* tap_camelsrt.c
+ * CAMEL Service Response Time statistics for tshark
+ * Copyright 2006 Florent Drouin (based on tap_h225rassrt.c from Lars Roland)
+ *
+ * $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.
+ */
+
+#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.h"
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include "epan/value_string.h"
+#include "epan/asn1.h"
+#include "epan/dissectors/packet-camel.h"
+#include "epan/camel-persistentdata.h"
+#include "timestats.h"
+#include "epan/stat_cmd_args.h"
+
+
+void register_tap_listener_camelsrt(void);
+
+/* Save the the first NUM_RAS_STATS stats in the array to calculate percentile */
+#define NUM_RAS_STATS 500000
+
+/* Number of couple message Request/Response to analyze*/
+#define NB_CRITERIA 7
+
+/* used to keep track of the statistics for an entire program interface */
+struct camelsrt_t {
+ char *filter;
+ guint32 count[NB_CAMELSRT_CATEGORY];
+ timestat_t stats[NB_CAMELSRT_CATEGORY];
+ nstime_t delta_time[NB_CAMELSRT_CATEGORY][NUM_RAS_STATS];
+};
+
+/* Reset the counter */
+static void camelsrt_reset(void *phs)
+{
+ struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+ memset(hs,0,sizeof(struct camelsrt_t));
+}
+
+
+static int camelsrt_packet(void *phs,
+ packet_info *pinfo _U_,
+ epan_dissect_t *edt _U_,
+ const void *phi)
+{
+ struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+ const struct camelsrt_info_t * pi=phi;
+ int i;
+
+ for (i=0; i<NB_CAMELSRT_CATEGORY; i++) {
+ if (pi->bool_msginfo[i] &&
+ pi->msginfo[i].is_delta_time
+ && pi->msginfo[i].request_available
+ && !pi->msginfo[i].is_duplicate ) {
+
+ time_stat_update(&(hs->stats[i]),
+ &(pi->msginfo[i].delta_time),
+ pinfo);
+
+ if (hs->count[i] < NUM_RAS_STATS) {
+ hs->delta_time[i][hs->count[i]++]
+ = pi->msginfo[i].delta_time;
+ }
+ }
+ }
+ return 1;
+}
+
+
+static void camelsrt_draw(void *phs)
+{
+ struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+ guint j,z;
+ guint32 li;
+ int somme,iteration=0;
+ timestat_t *rtd_temp;
+ double x,delay,delay_max,delay_min,delta;
+ double criteria[NB_CRITERIA]={ 5.0, 10.0, 75.0, 90.0, 95.0,99.0,99.90 };
+ double delay_criteria[NB_CRITERIA];
+
+ printf("\n");
+ printf("Camel Service Response Time (SRT) Statistics:\n");
+ printf("=================================================================================================\n");
+ printf("| Category | Measure | Min SRT | Max SRT | Avg SRT | Min frame | Max frame |\n");
+ printf("|-------------------------|---------|-----------|-----------|-----------|-----------|-----------|\n");
+
+ j=1;
+ printf("|%24s |%8u |%8.2f s |%8.2f s |%8.2f s |%10u |%10u |\n",
+ val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+ hs->stats[j].num,
+ nstime_to_sec(&(hs->stats[j].min)),
+ nstime_to_sec(&(hs->stats[j].max)),
+ get_average(&(hs->stats[j].tot),hs->stats[j].num)/1000.0,
+ hs->stats[j].min_num,
+ hs->stats[j].max_num
+ );
+ for(j=2; j<NB_CAMELSRT_CATEGORY; j++) {
+ if(hs->stats[j].num==0){
+ printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n",
+ val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+ 0, 0.0, 0.0, 0.0, 0, 0);
+ continue;
+ }
+
+ printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n",
+ val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+ hs->stats[j].num,
+ MIN(9999,nstime_to_msec(&(hs->stats[j].min))),
+ MIN(9999,nstime_to_msec(&(hs->stats[j].max))),
+ MIN(9999,get_average(&(hs->stats[j].tot),hs->stats[j].num)),
+ hs->stats[j].min_num,
+ hs->stats[j].max_num
+ );
+ } /* j category */
+
+ printf("=================================================================================================\n");
+ /*
+ * Display 95%
+ */
+
+ printf("| Category/Criteria |");
+ for(z=0; z<NB_CRITERIA; z++) printf("%7.2f%% |", criteria[z]);
+ printf("\n");
+
+ printf("|-------------------------|");
+ for(z=0; z<NB_CRITERIA; z++) printf("---------|");
+ printf("\n");
+ /* calculate the delay max to have a given number of messages (in percentage) */
+ for(j=2;j<NB_CAMELSRT_CATEGORY;j++) {
+
+ rtd_temp = &(hs->stats[j]);
+
+ if (hs->count[j]>0) {
+ /* Calculate the delay to answer to p% of the MS */
+ for(z=0; z<NB_CRITERIA; z++) {
+ iteration=0;
+ delay_max=(double)rtd_temp->max.secs*1000 +(double)rtd_temp->max.nsecs/1000000;
+ delay_min=(double)rtd_temp->min.secs*1000 +(double)rtd_temp->min.nsecs/1000000;
+ delay=delay_min;
+ delta=delay_max-delay_min;
+ while( (delta > 0.001) && (iteration < 10000) ) {
+ somme=0;
+ iteration++;
+
+ for(li=0;li<hs->count[j];li++) {
+ x=hs->delta_time[j][li].secs*1000
+ + (double)hs->delta_time[j][li].nsecs/1000000;
+ if (x <= delay) somme++;
+ }
+ if ( somme*100 > hs->count[j]*criteria[z] ) { /* trop grand */
+ delay_max=delay;
+ delay=(delay_max+delay_min)/2;
+ delta=delay_max-delay_min;
+ } else { /* trop petit */
+ delay_min=delay;
+ delay=(delay_max+delay_min)/2;
+ delta=delay_max-delay_min;
+ }
+ } /* while */
+ delay_criteria[z]=delay;
+ } /* z criteria */
+ /* Append the result to the table */
+ printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") );
+ for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", MIN(9999,delay_criteria[z]));
+ printf("\n");
+ } else { /* count */
+ printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") );
+ for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", 0.0);
+ printf("\n");
+ } /* count */
+ }/* j category */
+ printf("===========================");
+ for(z=0; z<NB_CRITERIA; z++) printf("==========");
+ printf("\n");
+}
+
+static void camelsrt_init(const char *optarg, void* userdata _U_)
+{
+ struct camelsrt_t *p_camelsrt;
+ GString *error_string;
+
+ p_camelsrt = g_malloc(sizeof(struct camelsrt_t));
+ if(!strncmp(optarg,"camel,srt,",9)){
+ p_camelsrt->filter=g_strdup(optarg+9);
+ } else {
+ p_camelsrt->filter=NULL;
+ }
+ camelsrt_reset(p_camelsrt);
+
+ error_string=register_tap_listener("CAMEL",
+ p_camelsrt,
+ p_camelsrt->filter,
+ 0,
+ NULL,
+ camelsrt_packet,
+ camelsrt_draw);
+
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(p_camelsrt->filter);
+ g_free(p_camelsrt);
+
+ fprintf(stderr, "tshark: Couldn't register camel,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ /*
+ * If we are using tshark, we have to display the stats, even if the stats are not persistent
+ * As the frame are proceeded in the chronological order, we do not need persistent stats
+ * Whereas, with wireshark, it is not possible to have the correct display, if the stats are
+ * not saved along the analyze
+ */
+ gtcap_StatSRT=TRUE;
+ gcamel_StatSRT=TRUE;
+}
+
+
+void /* Next line mandatory */
+register_tap_listener_camelsrt(void)
+{
+ register_stat_cmd_arg("camel,srt", camelsrt_init, NULL);
+}
diff --git a/ui/cli/tap-comparestat.c b/ui/cli/tap-comparestat.c
new file mode 100644
index 0000000000..81b063b2d9
--- /dev/null
+++ b/ui/cli/tap-comparestat.c
@@ -0,0 +1,583 @@
+/* tap-comparestat.c
+ * Compare two capture files
+ * Copyright 2008 Vincenzo Condoleo, Christophe Dirac, Reto Ruoss
+ * supported by HSR (Hochschule Rapperswil)
+ *
+ * $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 statistics about two merged capture files, to find packet loss,
+ * time delay, ip header checksum errors and order check to tshark.
+ * It's also detecting the matching regions of the different files.
+ *
+ * The packets are compared by the ip id. MAC or TTL is used to distinct the different files.
+ * It is only used by tshark and not wireshark
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include <epan/in_cksum.h>
+#include <epan/packet.h>
+#include <epan/tap.h>
+#include <epan/timestamp.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-ip.h>
+#include "timestats.h"
+
+
+/* For checksum */
+#define BYTES 8
+#define WRONG_CHKSUM 0
+
+#define MERGED_FILES 2
+
+#define TTL_SEARCH 5
+
+/* information which will be printed */
+typedef struct _for_print {
+ guint count;
+ guint16 cksum;
+ nstime_t predecessor_time;
+ struct _frame_info *partner;
+} for_print;
+
+/* each tracked packet */
+typedef struct _frame_info {
+ for_print *fp;
+ guint32 num;
+ guint16 id;
+ guint8 ip_ttl;
+ address dl_dst;
+ nstime_t abs_ts, zebra_time, delta;
+} frame_info;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _comparestat_t {
+ char *filter;
+ emem_tree_t *packet_tree, *ip_id_tree, *nr_tree;
+ address eth_dst, eth_src;
+ nstime_t zebra_time, current_time;
+ timestat_t stats;
+ GArray *ip_ttl_list;
+ gboolean last_hit;
+ guint32 start_ongoing_hits, stop_ongoing_hits, start_packet_nr_first, start_packet_nr_second, stop_packet_nr_first, stop_packet_nr_second;
+ guint32 first_file_amount, second_file_amount;
+} comparestat_t;
+
+
+/* to call directly _init */
+static gdouble compare_variance=0.0;
+static guint8 compare_start, compare_stop;
+static gboolean TTL_method=TRUE, ON_method=TRUE;
+
+/* This callback is never used by tshark but it is here for completeness. */
+static void
+comparestat_reset(void *dummy _U_)
+{
+}
+
+
+/* This callback is invoked whenever the tap system has seen a packet
+ * we might be interested in.
+ * function returns :
+ * 0: no updates, no need to call (*draw) later
+ * !0: state has changed, call (*draw) sometime later
+ */
+static int
+comparestat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *arg2)
+{
+ comparestat_t *cs=arg;
+ const ws_ip *ci=arg2;
+ frame_info *fInfo;
+ vec_t cksum_vec[3];
+ guint16 computed_cksum=0;
+
+ /* so this get filled, usually with the first frame */
+ if(cs->eth_dst.len==0) {
+ cs->eth_dst=pinfo->dl_dst;
+ cs->eth_src=pinfo->dl_src;
+ }
+
+ /* Set up the fields of the pseudo-header and create checksum */
+ cksum_vec[0].ptr=&ci->ip_v_hl;
+ cksum_vec[0].len=BYTES;
+ /* skip TTL */
+ cksum_vec[1].ptr=&ci->ip_p;
+ cksum_vec[1].len=1;
+ /* skip header checksum and ip's (because of NAT)*/
+ cksum_vec[2].ptr=ci->ip_dst.data;
+ cksum_vec[2].ptr=cksum_vec[2].ptr+ci->ip_dst.len;
+ /* dynamic computation */
+ cksum_vec[2].len=pinfo->iphdrlen-20;
+ computed_cksum=in_cksum(&cksum_vec[0], 3);
+
+ /* collect all packet infos */
+ fInfo=(frame_info*)se_alloc(sizeof(frame_info));
+ fInfo->fp=(for_print*)se_alloc(sizeof(for_print));
+ fInfo->fp->partner=NULL;
+ fInfo->fp->count=1;
+ fInfo->fp->cksum=computed_cksum;
+ fInfo->num=pinfo->fd->num;
+ fInfo->id=ci->ip_id;
+ fInfo->ip_ttl=ci->ip_ttl;
+ fInfo->dl_dst=pinfo->dl_dst;
+ fInfo->abs_ts=pinfo->fd->abs_ts;
+ /* clean memory */
+ nstime_set_zero(&fInfo->zebra_time);
+ nstime_set_zero(&fInfo->fp->predecessor_time);
+ se_tree_insert32(cs->packet_tree, pinfo->fd->num, fInfo);
+
+ return 1;
+}
+
+/* Find equal packets, same IP-Id, count them and make time statistics */
+static gboolean
+call_foreach_count_ip_id(gpointer value, gpointer arg)
+{
+ comparestat_t *cs=(comparestat_t*)arg;
+ frame_info *fInfo=(frame_info*)value, *fInfoTemp;
+ nstime_t delta;
+ guint i;
+
+ /* we only need one value out of pinfo we use a temp one */
+ packet_info *pinfo=(packet_info*)ep_alloc(sizeof(packet_info));
+ pinfo->fd=(frame_data*)ep_alloc(sizeof(frame_data));
+ pinfo->fd->num = fInfo->num;
+
+ fInfoTemp=se_tree_lookup32(cs->ip_id_tree, fInfo->id);
+ if(fInfoTemp==NULL){
+ /* Detect ongoing package loss */
+ if((cs->last_hit==FALSE)&&(cs->start_ongoing_hits>compare_start)&&(cs->stop_ongoing_hits<compare_stop)){
+ cs->stop_ongoing_hits++;
+ cs->stop_packet_nr_first=fInfo->num;
+ } else if(cs->stop_ongoing_hits<compare_stop){
+ cs->stop_ongoing_hits=0;
+ cs->stop_packet_nr_first=G_MAXINT32;
+ }
+ cs->last_hit=FALSE;
+
+ fInfo->fp->count=1;
+ se_tree_insert32(cs->ip_id_tree, fInfo->id, fInfo);
+ } else {
+ /* Detect ongoing package hits, special behavior if start is set to 0 */
+ if((cs->last_hit||(compare_start==0))&&(cs->start_ongoing_hits<compare_start||(compare_start==0))){
+ if((compare_start==0)&&(cs->start_ongoing_hits!=0)){
+ /* start from the first packet so allready set */
+ } else {
+ cs->start_ongoing_hits++;
+ /* Take the lower number */
+ cs->start_packet_nr_first=fInfoTemp->num;
+ cs->start_packet_nr_second=fInfo->num;
+ }
+ } else if(cs->start_ongoing_hits<compare_start){
+ cs->start_ongoing_hits=0;
+ cs->start_packet_nr_first=G_MAXINT32;
+ }
+ cs->last_hit=TRUE;
+
+ fInfo->fp->count=fInfoTemp->fp->count + 1;
+ if(fInfoTemp->fp->cksum!=fInfo->fp->cksum){
+ fInfo->fp->cksum=WRONG_CHKSUM;
+ fInfoTemp->fp->cksum=WRONG_CHKSUM;
+ }
+ /* Add partner */
+ fInfo->fp->partner=fInfoTemp;
+ /* Create time statistic */
+ if(fInfo->fp->count==MERGED_FILES){
+ nstime_delta(&delta, &fInfo->abs_ts, &fInfoTemp->abs_ts);
+ /* Set delta in both packets */
+ nstime_set_zero(&fInfoTemp->delta);
+ nstime_add(&fInfoTemp->delta, &delta);
+ nstime_set_zero(&fInfo->delta);
+ nstime_add(&fInfo->delta, &delta);
+ time_stat_update(&cs->stats, &delta, pinfo);
+ }
+ se_tree_insert32(cs->ip_id_tree, fInfo->id, fInfo);
+ }
+
+ /* collect TTL's */
+ if(TTL_method && (fInfo->num<TTL_SEARCH)){
+ for(i=0; i < cs->ip_ttl_list->len; i++){
+ if(g_array_index(cs->ip_ttl_list, guint8, i) == fInfo->ip_ttl){
+ return FALSE;
+ }
+ }
+ g_array_append_val(cs->ip_ttl_list, fInfo->ip_ttl);
+ }
+
+ return FALSE;
+}
+
+/*Create new numbering */
+static gboolean
+call_foreach_new_order(gpointer value, gpointer arg)
+{
+ comparestat_t *cs=(comparestat_t*)arg;
+ frame_info *fInfo=(frame_info*)value, *fInfoTemp;
+
+ /* overwrite Info column for new ordering */
+ fInfoTemp=se_tree_lookup32(cs->nr_tree, fInfo->id);
+ if(fInfoTemp==NULL){
+ if(TTL_method==FALSE){
+ if((ADDRESSES_EQUAL(&cs->eth_dst, &fInfo->dl_dst)) || (ADDRESSES_EQUAL(&cs->eth_src, &fInfo->dl_dst))){
+ se_tree_insert32(cs->nr_tree, fInfo->id, fInfo);
+ fInfo->zebra_time=cs->zebra_time;
+ cs->zebra_time.nsecs=cs->zebra_time.nsecs + MERGED_FILES;
+ } else {
+ cs->zebra_time.nsecs++;
+ se_tree_insert32(cs->nr_tree, fInfo->id, fInfo);
+ fInfo->zebra_time=cs->zebra_time;
+ cs->zebra_time.nsecs++;
+ }
+ } else {
+ if((g_array_index(cs->ip_ttl_list, guint8, 0)==fInfo->ip_ttl) || (g_array_index(cs->ip_ttl_list, guint8, 1)==fInfo->ip_ttl)){
+ se_tree_insert32(cs->nr_tree, fInfo->id, fInfo);
+ fInfo->zebra_time=cs->zebra_time;
+ cs->zebra_time.nsecs=cs->zebra_time.nsecs + MERGED_FILES;
+ } else {
+ cs->zebra_time.nsecs++;
+ se_tree_insert32(cs->nr_tree, fInfo->id, fInfo);
+ fInfo->zebra_time=cs->zebra_time;
+ cs->zebra_time.nsecs++;
+ }
+
+ }
+ } else {
+ if(TTL_method==FALSE){
+ if(((ADDRESSES_EQUAL(&cs->eth_dst, &fInfo->dl_dst)) || (ADDRESSES_EQUAL(&cs->eth_src, &fInfo->dl_dst)))&&(!fmod(fInfoTemp->zebra_time.nsecs,MERGED_FILES))){
+ fInfo->zebra_time.nsecs=fInfoTemp->zebra_time.nsecs;
+ } else {
+ fInfo->zebra_time.nsecs=fInfoTemp->zebra_time.nsecs+1;
+ }
+ } else {
+ if(((g_array_index(cs->ip_ttl_list, guint8, 0)==fInfo->ip_ttl) || (g_array_index(cs->ip_ttl_list, guint8, 1)==fInfo->ip_ttl))&&(!fmod(fInfoTemp->zebra_time.nsecs,MERGED_FILES))){
+ fInfo->zebra_time.nsecs=fInfoTemp->zebra_time.nsecs;
+ } else {
+ fInfo->zebra_time.nsecs=fInfoTemp->zebra_time.nsecs+1;
+ }
+ }
+ }
+
+ /* count packets of file */
+ if(fmod(fInfo->zebra_time.nsecs, MERGED_FILES)){
+ cs->first_file_amount++;
+ } else {
+ cs->second_file_amount++;
+ }
+
+ /* ordering */
+ if(!nstime_is_unset(&cs->current_time)){
+ fInfo->fp->predecessor_time.nsecs=cs->current_time.nsecs;
+ }
+
+ cs->current_time.nsecs=fInfo->zebra_time.nsecs;
+
+ return FALSE;
+}
+
+/* calculate scopes if not set yet */
+static gboolean
+call_foreach_merge_settings(gpointer value, gpointer arg)
+{
+ comparestat_t *cs=(comparestat_t*)arg;
+ frame_info *fInfo=(frame_info*)value, *fInfoTemp=NULL;
+ guint32 tot_packet_amount=cs->first_file_amount+cs->second_file_amount, swap;
+
+ if((fInfo->num==tot_packet_amount)&&(cs->stop_packet_nr_first!=G_MAXINT32)){
+ /* calculate missing stop number */
+ swap=cs->stop_packet_nr_first;
+ cs->stop_packet_nr_first=tot_packet_amount-cs->second_file_amount;;
+ cs->stop_packet_nr_second=swap;
+ }
+
+ if((fInfo->num==tot_packet_amount)&&(cs->stop_packet_nr_first==G_MAXINT32)&&(cs->start_packet_nr_first!=G_MAXINT32)){
+ fInfoTemp=se_tree_lookup32(cs->packet_tree, cs->start_packet_nr_first);
+ if(fInfoTemp==NULL){
+ printf("ERROR: start number not set correctly\n");
+ return FALSE;
+ }
+ if(fmod(fInfoTemp->zebra_time.nsecs, 2)){
+ /*first file*/
+ cs->stop_packet_nr_first=cs->start_packet_nr_first+abs(cs->second_file_amount-(cs->start_packet_nr_second-cs->first_file_amount));
+ if(cs->stop_packet_nr_first>(tot_packet_amount-cs->second_file_amount)){
+ cs->stop_packet_nr_first=tot_packet_amount-cs->second_file_amount;
+ }
+ /*this only happens if we have too many MAC's or TTL*/
+ if(cs->stop_packet_nr_first>cs->start_packet_nr_second){
+ cs->stop_packet_nr_first=cs->start_packet_nr_second-1;
+ }
+ fInfoTemp=se_tree_lookup32(cs->packet_tree, cs->stop_packet_nr_first);
+ while((fInfoTemp!=NULL)?fmod(!fInfoTemp->zebra_time.nsecs, 2):TRUE){
+ cs->stop_packet_nr_first--;
+ fInfoTemp=se_tree_lookup32(cs->packet_tree, cs->stop_packet_nr_first);
+ }
+ } else {
+ /*this only happens if we have too many MAC's or TTL*/
+ cs->stop_packet_nr_first=cs->first_file_amount+cs->start_packet_nr_first;
+ if(cs->stop_packet_nr_first>tot_packet_amount-cs->first_file_amount){
+ cs->stop_packet_nr_first=tot_packet_amount-cs->first_file_amount;
+ }
+ fInfoTemp=se_tree_lookup32(cs->packet_tree, cs->stop_packet_nr_first);
+ while((fInfoTemp!=NULL)?fmod(fInfoTemp->zebra_time.nsecs, 2):TRUE){
+ cs->stop_packet_nr_first--;
+ fInfoTemp=se_tree_lookup32(cs->packet_tree, cs->stop_packet_nr_first);
+ }
+ }
+ /* set second stop location */
+ cs->stop_packet_nr_second=cs->start_packet_nr_second+abs(cs->stop_packet_nr_first-cs->start_packet_nr_first);
+ if(cs->stop_packet_nr_second>tot_packet_amount){
+ cs->stop_packet_nr_second=tot_packet_amount;
+ }
+ }
+
+ /* no start found */
+ if(fInfo->num==tot_packet_amount&&compare_start!=0&&compare_stop!=0){
+ if(cs->start_packet_nr_first==G_MAXINT32){
+ printf("Start point couldn't be set, choose a lower compare start");
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+call_foreach_print_ip_tree(gpointer value, gpointer user_data)
+{
+ frame_info *fInfo=(frame_info*)value;
+ comparestat_t *cs=(comparestat_t*)user_data;
+ gdouble delta, average;
+ gboolean show_it=FALSE;
+
+ delta=fabs(get_average(&fInfo->delta,1));
+ average=fabs(get_average(&cs->stats.tot, cs->stats.num));
+
+ /* special case if both are set to zero ignore start and stop numbering */
+ if(compare_start!=0&&compare_stop!=0){
+ /* check out if packet is in searched scope */
+ if((cs->start_packet_nr_first<fInfo->num)&&(cs->stop_packet_nr_first>fInfo->num)){
+ show_it=TRUE;
+ } else {
+ /* so we won't miss the other file */
+ if((fInfo->num>cs->start_packet_nr_second)&&(fInfo->num<cs->stop_packet_nr_second)){
+ show_it=TRUE;
+ }
+ }
+ } else {
+ show_it=TRUE;
+ }
+
+ if(show_it){
+ if(fInfo->fp->count < MERGED_FILES){
+ printf("Packet id :%i, count:%i Problem:", fInfo->id, fInfo->fp->count);
+ printf("Packet lost\n");
+ }
+ if(fInfo->fp->count > MERGED_FILES){
+ printf("Packet id :%i, count:%i Problem:", fInfo->id, fInfo->fp->count);
+ printf("More than two packets\n");
+ if(fInfo->fp->cksum == WRONG_CHKSUM){
+ printf("Checksum error over IP header\n");
+ }
+ }
+ if(fInfo->fp->count == MERGED_FILES){
+ if(fInfo->fp->cksum == WRONG_CHKSUM){
+ printf("Packet id :%i, count:%i Problem:", fInfo->id, fInfo->fp->count);
+ printf("Checksum error over IP header\n");
+ if(((delta < (average-cs->stats.variance)) || (delta > (average+cs->stats.variance))) && (delta > 0.0) && (cs->stats.variance!=0)){
+ printf("Not arrived in time\n");
+ }
+ if((nstime_cmp(&fInfo->fp->predecessor_time, &fInfo->zebra_time)>0||nstime_cmp(&fInfo->fp->partner->fp->predecessor_time, &fInfo->fp->partner->zebra_time)>0) && (fInfo->zebra_time.nsecs!=MERGED_FILES) && ON_method){
+ printf("Not correct order\n");
+ }
+ } else if(((delta < (average-cs->stats.variance)) || (delta > (average+cs->stats.variance))) && (delta > 0.0) && (cs->stats.variance!=0)) {
+ printf("Packet id :%i, count:%i Problem:", fInfo->id, fInfo->fp->count);
+ printf("Package not arrived in time\n");
+ if((nstime_cmp(&fInfo->fp->predecessor_time, &fInfo->zebra_time)>0||nstime_cmp(&fInfo->fp->partner->fp->predecessor_time, &fInfo->fp->partner->zebra_time)>0) && fInfo->zebra_time.nsecs != MERGED_FILES && ON_method){
+ printf("Not correct order\n");
+ }
+ } else if((nstime_cmp(&fInfo->fp->predecessor_time, &fInfo->zebra_time)>0||nstime_cmp(&fInfo->fp->partner->fp->predecessor_time, &fInfo->fp->partner->zebra_time)>0) && fInfo->zebra_time.nsecs != MERGED_FILES && ON_method){
+ printf("Packet id :%i, count:%i Problem:", fInfo->id, fInfo->fp->count);
+ printf("Not correct order\n");
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/* This callback is used when tshark wants us to draw/update our
+ * data to the output device. Since this is tshark only output is
+ * stdout.
+ * TShark will only call this callback once, which is when tshark has
+ * finished reading all packets and exists.
+ * If used with wireshark this may be called any time, perhaps once every 3
+ * seconds or so.
+ * This function may even be called in parallell with (*reset) or (*draw)
+ * so make sure there are no races. The data in the rpcstat_t can thus change
+ * beneath us. Beware.
+ */
+static void
+comparestat_draw(void *prs)
+{
+ comparestat_t *cs=prs;
+ GString *filter_str = g_string_new("");
+ const gchar *statis_string;
+ guint32 first_file_amount, second_file_amount;
+
+ /* inital steps, clear all data before start*/
+ cs->zebra_time.secs=0;
+ cs->zebra_time.nsecs=1;
+ nstime_set_unset(&cs->current_time);
+ cs->ip_ttl_list=g_array_new(FALSE, FALSE, sizeof(guint8));
+ cs->last_hit=FALSE;
+ cs->start_ongoing_hits=0;
+ cs->stop_ongoing_hits=0;
+ cs->start_packet_nr_first=G_MAXINT32;
+ cs->start_packet_nr_second=G_MAXINT32;
+ cs->stop_packet_nr_first=G_MAXINT32;
+ cs->stop_packet_nr_second=G_MAXINT32;
+ cs->first_file_amount=0;
+ cs->second_file_amount=0;
+
+ time_stat_init(&cs->stats);
+ /* not using g_free, because struct is managed by binarytrees */
+ cs->ip_id_tree=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "ip_id_tree");
+ emem_tree_foreach(cs->packet_tree, call_foreach_count_ip_id, cs);
+
+ /* set up TTL choice if only one number found */
+ if(TTL_method&&cs->ip_ttl_list->len==1){
+ g_array_append_val(cs->ip_ttl_list, g_array_index(cs->ip_ttl_list, guint8, 1));
+ }
+
+ emem_tree_foreach(cs->packet_tree, call_foreach_new_order,cs);
+ emem_tree_foreach(cs->packet_tree, call_foreach_merge_settings, cs);
+
+ /* remembering file amounts */
+ first_file_amount=cs->first_file_amount;
+ second_file_amount=cs->second_file_amount;
+ /* reset after numbering */
+ cs->nr_tree=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "nr_tree");
+
+ /* Variance */
+ cs->stats.variance=compare_variance;
+
+ /* add statistic string */
+ statis_string=g_strdup_printf("Compare Statistics: \nFilter: %s\nNumber of packets total:%i 1st file:%i, 2nd file:%i\nScopes:\t start:%i stop:%i\nand:\t start:%i stop:%i\nEqual packets: %i \nAllowed variation: %f \nAverage time difference: %f\n", cs->filter ? cs->filter : "", (first_file_amount+second_file_amount), first_file_amount, second_file_amount, cs->start_packet_nr_first, cs->stop_packet_nr_first, cs->start_packet_nr_second, cs->stop_packet_nr_second, cs->stats.num, cs->stats.variance, fabs(get_average(&cs->stats.tot, cs->stats.num)));
+
+ printf("\n");
+ printf("===================================================================\n");
+ printf("%s", statis_string);
+ emem_tree_foreach(cs->ip_id_tree, call_foreach_print_ip_tree, cs);
+ printf("===================================================================\n");
+ g_string_free(filter_str, TRUE);
+ g_array_free(cs->ip_ttl_list, TRUE);
+}
+
+/* When called, this function will create a new instance of comparestat.
+ * This function is called from tshark when it parses the -z compare, arguments
+ * and it creates a new instance to store statistics in and registers this
+ * new instance for the compare tap.
+ */
+static void
+comparestat_init(const char *optarg, void* userdata _U_)
+{
+ comparestat_t *cs;
+ const char *filter=NULL;
+ GString *error_string;
+ gint start, stop,ttl, order, pos=0;
+ gdouble variance;
+
+ if(sscanf(optarg,"compare,%d,%d,%d,%d,%lf%n",&start, &stop, &ttl, &order, &variance, &pos)==5){
+ if(pos){
+ if(*(optarg+pos)==',')
+ filter=optarg+pos+1;
+ else
+ filter=optarg+pos;
+ } else {
+ filter=NULL;
+ }
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z compare,<start>,<stop>,<ttl[0|1]>,<order[0|1]>,<variance>[,<filter>]\" argument\n");
+ exit(1);
+ }
+
+ compare_variance=variance;
+ compare_start=start;
+ compare_stop=stop;
+ TTL_method=ttl;
+ ON_method=order;
+
+ cs=g_malloc(sizeof(comparestat_t));
+ nstime_set_unset(&cs->current_time);
+ cs->ip_ttl_list=g_array_new(FALSE, FALSE, sizeof(guint8));
+ cs->last_hit=FALSE;
+ cs->start_ongoing_hits=0;
+ cs->stop_ongoing_hits=0;
+ cs->start_packet_nr_first=G_MAXINT32;
+ cs->start_packet_nr_second=G_MAXINT32;
+ cs->stop_packet_nr_first=G_MAXINT32;
+ cs->stop_packet_nr_second=G_MAXINT32;
+ cs->first_file_amount=0;
+ cs->second_file_amount=0;
+
+ cs->zebra_time.secs=0;
+ cs->zebra_time.nsecs=1;
+ cs->nr_tree=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "nr_tree");
+ /* microsecond precision */
+ timestamp_set_precision(TS_PREC_AUTO_NSEC);
+
+ if(filter){
+ cs->filter=g_strdup(filter);
+ } else {
+ cs->filter=NULL;
+ }
+
+ /* create a Hash to count the packets with the same ip.id */
+ cs->packet_tree=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "Packet_info_tree");
+
+ error_string=register_tap_listener("ip", cs, filter, 0, comparestat_reset, comparestat_packet, comparestat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(cs->filter);
+ g_free(cs);
+
+ fprintf(stderr, "tshark: Couldn't register compare tap: %s\n", error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_comparestat(void)
+{
+ register_stat_cmd_arg("compare,", comparestat_init,NULL);
+}
diff --git a/ui/cli/tap-dcerpcstat.c b/ui/cli/tap-dcerpcstat.c
new file mode 100644
index 0000000000..5fea8fc085
--- /dev/null
+++ b/ui/cli/tap-dcerpcstat.c
@@ -0,0 +1,300 @@
+/* tap-dcerpcstat.c
+ * dcerpcstat 2002 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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-dcerpc.h>
+
+#define MICROSECS_PER_SEC 1000000
+#define NANOSECS_PER_SEC 1000000000
+
+/* used to keep track of statistics for a specific procedure */
+typedef struct _rpc_procedure_t {
+ const char *proc;
+ int num;
+ nstime_t min;
+ nstime_t max;
+ nstime_t tot;
+} rpc_procedure_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _rpcstat_t {
+ const char *prog;
+ char *filter;
+ e_uuid_t uuid;
+ guint16 ver;
+ guint32 num_procedures;
+ rpc_procedure_t *procedures;
+} rpcstat_t;
+
+
+
+static int
+dcerpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ const dcerpc_info *ri=pri;
+ rpcstat_t *rs=prs;
+ nstime_t delta;
+ rpc_procedure_t *rp;
+
+ if(!ri->call_data){
+ return 0;
+ }
+ if(!ri->call_data->req_frame){
+ /* we have not seen the request so we dont know the delta*/
+ return 0;
+ }
+ if(ri->call_data->opnum>=rs->num_procedures){
+ /* dont handle this since its outside of known table */
+ return 0;
+ }
+
+ /* we are only interested in reply packets */
+ if(ri->ptype != PDU_RESP){
+ return 0;
+ }
+
+ /* we are only interested in certain program/versions */
+ if( (ri->call_data->uuid.Data1!=rs->uuid.Data1)
+ ||(ri->call_data->uuid.Data2!=rs->uuid.Data2)
+ ||(ri->call_data->uuid.Data3!=rs->uuid.Data3)
+ ||(ri->call_data->uuid.Data4[0]!=rs->uuid.Data4[0])
+ ||(ri->call_data->uuid.Data4[1]!=rs->uuid.Data4[1])
+ ||(ri->call_data->uuid.Data4[2]!=rs->uuid.Data4[2])
+ ||(ri->call_data->uuid.Data4[3]!=rs->uuid.Data4[3])
+ ||(ri->call_data->uuid.Data4[4]!=rs->uuid.Data4[4])
+ ||(ri->call_data->uuid.Data4[5]!=rs->uuid.Data4[5])
+ ||(ri->call_data->uuid.Data4[6]!=rs->uuid.Data4[6])
+ ||(ri->call_data->uuid.Data4[7]!=rs->uuid.Data4[7])
+ ||(ri->call_data->ver!=rs->ver)){
+ return 0;
+ }
+
+ rp=&(rs->procedures[ri->call_data->opnum]);
+
+ /* calculate time delta between request and reply */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->call_data->req_time);
+
+ if(rp->num==0){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ if(rp->num==0){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs<rp->min.secs)
+ ||( (delta.secs==rp->min.secs)
+ &&(delta.nsecs<rp->min.nsecs) ) ){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs>rp->max.secs)
+ ||( (delta.secs==rp->max.secs)
+ &&(delta.nsecs>rp->max.nsecs) ) ){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ rp->tot.secs += delta.secs;
+ rp->tot.nsecs += delta.nsecs;
+ if(rp->tot.nsecs > NANOSECS_PER_SEC){
+ rp->tot.nsecs -= NANOSECS_PER_SEC;
+ rp->tot.secs++;
+ }
+
+ rp->num++;
+
+ return 1;
+}
+
+static void
+dcerpcstat_draw(void *prs)
+{
+ rpcstat_t *rs=prs;
+ guint32 i;
+ guint64 td;
+ printf("\n");
+ printf("=======================================================================\n");
+ printf("%s Major Version %u SRT Statistics:\n", rs->prog, rs->ver);
+ printf("Filter: %s\n",rs->filter?rs->filter:"");
+ printf("Procedure Calls Min SRT Max SRT Avg SRT\n");
+
+ for(i=0;i<rs->num_procedures;i++){
+ /* Only display procs with non-zero calls */
+ if(rs->procedures[i].num==0){
+ continue;
+ }
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
+ td = ((td / rs->procedures[i].num) + 500) / 1000;
+
+ printf("%-31s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ rs->procedures[i].proc,
+ rs->procedures[i].num,
+ (int)(rs->procedures[i].min.secs),(rs->procedures[i].min.nsecs+500)/1000,
+ (int)(rs->procedures[i].max.secs),(rs->procedures[i].max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+ printf("=======================================================================\n");
+}
+
+
+
+static void
+dcerpcstat_init(const char *optarg, void* userdata _U_)
+{
+ rpcstat_t *rs;
+ guint32 i, max_procs;
+ dcerpc_sub_dissector *procs;
+ e_uuid_t uuid;
+ guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
+ int major, minor;
+ guint16 ver;
+ int pos=0;
+ const char *filter=NULL;
+ GString *error_string;
+
+ /*
+ * XXX - DCE RPC statistics are maintained only by major version,
+ * not by major and minor version, so the minor version number is
+ * ignored.
+ *
+ * Should we just stop supporting minor version numbers here?
+ * Or should we allow it to be omitted? Or should we keep
+ * separate statistics for different minor version numbers,
+ * and allow the minor version number to be omitted, and
+ * report aggregate statistics for all minor version numbers
+ * if it's omitted?
+ */
+ if(sscanf(optarg,
+ "dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
+ &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,
+ &major,&minor,&pos)==13){
+ uuid.Data1=d1;
+ uuid.Data2=d2;
+ uuid.Data3=d3;
+ uuid.Data4[0]=d40;
+ uuid.Data4[1]=d41;
+ uuid.Data4[2]=d42;
+ uuid.Data4[3]=d43;
+ uuid.Data4[4]=d44;
+ uuid.Data4[5]=d45;
+ uuid.Data4[6]=d46;
+ uuid.Data4[7]=d47;
+ if(pos){
+ filter=optarg+pos;
+ } else {
+ filter=NULL;
+ }
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
+ exit(1);
+ }
+ if (major < 0 || major > 65535) {
+ fprintf(stderr,"tshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535\n", major);
+ exit(1);
+ }
+ if (minor < 0 || minor > 65535) {
+ fprintf(stderr,"tshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535\n", minor);
+ exit(1);
+ }
+ ver = major;
+
+ rs=g_malloc(sizeof(rpcstat_t));
+ rs->prog=dcerpc_get_proto_name(&uuid, ver);
+ if(!rs->prog){
+ g_free(rs);
+ fprintf(stderr,"tshark: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%u not supported\n",uuid.Data1,uuid.Data2,uuid.Data3,uuid.Data4[0],uuid.Data4[1],uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],uuid.Data4[5],uuid.Data4[6],uuid.Data4[7],ver);
+ exit(1);
+ }
+ procs=dcerpc_get_proto_sub_dissector(&uuid, ver);
+ rs->uuid=uuid;
+ rs->ver=ver;
+
+ if(filter){
+ rs->filter=g_strdup(filter);
+ } else {
+ rs->filter=NULL;
+ }
+
+ for(i=0,max_procs=0;procs[i].name;i++){
+ if(procs[i].num>max_procs){
+ max_procs=procs[i].num;
+ }
+ }
+ rs->num_procedures=max_procs+1;
+ rs->procedures=g_malloc(sizeof(rpc_procedure_t)*(rs->num_procedures+1));
+ for(i=0;i<rs->num_procedures;i++){
+ int j;
+ rs->procedures[i].proc="unknown";
+ for(j=0;procs[j].name;j++){
+ if(procs[j].num==i){
+ rs->procedures[i].proc=procs[j].name;
+ }
+ }
+ rs->procedures[i].num=0;
+ rs->procedures[i].min.secs=0;
+ rs->procedures[i].min.nsecs=0;
+ rs->procedures[i].max.secs=0;
+ rs->procedures[i].max.nsecs=0;
+ rs->procedures[i].tot.secs=0;
+ rs->procedures[i].tot.nsecs=0;
+ }
+
+ error_string=register_tap_listener("dcerpc", rs, filter, 0, NULL, dcerpcstat_packet, dcerpcstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(rs->procedures);
+ g_free(rs->filter);
+ g_free(rs);
+
+ fprintf(stderr, "tshark: Couldn't register dcerpc,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+void
+register_tap_listener_dcerpcstat(void)
+{
+ register_stat_cmd_arg("dcerpc,srt,", dcerpcstat_init,NULL);
+}
diff --git a/ui/cli/tap-diameter-avp.c b/ui/cli/tap-diameter-avp.c
new file mode 100644
index 0000000000..002167c31f
--- /dev/null
+++ b/ui/cli/tap-diameter-avp.c
@@ -0,0 +1,286 @@
+/* tap-diameter-avp.c
+ * Copyright 2010 Andrej Kuehnal <andrejk@freenet.de>
+ *
+ * $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 TAP enables extraction of most important diameter fields in text format.
+ * - much more performance than -T text and -T pdml
+ * - more powerfull than -T field and -z proto,colinfo
+ * - exacltly one text line per diameter message
+ * - multiple diameter messages in one frame supported
+ * E.g. one device watchdog answer and two credit control answers
+ * in one TCP packet produces 3 text lines.
+ * - several fields with same name within one diameter message supported
+ * E.g. Multiple AVP(444) Subscription-Id-Data once with IMSI once with MSISDN
+ * - several grouped AVPs supported
+ * E.g. Zero or more Multiple-Services-Credit-Control AVPs(456)
+ */
+
+#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/epan_dissect.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include "epan/nstime.h"
+#include "epan/ftypes/ftypes.h"
+#include "epan/to_str.h"
+#include "epan/dissectors/packet-diameter.h"
+
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _diameteravp_t {
+ guint32 frame;
+ guint32 diammsg_toprocess;
+ guint32 cmd_code;
+ guint32 req_count;
+ guint32 ans_count;
+ guint32 paired_ans_count;
+ gchar* filter;
+} diameteravp_t;
+
+/* Copied from proto.c */
+static gboolean
+tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func, gpointer data)
+{
+ proto_node *pnode = tree;
+ proto_node *child;
+ proto_node *current;
+
+ if (func(pnode, data))
+ return TRUE;
+
+ child = pnode->first_child;
+ while (child != NULL) {
+ current = child;
+ child = current->next;
+ if (tree_traverse_pre_order((proto_tree *)current, func, data))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+diam_tree_to_csv(proto_node* node, gpointer data)
+{
+ char* val_str=NULL;
+ char* val_tmp=NULL;
+ ftenum_t ftype;
+ field_info* fi;
+ header_field_info *hfi;
+ if(!node) {
+ fprintf(stderr,"traverse end: empty node. node='%p' data='%p'\n",node,data);
+ return FALSE;
+ }
+ fi=node->finfo;
+ hfi=fi ? fi->hfinfo : NULL;
+ if(!hfi) {
+ fprintf(stderr,"traverse end: hfi not found. node='%p'\n",node);
+ return FALSE;
+ }
+ ftype=fi->value.ftype->ftype;
+ if (ftype!=FT_NONE&&ftype!=FT_PROTOCOL) {
+ /* convert value to string */
+ if(fi->value.ftype->val_to_string_repr)
+ {
+ val_tmp=fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL);
+ if(val_tmp)
+ {
+ val_str=ep_strdup(val_tmp);
+ g_free(val_tmp);
+ }
+ }
+ if(!val_str)
+ val_str=ep_strdup_printf("unsupported type: %s",ftype_name(ftype));
+
+ /*printf("traverse: name='%s', abbrev='%s',desc='%s', val='%s'\n",hfi->name,hfi->abbrev,ftype_name(hfi->type),val_str);*/
+ printf("%s='%s' ",hfi->name,val_str);
+ }
+ return FALSE;
+}
+
+static int
+diameteravp_packet(void *pds, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pdi)
+{
+ int ret = 0;
+ double resp_time=0.;
+ gboolean is_request=TRUE;
+ guint32 cmd_code=0;
+ guint32 req_frame=0;
+ guint32 ans_frame=0;
+ guint32 diam_child_node=0;
+ proto_node* current=NULL;
+ proto_node* node = NULL;
+ header_field_info* hfi=NULL;
+ field_info* finfo=NULL;
+ const diameter_req_ans_pair_t* dp=pdi;
+ diameteravp_t *ds=NULL;
+
+ /* Validate paramerers. */
+ if(!dp || !edt || !edt->tree)
+ return ret;
+
+ /* Several diameter messages within one frame are possible. *
+ * Check if we processing the message in same frame like befor or in new frame.*/
+ ds=(diameteravp_t *)pds;
+ if(pinfo->fd->num > ds->frame) {
+ ds->frame=pinfo->fd->num;
+ ds->diammsg_toprocess=0;
+ } else {
+ ds->diammsg_toprocess+=1;
+ }
+
+ /* Extract data from request/answer pair provided by diameter dissector.*/
+ is_request=dp->processing_request;
+ cmd_code=dp->cmd_code;
+ req_frame=dp->req_frame;
+ ans_frame=dp->ans_frame;
+ if(!is_request) {
+ nstime_t ns;
+ nstime_delta(&ns, &pinfo->fd->abs_ts, &dp->req_time);
+ resp_time=nstime_to_sec(&ns);
+ resp_time=resp_time<0?0.:resp_time;
+ }
+
+ /* Check command code provided by command line option.*/
+ if (ds->cmd_code && ds->cmd_code!=cmd_code)
+ return ret;
+
+ /* Loop over top level nodes */
+ node = edt->tree->first_child;
+ while (node != NULL) {
+ current = node;
+ node = current->next;
+ finfo=current->finfo;
+ hfi=finfo ? finfo->hfinfo : NULL;
+ /*fprintf(stderr,"DEBUG: diameteravp_packet %d %p %p node=%p abbrev=%s\n",cmd_code,edt,edt->tree,current,hfi->abbrev);*/
+ /* process current diameter subtree in the current frame. */
+ if(hfi && hfi->abbrev && strcmp(hfi->abbrev,"diameter")==0) {
+ /* Process current diameter message in the frame */
+ if (ds->diammsg_toprocess==diam_child_node) {
+ if(is_request) {
+ ds->req_count++;
+ } else {
+ ds->ans_count++;
+ if (req_frame>0)
+ ds->paired_ans_count++;
+ }
+ /* Output frame data.*/
+ printf("frame='%d' time='%f' src='%s' srcport='%d' dst='%s' dstport='%d' proto='diameter' msgnr='%d' is_request='%d' cmd='%d' req_frame='%d' ans_frame='%d' resp_time='%f' ",
+ pinfo->fd->num,nstime_to_sec(&pinfo->fd->abs_ts),ep_address_to_str(&pinfo->src),pinfo->srcport,ep_address_to_str(&pinfo->dst), pinfo->destport,ds->diammsg_toprocess,is_request,cmd_code,req_frame,ans_frame,resp_time);
+ /* Visit selected nodes of one diameter message.*/
+ tree_traverse_pre_order(current, diam_tree_to_csv, &ds);
+ /* End of message.*/
+ printf("\n");
+ /*printf("hfi: name='%s', msg_curr='%d' abbrev='%s',type='%s'\n",hfi->name,diam_child_node,hfi->abbrev,ftype_name(hfi->type));*/
+ }
+ diam_child_node++;
+ }
+ }
+ return ret;
+}
+
+static void
+diameteravp_draw(void* pds)
+{
+ diameteravp_t *ds=(diameteravp_t *)pds;
+ /* printing results */
+ printf("=== Diameter Summary ===\nrequset count:\t%d\nanswer count:\t%d\nreq/ans pairs:\t%d\n",ds->req_count,ds->ans_count,ds->paired_ans_count);
+}
+
+
+static void
+diameteravp_init(const char *optarg, void* userdata _U_)
+{
+ diameteravp_t *ds;
+ gchar* field=NULL;
+ gchar** tokens;
+ guint opt_count=0;
+ guint opt_idx=0;
+ GString* filter=NULL;
+ GString* error_string=NULL;
+
+ ds=g_malloc(sizeof(diameteravp_t));
+ ds->frame=0;
+ ds->diammsg_toprocess=0;
+ ds->cmd_code=0;
+ ds->req_count=0;
+ ds->ans_count=0;
+ ds->paired_ans_count=0;
+ ds->filter=NULL;
+
+ filter=g_string_new("diameter");
+
+ /* Split command line options. */
+ tokens = g_strsplit(optarg,",", 1024);
+ opt_count=0;
+ while (tokens[opt_count])
+ opt_count++;
+ if (opt_count>2)
+ ds->cmd_code=(guint32)atoi(tokens[2]);
+
+ /* Loop over diameter field names. */
+ for(opt_idx=3;opt_idx<opt_count;opt_idx++)
+ {
+ /* Current field from command line arguments. */
+ field=tokens[opt_idx];
+ /* Connect all requested fields with logical OR. */
+ g_string_append(filter,"||");
+ /* Prefix field name with "diameter." by default. */
+ if(!strchr(field,'.'))
+ g_string_append(filter, "diameter.");
+ /* Append field name to the filter. */
+ g_string_append(filter, field);
+ }
+ g_strfreev(tokens);
+ ds->filter=g_string_free(filter,FALSE);
+
+ error_string=register_tap_listener("diameter", ds, ds->filter, 0, NULL, diameteravp_packet, diameteravp_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ds);
+
+ fprintf(stderr, "tshark: Couldn't register diam,csv tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_diameteravp(void)
+{
+ register_stat_cmd_arg("diameter,avp", diameteravp_init, NULL);
+}
+
diff --git a/ui/cli/tap-expert.c b/ui/cli/tap-expert.c
new file mode 100644
index 0000000000..c32e93c97d
--- /dev/null
+++ b/ui/cli/tap-expert.c
@@ -0,0 +1,279 @@
+/* tap-expert.c
+ * Copyright 2011 Martin Mathieson
+ *
+ * $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.
+ */
+
+
+#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.h>
+#include <epan/packet_info.h>
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/expert.h>
+
+/* Tap data */
+typedef enum severity_level_t {
+ chat_level=0,
+ note_level,
+ warn_level,
+ error_level,
+ max_level
+} severity_level_t;
+
+/* This variable stores the lowest level that will be displayed.
+ May be changed from the command line */
+static severity_level_t lowest_report_level = chat_level;
+
+typedef struct expert_entry
+{
+ guint32 group;
+ const gchar *protocol;
+ gchar *summary;
+ int frequency;
+} expert_entry;
+
+
+/* Overall struct for storing all data seen */
+typedef struct expert_tapdata_t {
+ GArray *ei_array[max_level]; /* expert info items */
+ GStringChunk* text; /* for efficient storage of summary strings */
+} expert_tapdata_t;
+
+
+/* Reset expert stats */
+static void
+expert_stat_reset(void *tapdata)
+{
+ gint n;
+ expert_tapdata_t *etd = tapdata;
+
+ /* Free & reallocate chunk of strings */
+ g_string_chunk_free(etd->text);
+ etd->text = g_string_chunk_new(100);
+
+ /* Empty each of the arrays */
+ for (n=0; n < max_level; n++) {
+ g_array_set_size(etd->ei_array[n], 0);
+ }
+}
+
+/* Process stat struct for an expert frame */
+static int
+expert_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_,
+ const void *pointer)
+{
+ expert_info_t *ei = (expert_info_t *)pointer;
+ expert_tapdata_t *data = tapdata;
+ severity_level_t severity_level;
+ expert_entry tmp_entry;
+ expert_entry *entry;
+ guint n;
+
+ switch (ei->severity) {
+ case PI_CHAT:
+ severity_level = chat_level;
+ break;
+ case PI_NOTE:
+ severity_level = note_level;
+ break;
+ case PI_WARN:
+ severity_level = warn_level;
+ break;
+ case PI_ERROR:
+ severity_level = error_level;
+ break;
+ default:
+ g_assert_not_reached();
+ return 0;
+ }
+
+ /* Don't store details at a lesser severity than we are interested in */
+ if (severity_level < lowest_report_level) {
+ return 1;
+ }
+
+ /* If a duplicate just bump up frequency.
+ TODO: could make more efficient by avoiding linear search...*/
+ for (n=0; n < data->ei_array[severity_level]->len; n++) {
+ entry = &g_array_index(data->ei_array[severity_level], expert_entry, n);
+ if ((strcmp(ei->protocol, entry->protocol) == 0) &&
+ (strcmp(ei->summary, entry->summary) == 0)) {
+ entry->frequency++;
+ return 1;
+ }
+ }
+
+ /* Else Add new item to end of list for severity level */
+ g_array_append_val(data->ei_array[severity_level], tmp_entry);
+
+ /* Get pointer to newly-allocated item */
+ entry = &g_array_index(data->ei_array[severity_level], expert_entry,
+ data->ei_array[severity_level]->len - 1); /* ugly */
+ /* Copy/Store protocol and summary strings efficiently using GStringChunk */
+ entry->protocol = g_string_chunk_insert_const(data->text, ei->protocol);
+ entry->summary = g_string_chunk_insert_const(data->text, ei->summary);
+ entry->group = ei->group;
+ entry->frequency = 1;
+
+ return 1;
+}
+
+/* Output for all of the items of one severity */
+static void draw_items_for_severity(GArray *items, const gchar *label)
+{
+ guint n;
+ expert_entry *ei;
+ int total = 0;
+
+ /* Don't print title if no items */
+ if (items->len == 0) {
+ return;
+ }
+
+ /* Add frequencies together to get total */
+ for (n=0; n < items->len; n++) {
+ ei = &g_array_index(items, expert_entry, n);
+ total += ei->frequency;
+ }
+
+ /* Title */
+ printf("\n%s (%u)\n", label, total);
+ printf("=============\n");
+
+ /* Column headings */
+ printf(" Frequency Group Protocol Summary\n");
+
+ /* Items */
+ for (n=0; n < items->len; n++) {
+ ei = &g_array_index(items, expert_entry, n);
+ printf("%12u %10s %18s %s\n",
+ ei->frequency,
+ val_to_str(ei->group, expert_group_vals, "Unknown"),
+ ei->protocol, ei->summary);
+ }
+}
+
+/* (Re)draw expert stats */
+static void
+expert_stat_draw(void *phs _U_)
+{
+ /* Look up the statistics struct */
+ expert_tapdata_t *hs = (expert_tapdata_t *)phs;
+
+ draw_items_for_severity(hs->ei_array[error_level], "Errors");
+ draw_items_for_severity(hs->ei_array[warn_level], "Warns");
+ draw_items_for_severity(hs->ei_array[note_level], "Notes");
+ draw_items_for_severity(hs->ei_array[chat_level], "Chats");
+}
+
+/* Create a new expert stats struct */
+static void expert_stat_init(const char *optarg, void *userdata _U_)
+{
+ const char *args = NULL;
+ const char *filter = NULL;
+ GString *error_string;
+ expert_tapdata_t *hs;
+ int n;
+
+ /* Check for args. */
+ if (strncmp(optarg, "expert", 6) == 0) {
+ /* Skip those characters */
+ args = optarg + 6;
+ }
+ else {
+ /* No args. Will show all reports, with no filter */
+ lowest_report_level = max_level;
+ }
+
+ /* First (optional) arg is Error|Warn|Note|Chat */
+ if (args != NULL) {
+ if (g_ascii_strncasecmp(args, ",error", 6) == 0) {
+ lowest_report_level = error_level;
+ args += 6;
+ }
+ else if (g_ascii_strncasecmp(args, ",warn", 5) == 0) {
+ lowest_report_level = warn_level;
+ args += 5;
+ } else if (g_ascii_strncasecmp(args, ",note", 5) == 0) {
+ lowest_report_level = note_level;
+ args += 5;
+ } else if (g_ascii_strncasecmp(args, ",chat", 5) == 0) {
+ lowest_report_level = chat_level;
+ args += 5;
+ }
+ }
+
+ /* Second (optional) arg is a filter string */
+ if (args != NULL) {
+ if (args[0] == ',') {
+ filter = args+1;
+ }
+ }
+
+
+ /* Create top-level struct */
+ hs = g_malloc(sizeof(expert_tapdata_t));
+ memset(hs, 0, sizeof(expert_tapdata_t));
+
+ /* Allocate chunk of strings */
+ hs->text = g_string_chunk_new(100);
+
+ /* Allocate GArray for each severity level */
+ for (n=0; n < max_level; n++) {
+ hs->ei_array[n] = g_array_sized_new(FALSE, FALSE, sizeof(expert_info_t), 1000);
+ }
+
+ /**********************************************/
+ /* Register the tap listener */
+ /**********************************************/
+
+ error_string = register_tap_listener("expert", hs,
+ filter, 0,
+ expert_stat_reset,
+ expert_stat_packet,
+ expert_stat_draw);
+ if (error_string) {
+ printf("Expert tap error (%s)!\n", error_string->str);
+ g_string_free(error_string, TRUE);
+ g_free(hs);
+ exit(1);
+ }
+}
+
+
+/* Register this tap listener (need void on own so line register function found) */
+void
+register_tap_listener_expert_info(void)
+{
+ register_stat_cmd_arg("expert", expert_stat_init, NULL);
+}
+
diff --git a/ui/cli/tap-follow.c b/ui/cli/tap-follow.c
new file mode 100644
index 0000000000..2b4013cc53
--- /dev/null
+++ b/ui/cli/tap-follow.c
@@ -0,0 +1,869 @@
+/* tap-follow.c
+ *
+ * Copyright 2011, QA Cafe <info@qacafe.com>
+ *
+ * $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 udp and tcp follow stream capabilities to tshark.
+ * It is only used by tshark and not wireshark.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <epan/addr_resolv.h>
+#include <epan/epan_dissect.h>
+#include <epan/follow.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/tap.h>
+#include <epan/tvbuff-int.h>
+
+#include "wsutil/file_util.h"
+#include "tempfile.h"
+
+WS_VAR_IMPORT FILE *data_out_file;
+
+typedef enum
+{
+ type_TCP,
+ type_UDP
+} type_e;
+
+typedef enum
+{
+ mode_HEX,
+ mode_ASCII,
+ mode_RAW
+} mode_e;
+
+typedef struct
+{
+ type_e type;
+ mode_e mode;
+
+ /* filter */
+ guint32 index;
+ address addr[2];
+ int port[2];
+ guint8 addrBuf[2][16];
+
+ /* range */
+ guint32 chunkMin;
+ guint32 chunkMax;
+
+ /* stream chunk file */
+ FILE * filep;
+ gchar * filenamep;
+} follow_t;
+
+#define STR_FOLLOW "follow,"
+#define STR_FOLLOW_TCP STR_FOLLOW "tcp"
+#define STR_FOLLOW_UDP STR_FOLLOW "udp"
+
+#define STR_HEX ",hex"
+#define STR_ASCII ",ascii"
+#define STR_RAW ",raw"
+
+static void
+followExit(
+ const char * strp
+ )
+{
+ fprintf(stderr, "tshark: follow - %s\n", strp);
+ exit(1);
+}
+
+static const char *
+followStrType(
+ const follow_t * fp
+ )
+{
+ switch (fp->type)
+ {
+ case type_TCP: return "tcp";
+ case type_UDP: return "udp";
+ }
+
+ g_assert_not_reached();
+
+ return "<unknown-type>";
+}
+
+static const char *
+followStrMode(
+ const follow_t * fp
+ )
+{
+ switch (fp->mode)
+ {
+ case mode_HEX: return "hex";
+ case mode_ASCII: return "ascii";
+ case mode_RAW: return "raw";
+ }
+
+ g_assert_not_reached();
+
+ return "<unknown-mode>";
+}
+
+static const char *
+followStrFilter(
+ const follow_t * fp
+ )
+{
+ static char filter[512];
+ int len = 0;
+ const gchar * verp;
+ gchar ip0[MAX_IP6_STR_LEN];
+ gchar ip1[MAX_IP6_STR_LEN];
+
+ if (fp->index != G_MAXUINT32)
+ {
+ switch (fp->type)
+ {
+ case type_TCP:
+ len = g_snprintf(filter, sizeof filter,
+ "tcp.stream eq %d", fp->index);
+ break;
+ case type_UDP:
+ break;
+ }
+ }
+ else
+ {
+ verp = fp->addr[0].type == AT_IPv6 ? "v6" : "";
+ address_to_str_buf(&fp->addr[0], ip0, sizeof ip0);
+ address_to_str_buf(&fp->addr[1], ip1, sizeof ip1);
+
+ switch (fp->type)
+ {
+ case type_TCP:
+ len = g_snprintf(filter, sizeof filter,
+ "((ip%s.src eq %s and tcp.srcport eq %d) and "
+ "(ip%s.dst eq %s and tcp.dstport eq %d))"
+ " or "
+ "((ip%s.src eq %s and tcp.srcport eq %d) and "
+ "(ip%s.dst eq %s and tcp.dstport eq %d))",
+ verp, ip0, fp->port[0],
+ verp, ip1, fp->port[1],
+ verp, ip1, fp->port[1],
+ verp, ip0, fp->port[0]);
+ break;
+ case type_UDP:
+ len = g_snprintf(filter, sizeof filter,
+ "((ip%s.src eq %s and udp.srcport eq %d) and "
+ "(ip%s.dst eq %s and udp.dstport eq %d))"
+ " or "
+ "((ip%s.src eq %s and udp.srcport eq %d) and "
+ "(ip%s.dst eq %s and udp.dstport eq %d))",
+ verp, ip0, fp->port[0],
+ verp, ip1, fp->port[1],
+ verp, ip1, fp->port[1],
+ verp, ip0, fp->port[0]);
+ break;
+ }
+ }
+
+ if (len == 0)
+ {
+ followExit("Don't know how to create filter.");
+ }
+
+ if (len == sizeof filter)
+ {
+ followExit("Filter buffer overflow.");
+ }
+
+ return filter;
+}
+
+static void
+followFileClose(
+ follow_t * fp
+ )
+{
+ if (fp->filep != NULL)
+ {
+ fclose(fp->filep);
+ fp->filep = NULL;
+ if (fp->type == type_TCP)
+ {
+ data_out_file = NULL;
+ }
+ }
+
+ if (fp->filenamep != NULL)
+ {
+ ws_unlink(fp->filenamep);
+ g_free(fp->filenamep);
+ fp->filenamep = NULL;
+ }
+}
+
+static void
+followFileOpen(
+ follow_t * fp
+ )
+{
+ int fd;
+ char * tempfilep;
+
+ if (fp->type == type_TCP && data_out_file != NULL)
+ {
+ followExit("Only one TCP stream can be followed at a time.");
+ }
+
+ followFileClose(fp);
+
+ fd = create_tempfile(&tempfilep, "follow");
+ if (fd == -1)
+ {
+ followExit("Error creating temp file.");
+ }
+
+ fp->filenamep = g_strdup(tempfilep);
+ if (fp->filenamep == NULL)
+ {
+ ws_close(fd);
+ ws_unlink(tempfilep);
+ followExit("Error duping temp file name.");
+ }
+
+ fp->filep = fdopen(fd, "w+b");
+ if (fp->filep == NULL)
+ {
+ ws_close(fd);
+ ws_unlink(fp->filenamep);
+ g_free(fp->filenamep);
+ fp->filenamep = NULL;
+ followExit("Error opening temp file stream.");
+ }
+
+ if (fp->type == type_TCP)
+ {
+ data_out_file = fp->filep;
+ }
+}
+
+static follow_t *
+followAlloc(
+ type_e type
+ )
+{
+ follow_t * fp;
+
+ fp = g_malloc0(sizeof *fp);
+
+ fp->type = type;
+ SET_ADDRESS(&fp->addr[0], AT_NONE, 0, fp->addrBuf[0]);
+ SET_ADDRESS(&fp->addr[1], AT_NONE, 0, fp->addrBuf[1]);
+
+ return fp;
+}
+
+static void
+followFree(
+ follow_t * fp
+ )
+{
+ followFileClose(fp);
+ g_free(fp);
+}
+
+static int
+followPacket(
+ void * contextp,
+ packet_info * pip,
+ epan_dissect_t * edp _U_,
+ const void * datap
+ )
+{
+ follow_t * fp = contextp;
+ const tvbuff_t * tvbp = datap;
+ tcp_stream_chunk sc;
+ size_t size;
+
+ if (tvbp->length > 0)
+ {
+ memcpy(sc.src_addr, pip->net_src.data, pip->net_src.len);
+ sc.src_port = pip->srcport;
+ sc.dlen = tvbp->length;
+
+ size = fwrite(&sc, 1, sizeof sc, fp->filep);
+ if (sizeof sc != size)
+ {
+ followExit("Error writing stream chunk header.");
+ }
+
+ size = fwrite(tvbp->real_data, 1, sc.dlen, fp->filep);
+ if (sc.dlen != size)
+ {
+ followExit("Error writing stream chunk data.");
+ }
+ }
+
+ return 0;
+}
+
+#define BYTES_PER_LINE 16
+#define OFFSET_START 0
+#define OFFSET_LEN 8
+#define OFFSET_SPACE 2
+#define HEX_START (OFFSET_START + OFFSET_LEN + OFFSET_SPACE)
+#define HEX_LEN (BYTES_PER_LINE * 3) /* extra space at column 8 */
+#define HEX_SPACE 2
+#define ASCII_START (HEX_START + HEX_LEN + HEX_SPACE)
+#define ASCII_LEN (BYTES_PER_LINE + 1) /* extra space at column 8 */
+#define ASCII_SPACE 0
+#define LINE_LEN (ASCII_START + ASCII_LEN + ASCII_SPACE)
+
+static const char bin2hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+static void
+followPrintHex(
+ const char * prefixp,
+ guint32 offset,
+ void * datap,
+ int len
+ )
+{
+ int ii;
+ int jj;
+ int kk;
+ guint8 val;
+ char line[LINE_LEN + 1];
+
+ for (ii = 0, jj = 0, kk = 0; ii < len; )
+ {
+ if ((ii % BYTES_PER_LINE) == 0)
+ {
+ /* new line */
+ g_snprintf(line, LINE_LEN + 1, "%0*X", OFFSET_LEN, offset);
+ memset(line + HEX_START - OFFSET_SPACE, ' ',
+ HEX_LEN + OFFSET_SPACE + HEX_SPACE);
+
+ /* offset of hex */
+ jj = HEX_START;
+
+ /* offset of ascii */
+ kk = ASCII_START;
+ }
+
+ val = ((guint8 *)datap)[ii];
+
+ line[jj++] = bin2hex[val >> 4];
+ line[jj++] = bin2hex[val & 0xf];
+ jj++;
+
+ line[kk++] = val >= ' ' && val < 0x7f ? val : '.';
+
+ /* extra space at column 8 */
+ if (++ii % BYTES_PER_LINE == BYTES_PER_LINE/2)
+ {
+ line[jj++] = ' ';
+ line[kk++] = ' ';
+ }
+
+ if ((ii % BYTES_PER_LINE) == 0 || ii == len)
+ {
+ /* end of line or buffer */
+ if (line[kk - 1] == ' ')
+ {
+ kk--;
+ }
+ line[kk] = 0;
+ printf("%s%s\n", prefixp, line);
+ offset += BYTES_PER_LINE;
+ }
+ }
+}
+
+static void
+followDraw(
+ void * contextp
+ )
+{
+ static const char seperator[] =
+ "===================================================================\n";
+
+ follow_t * fp = contextp;
+ tcp_stream_chunk sc;
+ int node;
+ const address * addr[2];
+ int port[2];
+ gchar buf[MAX_IP6_STR_LEN];
+ guint32 ii;
+ guint32 jj;
+ guint32 len;
+ guint32 chunk;
+ guint32 offset[2];
+ guint8 bin[4096];
+ char data[(sizeof bin * 2) + 2];
+
+ g_assert(sizeof bin % BYTES_PER_LINE == 0);
+
+ if (fp->type == type_TCP)
+ {
+ follow_stats_t stats;
+ address_type type;
+ int len;
+
+ follow_stats(&stats);
+
+ if (stats.is_ipv6)
+ {
+ type = AT_IPv6;
+ len = 16;
+ }
+ else
+ {
+ type = AT_IPv4;
+ len = 4;
+ }
+
+ for (node = 0; node < 2; node++)
+ {
+ memcpy(fp->addrBuf[node], stats.ip_address[node], len);
+ SET_ADDRESS(&fp->addr[node], type, len, fp->addrBuf[node]);
+ fp->port[node] = stats.port[node];
+ }
+ }
+
+ /* find first stream chunk */
+ rewind(fp->filep);
+ for (chunk = 0;;)
+ {
+ len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
+ if (len != sizeof sc)
+ {
+ /* no data */
+ sc.dlen = 0;
+ memcpy(sc.src_addr, fp->addr[0].data, fp->addr[0].len) ;
+ sc.src_port = fp->port[0];
+ break;
+ }
+ if (sc.dlen > 0)
+ {
+ chunk++;
+ break;
+ }
+ }
+
+ /* node 0 is source of first chunk with data */
+ if (memcmp(sc.src_addr, fp->addr[0].data, fp->addr[0].len) == 0 &&
+ sc.src_port == fp->port[0])
+ {
+ addr[0] = &fp->addr[0];
+ port[0] = fp->port[0];
+ addr[1] = &fp->addr[1];
+ port[1] = fp->port[1];
+ }
+ else
+ {
+ addr[0] = &fp->addr[1];
+ port[0] = fp->port[1];
+ addr[1] = &fp->addr[0];
+ port[1] = fp->port[0];
+ }
+
+ printf("\n%s", seperator);
+ printf("Follow: %s,%s\n", followStrType(fp), followStrMode(fp));
+ printf("Filter: %s\n", followStrFilter(fp));
+
+ for (node = 0; node < 2; node++)
+ {
+ address_to_str_buf(addr[node], buf, sizeof buf);
+ if (addr[node]->type == AT_IPv6)
+ {
+ printf("Node %u: [%s]:%d\n", node, buf, port[node]);
+ }
+ else
+ {
+ printf("Node %u: %s:%d\n", node, buf, port[node]);
+ }
+ }
+
+ offset[0] = offset[1] = 0;
+
+ while (chunk <= fp->chunkMax)
+ {
+ node = (memcmp(addr[0]->data, sc.src_addr, addr[0]->len) == 0 &&
+ port[0] == sc.src_port) ? 0 : 1;
+
+ if (chunk < fp->chunkMin)
+ {
+ while (sc.dlen > 0)
+ {
+ len = sc.dlen < sizeof bin ? sc.dlen : sizeof bin;
+ sc.dlen -= len;
+ if (fread(bin, 1, len, fp->filep) != len)
+ {
+ followExit("Error reading stream chunk data.");
+ }
+ offset[node] += len;
+ }
+ }
+ else
+ {
+ switch (fp->mode)
+ {
+ case mode_HEX:
+ break;
+
+ case mode_ASCII:
+ printf("%s%d\n", node ? "\t" : "", sc.dlen);
+ break;
+
+ case mode_RAW:
+ if (node)
+ {
+ putchar('\t');
+ }
+ break;
+ }
+
+ while (sc.dlen > 0)
+ {
+ len = sc.dlen < sizeof bin ? sc.dlen : sizeof bin;
+ sc.dlen -= len;
+ if (fread(bin, 1, len, fp->filep) != len)
+ {
+ followExit("Error reading stream chunk data.");
+ }
+
+ switch (fp->mode)
+ {
+ case mode_HEX:
+ followPrintHex(node ? "\t" : "", offset[node], bin, len);
+ break;
+
+ case mode_ASCII:
+ for (ii = 0; ii < len; ii++)
+ {
+ switch (bin[ii])
+ {
+ case '\r':
+ case '\n':
+ data[ii] = bin[ii];
+ break;
+ default:
+ data[ii] = isprint(bin[ii]) ? bin[ii] : '.';
+ break;
+ }
+ }
+ if (sc.dlen == 0)
+ {
+ data[ii++] = '\n';
+ }
+ data[ii] = 0;
+ printf("%s", data);
+ break;
+
+ case mode_RAW:
+ for (ii = 0, jj = 0; ii < len; ii++)
+ {
+ data[jj++] = bin2hex[bin[ii] >> 4];
+ data[jj++] = bin2hex[bin[ii] & 0xf];
+ }
+ if (sc.dlen == 0)
+ {
+ data[jj++] = '\n';
+ }
+ data[jj] = 0;
+ printf("%s", data);
+ }
+
+ offset[node] += len;
+ }
+ }
+
+ for (;;)
+ {
+ len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
+ if (len != sizeof sc)
+ {
+ /* no more data */
+ sc.dlen = 0;
+ chunk = G_MAXUINT32;
+ goto done;
+ }
+ if (sc.dlen > 0)
+ {
+ chunk++;
+ break;
+ }
+ }
+ }
+
+done:
+
+ printf("%s", seperator);
+
+ followFileClose(fp);
+}
+
+static gboolean
+followArgStrncmp(
+ const char ** optargp,
+ const char * strp
+ )
+{
+ int len = (guint32)strlen(strp);
+
+ if (strncmp(*optargp, strp, len) == 0)
+ {
+ *optargp += len;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+followArgMode(
+ const char ** optargp,
+ follow_t * fp
+ )
+{
+ if (followArgStrncmp(optargp, STR_HEX))
+ {
+ fp->mode = mode_HEX;
+ }
+ else if (followArgStrncmp(optargp, STR_ASCII))
+ {
+ fp->mode = mode_ASCII;
+ }
+ else if (followArgStrncmp(optargp, STR_RAW))
+ {
+ fp->mode = mode_RAW;
+ }
+ else
+ {
+ followExit("Invalid display mode.");
+ }
+}
+
+static void
+followArgFilter(
+ const char ** optargp,
+ follow_t * fp
+ )
+{
+#define _STRING(s) # s
+#define STRING(s) _STRING(s)
+
+#define ADDR_CHARS 80
+#define ADDR_LEN (ADDR_CHARS + 1)
+#define ADDRv6_FMT ",[%" STRING(ADDR_CHARS) "[^]]]:%d%n"
+#define ADDRv4_FMT ",%" STRING(ADDR_CHARS) "[^:]:%d%n"
+
+ int len;
+ unsigned int ii;
+ char addr[ADDR_LEN];
+
+ if (sscanf(*optargp, ",%u%n", &fp->index, &len) == 1 &&
+ ((*optargp)[len] == 0 || (*optargp)[len] == ','))
+ {
+ *optargp += len;
+ }
+ else
+ {
+ for (ii = 0; ii < sizeof fp->addr/sizeof *fp->addr; ii++)
+ {
+ if ((sscanf(*optargp, ADDRv6_FMT, addr, &fp->port[ii], &len) != 2 &&
+ sscanf(*optargp, ADDRv4_FMT, addr, &fp->port[ii], &len) != 2) ||
+ fp->port[ii] <= 0 || fp->port[ii] > G_MAXUINT16)
+ {
+ followExit("Invalid address:port pair.");
+ }
+
+ if (strcmp("ip6", host_ip_af(addr)) == 0)
+ {
+ if (!get_host_ipaddr6(addr, (struct e_in6_addr *)fp->addrBuf[ii]))
+ {
+ followExit("Can't get IPv6 address");
+ }
+ SET_ADDRESS(&fp->addr[ii], AT_IPv6, 16, fp->addrBuf[ii]);
+ }
+ else
+ {
+ if (!get_host_ipaddr(addr, (guint32 *)fp->addrBuf[ii]))
+ {
+ followExit("Can't get IPv4 address");
+ }
+ SET_ADDRESS(&fp->addr[ii], AT_IPv4, 4, fp->addrBuf[ii]);
+ }
+
+ *optargp += len;
+ }
+
+ if (fp->addr[0].type != fp->addr[1].type)
+ {
+ followExit("Mismatched IP address types.");
+ }
+ fp->index = G_MAXUINT32;
+ }
+}
+
+static void
+followArgRange(
+ const char ** optargp,
+ follow_t * fp
+ )
+{
+ int len;
+
+ if (**optargp == 0)
+ {
+ fp->chunkMin = 1;
+ fp->chunkMax = G_MAXUINT32;
+ }
+ else
+ {
+ if (sscanf(*optargp, ",%u-%u%n", &fp->chunkMin, &fp->chunkMax, &len) == 2)
+ {
+ *optargp += len;
+ }
+ else if (sscanf(*optargp, ",%u%n", &fp->chunkMin, &len) == 1)
+ {
+ fp->chunkMax = fp->chunkMin;
+ *optargp += len;
+ }
+ else
+ {
+ followExit("Invalid range.");
+ }
+
+ if (fp->chunkMin < 1 || fp->chunkMin > fp->chunkMax)
+ {
+ followExit("Invalid range value.");
+ }
+ }
+}
+
+static void
+followArgDone(
+ const char * optarg
+ )
+{
+ if (*optarg != 0)
+ {
+ followExit("Invalid parameter.");
+ }
+}
+
+static void
+followTcp(
+ const char * optarg,
+ void * userdata _U_
+ )
+{
+ follow_t * fp;
+ GString * errp;
+
+ optarg += strlen(STR_FOLLOW_TCP);
+
+ fp = followAlloc(type_TCP);
+
+ followArgMode(&optarg, fp);
+ followArgFilter(&optarg, fp);
+ followArgRange(&optarg, fp);
+ followArgDone(optarg);
+
+ reset_tcp_reassembly();
+ if (fp->index != G_MAXUINT32)
+ {
+ if (!follow_tcp_index(fp->index))
+ {
+ followExit("Can't follow tcp index.");
+ }
+ }
+ else
+ {
+ if (!follow_tcp_addr(&fp->addr[0], fp->port[0],
+ &fp->addr[1], fp->port[1]))
+ {
+ followExit("Can't follow tcp address/port pairs.");
+ }
+ }
+
+ followFileOpen(fp);
+
+ errp = register_tap_listener("frame", fp, NULL, 0,
+ NULL, NULL, followDraw);
+ if (errp != NULL)
+ {
+ followFree(fp);
+ g_string_free(errp, TRUE);
+ followExit("Error registering tcp tap listner.");
+ }
+}
+
+static void
+followUdp(
+ const char * optarg,
+ void * userdata _U_
+ )
+{
+ follow_t * fp;
+ GString * errp;
+
+ optarg += strlen(STR_FOLLOW_UDP);
+
+ fp = followAlloc(type_UDP);
+
+ followArgMode(&optarg, fp);
+ followArgFilter(&optarg, fp);
+ followArgRange(&optarg, fp);
+ followArgDone(optarg);
+
+ if (fp->index != G_MAXUINT32)
+ {
+ followExit("UDP does not support index filters.");
+ }
+
+ followFileOpen(fp);
+
+ errp = register_tap_listener("udp_follow", fp, followStrFilter(fp), 0,
+ NULL, followPacket, followDraw);
+ if (errp != NULL)
+ {
+ followFree(fp);
+ g_string_free(errp, TRUE);
+ followExit("Error registering udp tap listner.");
+ }
+}
+
+void
+register_tap_listener_follow(void)
+{
+ register_stat_cmd_arg(STR_FOLLOW_TCP, followTcp, NULL);
+ register_stat_cmd_arg(STR_FOLLOW_UDP, followUdp, NULL);
+}
diff --git a/ui/cli/tap-funnel.c b/ui/cli/tap-funnel.c
new file mode 100644
index 0000000000..9fcd10ed33
--- /dev/null
+++ b/ui/cli/tap-funnel.c
@@ -0,0 +1,195 @@
+/*
+ * tap-funnel.c
+ *
+ * EPAN's GUI mini-API
+ *
+ * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <epan/funnel.h>
+#include <stdio.h>
+#include <epan/stat_cmd_args.h>
+
+
+struct _funnel_text_window_t {
+ gchar* title;
+ GString* text;
+};
+
+static GPtrArray* text_windows = NULL;
+
+static funnel_text_window_t* new_text_window(const gchar* title) {
+ funnel_text_window_t* tw = g_malloc(sizeof(funnel_text_window_t));
+ tw->title = g_strdup(title);
+ tw->text = g_string_new("");
+
+ if (!text_windows)
+ text_windows = g_ptr_array_new();
+
+ g_ptr_array_add(text_windows,tw);
+
+ return tw;
+}
+
+static void text_window_clear(funnel_text_window_t* tw) {
+ g_string_free(tw->text,TRUE);
+ tw->text = g_string_new("");
+}
+
+static void text_window_append(funnel_text_window_t* tw, const char *text ) {
+ g_string_append(tw->text,text);
+}
+
+static void text_window_set_text(funnel_text_window_t* tw, const char* text) {
+ g_string_free(tw->text,TRUE);
+ tw->text = g_string_new(text);
+}
+
+static void text_window_prepend(funnel_text_window_t* tw, const char *text) {
+ g_string_prepend(tw->text,text);
+}
+
+static const gchar* text_window_get_text(funnel_text_window_t* tw) {
+ return tw->text->str;
+}
+
+/* XXX: finish this */
+static void funnel_logger(const gchar *log_domain _U_,
+ GLogLevelFlags log_level _U_,
+ const gchar *message,
+ gpointer user_data _U_) {
+ fputs(message,stderr);
+}
+
+
+
+static const funnel_ops_t funnel_ops = {
+ new_text_window,
+ text_window_set_text,
+ text_window_append,
+ text_window_prepend,
+ text_window_clear,
+ text_window_get_text,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /*...,*/
+ NULL,
+ funnel_logger,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+void initialize_funnel_ops(void) {
+ funnel_set_funnel_ops(&funnel_ops);
+}
+
+
+void funnel_dump_all_text_windows(void) {
+ guint i;
+
+ if (!text_windows) return;
+
+ for ( i = 0 ; i < text_windows->len; i++) {
+ funnel_text_window_t* tw = g_ptr_array_index(text_windows,i);
+ printf("\n========================== %s "
+ "==========================\n%s\n",tw->title,tw->text->str);
+
+ g_ptr_array_remove_index(text_windows,i);
+ g_free(tw->title);
+ g_string_free(tw->text,TRUE);
+ g_free(tw);
+ }
+}
+
+#if 0
+
+GHashTable* menus = NULL;;
+typedef struct _menu_cb_t {
+ void (*callback)(gpointer);
+ void* callback_data;
+} menu_cb_t;
+
+
+static void init_funnel_cmd(const char *optarg, void* data ) {
+ gchar** args = g_strsplit(optarg,",",0);
+ gchar** arg;
+ menu_cb_t* mcb = data;
+
+ for(arg = args; *arg ; arg++) {
+ g_strstrip(*arg);
+ }
+
+ if (mcb->callback) {
+ mcb->callback(mcb->callback_data);
+ }
+
+}
+
+static void register_menu_cb(const char *name,
+ register_stat_group_t group _U_,
+ void (*callback)(gpointer),
+ gpointer callback_data,
+ gboolean retap _U_) {
+ menu_cb_t* mcb = g_malloc(sizeof(menu_cb_t));
+
+ mcb->callback = callback;
+ mcb->callback_data = callback_data;
+
+ if (!menus)
+ menus = g_hash_table_new(g_str_hash,g_str_equal);
+
+ g_hash_table_insert(menus,g_strdup(name),mcb);
+
+ register_stat_cmd_arg(name,init_funnel_cmd,mcb);
+}
+
+void initialize_funnel_ops(void) {
+ funnel_set_funnel_ops(&funnel_ops);
+}
+
+#endif
+void
+register_tap_listener_gtkfunnel(void)
+{
+#if 0
+ /* #if 0 at least since Revision Rev 17396 */
+ funnel_register_all_menus(register_menu_cb);
+#endif
+}
diff --git a/ui/cli/tap-gsm_astat.c b/ui/cli/tap-gsm_astat.c
new file mode 100644
index 0000000000..b84e377dfb
--- /dev/null
+++ b/ui/cli/tap-gsm_astat.c
@@ -0,0 +1,353 @@
+/* tap-gsm_astat.c
+ *
+ * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
+ * In association with Telos Technology Inc.
+ *
+ * $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 TAP provides statistics for the GSM A Interface:
+ */
+
+#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/value_string.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-bssap.h>
+#include <epan/dissectors/packet-gsm_a_common.h>
+
+
+typedef struct _gsm_a_stat_t {
+ int bssmap_message_type[0xff];
+ int dtap_mm_message_type[0xff];
+ int dtap_rr_message_type[0xff];
+ int dtap_cc_message_type[0xff];
+ int dtap_gmm_message_type[0xff];
+ int dtap_sms_message_type[0xff];
+ int dtap_sm_message_type[0xff];
+ int dtap_ss_message_type[0xff];
+ int dtap_tp_message_type[0xff];
+ int sacch_rr_message_type[0xff];
+} gsm_a_stat_t;
+
+
+static int
+gsm_a_stat_packet(
+ void *tapdata,
+ packet_info *pinfo _U_,
+ epan_dissect_t *edt _U_,
+ const void *data)
+{
+ gsm_a_stat_t *stat_p = tapdata;
+ const gsm_a_tap_rec_t *tap_p = data;
+
+ switch (tap_p->pdu_type)
+ {
+ case BSSAP_PDU_TYPE_BSSMAP:
+ stat_p->bssmap_message_type[tap_p->message_type]++;
+ break;
+
+ case BSSAP_PDU_TYPE_DTAP:
+ switch (tap_p->protocol_disc)
+ {
+ case PD_CC:
+ stat_p->dtap_cc_message_type[tap_p->message_type]++;
+ break;
+ case PD_MM:
+ stat_p->dtap_mm_message_type[tap_p->message_type]++;
+ break;
+ case PD_RR:
+ stat_p->dtap_rr_message_type[tap_p->message_type]++;
+ break;
+ case PD_GMM:
+ stat_p->dtap_gmm_message_type[tap_p->message_type]++;
+ break;
+ case PD_SMS:
+ stat_p->dtap_sms_message_type[tap_p->message_type]++;
+ break;
+ case PD_SM:
+ stat_p->dtap_sm_message_type[tap_p->message_type]++;
+ break;
+ case PD_SS:
+ stat_p->dtap_ss_message_type[tap_p->message_type]++;
+ break;
+ case PD_TP:
+ stat_p->dtap_tp_message_type[tap_p->message_type]++;
+ break;
+ default:
+ /*
+ * unsupported PD
+ */
+ return(0);
+ }
+ break;
+
+ case GSM_A_PDU_TYPE_SACCH:
+ switch (tap_p->protocol_disc)
+ {
+ case 0:
+ stat_p->sacch_rr_message_type[tap_p->message_type]++;
+ break;
+ default:
+ /* unknown Short PD */
+ break;
+ }
+ break;
+
+
+ default:
+ /*
+ * unknown PDU type !!!
+ */
+ return(0);
+ }
+
+ return(1);
+}
+
+
+static void
+gsm_a_stat_draw(
+ void *tapdata)
+{
+ gsm_a_stat_t *stat_p = tapdata;
+ guint8 i;
+
+
+ printf("\n");
+ printf("=========== GS=M A-i/f Statistics ============================\n");
+ printf("BSSMAP\n");
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_bssmap_msg_strings[i].strptr)
+ {
+ if (stat_p->bssmap_message_type[gsm_a_bssmap_msg_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_bssmap_msg_strings[i].value,
+ gsm_a_bssmap_msg_strings[i].strptr,
+ stat_p->bssmap_message_type[gsm_a_bssmap_msg_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_MM]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_mm_strings[i].strptr)
+ {
+ if (stat_p->dtap_mm_message_type[gsm_a_dtap_msg_mm_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_mm_strings[i].value,
+ gsm_a_dtap_msg_mm_strings[i].strptr,
+ stat_p->dtap_mm_message_type[gsm_a_dtap_msg_mm_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_RR]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_rr_strings[i].strptr)
+ {
+ if (stat_p->dtap_rr_message_type[gsm_a_dtap_msg_rr_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_rr_strings[i].value,
+ gsm_a_dtap_msg_rr_strings[i].strptr,
+ stat_p->dtap_rr_message_type[gsm_a_dtap_msg_rr_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_CC]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_cc_strings[i].strptr)
+ {
+ if (stat_p->dtap_cc_message_type[gsm_a_dtap_msg_cc_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_cc_strings[i].value,
+ gsm_a_dtap_msg_cc_strings[i].strptr,
+ stat_p->dtap_cc_message_type[gsm_a_dtap_msg_cc_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_GMM]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_gmm_strings[i].strptr)
+ {
+ if (stat_p->dtap_gmm_message_type[gsm_a_dtap_msg_gmm_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_gmm_strings[i].value,
+ gsm_a_dtap_msg_gmm_strings[i].strptr,
+ stat_p->dtap_gmm_message_type[gsm_a_dtap_msg_gmm_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_SMS]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_sms_strings[i].strptr)
+ {
+ if (stat_p->dtap_sms_message_type[gsm_a_dtap_msg_sms_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_sms_strings[i].value,
+ gsm_a_dtap_msg_sms_strings[i].strptr,
+ stat_p->dtap_sms_message_type[gsm_a_dtap_msg_sms_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_SM]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_sm_strings[i].strptr)
+ {
+ if (stat_p->dtap_sm_message_type[gsm_a_dtap_msg_sm_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_sm_strings[i].value,
+ gsm_a_dtap_msg_sm_strings[i].strptr,
+ stat_p->dtap_sm_message_type[gsm_a_dtap_msg_sm_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_SS]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_ss_strings[i].strptr)
+ {
+ if (stat_p->dtap_ss_message_type[gsm_a_dtap_msg_ss_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_ss_strings[i].value,
+ gsm_a_dtap_msg_ss_strings[i].strptr,
+ stat_p->dtap_ss_message_type[gsm_a_dtap_msg_ss_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nDTAP %s\n", gsm_a_pd_str[PD_TP]);
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_dtap_msg_tp_strings[i].strptr)
+ {
+ if (stat_p->dtap_tp_message_type[gsm_a_dtap_msg_tp_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_dtap_msg_tp_strings[i].value,
+ gsm_a_dtap_msg_tp_strings[i].strptr,
+ stat_p->dtap_tp_message_type[gsm_a_dtap_msg_tp_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("\nSACCH Radio Resources Management messages\n");
+ printf("Message (ID)Type Number\n");
+
+ i = 0;
+ while (gsm_a_rr_short_pd_msg_strings[i].strptr)
+ {
+ if (stat_p->sacch_rr_message_type[gsm_a_rr_short_pd_msg_strings[i].value] > 0)
+ {
+ printf("0x%02x %-50s%d\n",
+ gsm_a_rr_short_pd_msg_strings[i].value,
+ gsm_a_rr_short_pd_msg_strings[i].strptr,
+ stat_p->sacch_rr_message_type[gsm_a_rr_short_pd_msg_strings[i].value]);
+ }
+
+ i++;
+ }
+
+ printf("==============================================================\n");
+}
+
+
+static void
+gsm_a_stat_init(const char *optarg _U_,void* userdata _U_)
+{
+ gsm_a_stat_t *stat_p;
+ GString *err_p;
+
+ stat_p = g_malloc(sizeof(gsm_a_stat_t));
+
+ memset(stat_p, 0, sizeof(gsm_a_stat_t));
+
+ err_p =
+ register_tap_listener("gsm_a", stat_p, NULL, 0,
+ NULL,
+ gsm_a_stat_packet,
+ gsm_a_stat_draw);
+
+ if (err_p != NULL)
+ {
+ g_free(stat_p);
+ g_string_free(err_p, TRUE);
+
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_gsm_astat(void)
+{
+ register_stat_cmd_arg("gsm_a,", gsm_a_stat_init,NULL);
+}
diff --git a/ui/cli/tap-h225counter.c b/ui/cli/tap-h225counter.c
new file mode 100644
index 0000000000..6076f1c225
--- /dev/null
+++ b/ui/cli/tap-h225counter.c
@@ -0,0 +1,384 @@
+/* tap_h225counter.c
+ * h225 message counter for wireshark
+ * Copyright 2003 Lars Roland
+ *
+ * $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.
+ */
+
+#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.h"
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include <epan/dissectors/packet-h225.h>
+
+/* following values represent the size of their valuestring arrays */
+
+#define RAS_MSG_TYPES 33
+#define CS_MSG_TYPES 13
+
+#define GRJ_REASONS 8
+#define RRJ_REASONS 18
+#define URQ_REASONS 6
+#define URJ_REASONS 6
+#define ARJ_REASONS 22
+#define BRJ_REASONS 8
+#define DRQ_REASONS 3
+#define DRJ_REASONS 4
+#define LRJ_REASONS 16
+#define IRQNAK_REASONS 4
+#define REL_CMP_REASONS 26
+#define FACILITY_REASONS 11
+
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _h225counter_t {
+ char *filter;
+ guint32 ras_msg[RAS_MSG_TYPES + 1];
+ guint32 cs_msg[CS_MSG_TYPES + 1];
+ guint32 grj_reason[GRJ_REASONS + 1];
+ guint32 rrj_reason[RRJ_REASONS + 1];
+ guint32 urq_reason[URQ_REASONS + 1];
+ guint32 urj_reason[URJ_REASONS + 1];
+ guint32 arj_reason[ARJ_REASONS + 1];
+ guint32 brj_reason[BRJ_REASONS + 1];
+ guint32 drq_reason[DRQ_REASONS + 1];
+ guint32 drj_reason[DRJ_REASONS + 1];
+ guint32 lrj_reason[LRJ_REASONS + 1];
+ guint32 irqnak_reason[IRQNAK_REASONS + 1];
+ guint32 rel_cmp_reason[REL_CMP_REASONS + 1];
+ guint32 facility_reason[FACILITY_REASONS + 1];
+} h225counter_t;
+
+
+static void
+h225counter_reset(void *phs)
+{
+ h225counter_t *hs=(h225counter_t *)phs;
+ char *save_filter = hs->filter;
+
+ memset(hs, 0, sizeof(h225counter_t));
+
+ hs->filter = save_filter;
+}
+
+static int
+h225counter_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi)
+{
+ h225counter_t *hs=(h225counter_t *)phs;
+ const h225_packet_info *pi=phi;
+
+ switch (pi->msg_type) {
+
+ case H225_RAS:
+ if(pi->msg_tag==-1) { /* uninitialized */
+ return 0;
+ }
+ else if (pi->msg_tag >= RAS_MSG_TYPES) { /* unknown */
+ hs->ras_msg[RAS_MSG_TYPES]++;
+ }
+ else {
+ hs->ras_msg[pi->msg_tag]++;
+ }
+
+ /* Look for reason tag */
+ if(pi->reason==-1) { /* uninitialized */
+ break;
+ }
+
+ switch(pi->msg_tag) {
+
+ case 2: /* GRJ */
+ if(pi->reason < GRJ_REASONS)
+ hs->grj_reason[pi->reason]++;
+ else
+ hs->grj_reason[GRJ_REASONS]++;
+ break;
+ case 5: /* RRJ */
+ if(pi->reason < RRJ_REASONS)
+ hs->rrj_reason[pi->reason]++;
+ else
+ hs->rrj_reason[RRJ_REASONS]++;
+ break;
+ case 6: /* URQ */
+ if(pi->reason < URQ_REASONS)
+ hs->urq_reason[pi->reason]++;
+ else
+ hs->urq_reason[URQ_REASONS]++;
+ break;
+ case 8: /* URJ */
+ if(pi->reason < URJ_REASONS)
+ hs->urj_reason[pi->reason]++;
+ else
+ hs->urj_reason[URJ_REASONS]++;
+ break;
+ case 11: /* ARJ */
+ if(pi->reason < ARJ_REASONS)
+ hs->arj_reason[pi->reason]++;
+ else
+ hs->arj_reason[ARJ_REASONS]++;
+ break;
+ case 14: /* BRJ */
+ if(pi->reason < BRJ_REASONS)
+ hs->brj_reason[pi->reason]++;
+ else
+ hs->brj_reason[BRJ_REASONS]++;
+ break;
+ case 15: /* DRQ */
+ if(pi->reason < DRQ_REASONS)
+ hs->drq_reason[pi->reason]++;
+ else
+ hs->drq_reason[DRQ_REASONS]++;
+ break;
+ case 17: /* DRJ */
+ if(pi->reason < DRJ_REASONS)
+ hs->drj_reason[pi->reason]++;
+ else
+ hs->drj_reason[DRJ_REASONS]++;
+ break;
+ case 20: /* LRJ */
+ if(pi->reason < LRJ_REASONS)
+ hs->lrj_reason[pi->reason]++;
+ else
+ hs->lrj_reason[LRJ_REASONS]++;
+ break;
+ case 29: /* IRQ Nak */
+ if(pi->reason < IRQNAK_REASONS)
+ hs->irqnak_reason[pi->reason]++;
+ else
+ hs->irqnak_reason[IRQNAK_REASONS]++;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+
+ break;
+
+ case H225_CS:
+ if(pi->msg_tag==-1) { /* uninitialized */
+ return 0;
+ }
+ else if (pi->msg_tag >= CS_MSG_TYPES) { /* unknown */
+ hs->cs_msg[CS_MSG_TYPES]++;
+ }
+ else {
+ hs->cs_msg[pi->msg_tag]++;
+ }
+
+ /* Look for reason tag */
+ if(pi->reason==-1) { /* uninitialized */
+ break;
+ }
+
+ switch(pi->msg_tag) {
+
+ case 5: /* ReleaseComplete */
+ if(pi->reason < REL_CMP_REASONS)
+ hs->rel_cmp_reason[pi->reason]++;
+ else
+ hs->rel_cmp_reason[REL_CMP_REASONS]++;
+ break;
+ case 6: /* Facility */
+ if(pi->reason < FACILITY_REASONS)
+ hs->facility_reason[pi->reason]++;
+ else
+ hs->facility_reason[FACILITY_REASONS]++;
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void
+h225counter_draw(void *phs)
+{
+ h225counter_t *hs=(h225counter_t *)phs;
+ int i,j;
+
+ printf("================== H225 Message and Reason Counter ==================\n");
+ printf("RAS-Messages:\n");
+ for(i=0;i<=RAS_MSG_TYPES;i++) {
+ if(hs->ras_msg[i]!=0) {
+ printf(" %s : %u\n", val_to_str(i,h225_RasMessage_vals,"unknown ras-messages "), hs->ras_msg[i]);
+ /* reason counter */
+ switch(i) {
+ case 2: /* GRJ */
+ for(j=0;j<=GRJ_REASONS;j++) {
+ if(hs->grj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,GatekeeperRejectReason_vals,"unknown reason "), hs->grj_reason[j]);
+ }
+ }
+ break;
+ case 5: /* RRJ */
+ for(j=0;j<=RRJ_REASONS;j++) {
+ if(hs->rrj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,RegistrationRejectReason_vals,"unknown reason "), hs->rrj_reason[j]);
+ }
+ }
+ break;
+ case 6: /* URQ */
+ for(j=0;j<=URQ_REASONS;j++) {
+ if(hs->urq_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,UnregRequestReason_vals,"unknown reason "), hs->urq_reason[j]);
+ }
+ }
+ break;
+ case 8: /* URJ */
+ for(j=0;j<=URJ_REASONS;j++) {
+ if(hs->urj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,UnregRejectReason_vals,"unknown reason "), hs->urj_reason[j]);
+ }
+ }
+ break;
+ case 11: /* ARJ */
+ for(j=0;j<=ARJ_REASONS;j++) {
+ if(hs->arj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,AdmissionRejectReason_vals,"unknown reason "), hs->arj_reason[j]);
+ }
+ }
+ break;
+ case 14: /* BRJ */
+ for(j=0;j<=BRJ_REASONS;j++) {
+ if(hs->brj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,BandRejectReason_vals,"unknown reason "), hs->brj_reason[j]);
+ }
+ }
+ break;
+ case 15: /* DRQ */
+ for(j=0;j<=DRQ_REASONS;j++) {
+ if(hs->drq_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,DisengageReason_vals,"unknown reason "), hs->drq_reason[j]);
+ }
+ }
+ break;
+ case 17: /* DRJ */
+ for(j=0;j<=DRJ_REASONS;j++) {
+ if(hs->drj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,DisengageRejectReason_vals,"unknown reason "), hs->drj_reason[j]);
+ }
+ }
+ break;
+ case 20: /* LRJ */
+ for(j=0;j<=LRJ_REASONS;j++) {
+ if(hs->lrj_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,LocationRejectReason_vals,"unknown reason "), hs->lrj_reason[j]);
+ }
+ }
+ break;
+ case 29: /* IRQNak */
+ for(j=0;j<=IRQNAK_REASONS;j++) {
+ if(hs->irqnak_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,InfoRequestNakReason_vals,"unknown reason "), hs->irqnak_reason[j]);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ /* end of reason counter*/
+ }
+ }
+ printf("Call Signalling:\n");
+ for(i=0;i<=CS_MSG_TYPES;i++) {
+ if(hs->cs_msg[i]!=0) {
+ printf(" %s : %u\n", val_to_str(i,T_h323_message_body_vals,"unknown cs-messages "), hs->cs_msg[i]);
+ /* reason counter */
+ switch(i) {
+ case 5: /* ReleaseComplete */
+ for(j=0;j<=REL_CMP_REASONS;j++) {
+ if(hs->rel_cmp_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,h225_ReleaseCompleteReason_vals,"unknown reason "), hs->rel_cmp_reason[j]);
+ }
+ }
+ break;
+ case 6: /* Facility */
+ for(j=0;j<=FACILITY_REASONS;j++) {
+ if(hs->facility_reason[j]!=0) {
+ printf(" %s : %u\n", val_to_str(j,FacilityReason_vals,"unknown reason "), hs->facility_reason[j]);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ printf("=====================================================================\n");
+}
+
+
+static void
+h225counter_init(const char *optarg, void* userdata _U_)
+{
+ h225counter_t *hs;
+ GString *error_string;
+
+ hs = g_malloc(sizeof(h225counter_t));
+ if(!strncmp(optarg,"h225,counter,",13)){
+ hs->filter=g_strdup(optarg+13);
+ } else {
+ hs->filter=NULL;
+ }
+
+ h225counter_reset(hs);
+
+ error_string=register_tap_listener("h225", hs, hs->filter, 0, NULL, h225counter_packet, h225counter_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(hs->filter);
+ g_free(hs);
+
+ fprintf(stderr, "tshark: Couldn't register h225,counter tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_h225counter(void)
+{
+ register_stat_cmd_arg("h225,counter", h225counter_init,NULL);
+}
diff --git a/ui/cli/tap-h225rassrt.c b/ui/cli/tap-h225rassrt.c
new file mode 100644
index 0000000000..a0c6d8e37e
--- /dev/null
+++ b/ui/cli/tap-h225rassrt.c
@@ -0,0 +1,246 @@
+/* tap_h225rassrt.c
+ * h225 RAS Service Response Time statistics for wireshark
+ * Copyright 2003 Lars Roland
+ *
+ * $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.
+ */
+
+#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.h"
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include <epan/dissectors/packet-h225.h>
+#include "timestats.h"
+
+/* following values represent the size of their valuestring arrays */
+#define NUM_RAS_STATS 7
+
+static const value_string ras_message_category[] = {
+ { 0, "Gatekeeper "},
+ { 1, "Registration "},
+ { 2, "UnRegistration"},
+ { 3, "Admission "},
+ { 4, "Bandwidth "},
+ { 5, "Disengage "},
+ { 6, "Location "},
+ { 0, NULL }
+};
+
+typedef enum _ras_type {
+ RAS_REQUEST,
+ RAS_CONFIRM,
+ RAS_REJECT,
+ RAS_OTHER
+}ras_type;
+
+typedef enum _ras_category {
+ RAS_GATEKEEPER,
+ RAS_REGISTRATION,
+ RAS_UNREGISTRATION,
+ RAS_ADMISSION,
+ RAS_BANDWIDTH,
+ RAS_DISENGAGE,
+ RAS_LOCATION,
+ RAS_OTHERS
+}ras_category;
+
+/* Summary of response-time calculations*/
+typedef struct _h225_rtd_t {
+ guint32 open_req_num;
+ guint32 disc_rsp_num;
+ guint32 req_dup_num;
+ guint32 rsp_dup_num;
+ timestat_t stats;
+} h225_rtd_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _h225rassrt_t {
+ char *filter;
+ h225_rtd_t ras_rtd[NUM_RAS_STATS];
+} h225rassrt_t;
+
+
+static void
+h225rassrt_reset(void *phs)
+{
+ h225rassrt_t *hs=(h225rassrt_t *)phs;
+ int i;
+
+ for(i=0;i<NUM_RAS_STATS;i++) {
+ hs->ras_rtd[i].stats.num = 0;
+ hs->ras_rtd[i].stats.min_num = 0;
+ hs->ras_rtd[i].stats.max_num = 0;
+ hs->ras_rtd[i].stats.min.secs = 0;
+ hs->ras_rtd[i].stats.min.nsecs = 0;
+ hs->ras_rtd[i].stats.max.secs = 0;
+ hs->ras_rtd[i].stats.max.nsecs = 0;
+ hs->ras_rtd[i].stats.tot.secs = 0;
+ hs->ras_rtd[i].stats.tot.nsecs = 0;
+ hs->ras_rtd[i].open_req_num = 0;
+ hs->ras_rtd[i].disc_rsp_num = 0;
+ hs->ras_rtd[i].req_dup_num = 0;
+ hs->ras_rtd[i].rsp_dup_num = 0;
+ }
+
+}
+
+static int
+h225rassrt_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi)
+{
+ h225rassrt_t *hs=(h225rassrt_t *)phs;
+ const h225_packet_info *pi=phi;
+
+ ras_type rasmsg_type = RAS_OTHER;
+ ras_category rascategory = RAS_OTHERS;
+
+ if (pi->msg_type != H225_RAS || pi->msg_tag == -1) {
+ /* No RAS Message or uninitialized msg_tag -> return */
+ return 0;
+ }
+
+ if (pi->msg_tag < 21) {
+ /* */
+ rascategory = pi->msg_tag / 3;
+ rasmsg_type = pi->msg_tag % 3;
+ }
+ else {
+ /* No SRT yet (ToDo) */
+ return 0;
+ }
+
+ switch(rasmsg_type) {
+
+ case RAS_REQUEST:
+ if(pi->is_duplicate){
+ hs->ras_rtd[rascategory].req_dup_num++;
+ }
+ else {
+ hs->ras_rtd[rascategory].open_req_num++;
+ }
+ break;
+
+ case RAS_CONFIRM:
+ /* no break - delay calculation is identical for Confirm and Reject */
+ case RAS_REJECT:
+ if(pi->is_duplicate){
+ /* Duplicate is ignored */
+ hs->ras_rtd[rascategory].rsp_dup_num++;
+ }
+ else if (!pi->request_available) {
+ /* no request was seen, ignore response */
+ hs->ras_rtd[rascategory].disc_rsp_num++;
+ }
+ else {
+ hs->ras_rtd[rascategory].open_req_num--;
+ time_stat_update(&(hs->ras_rtd[rascategory].stats),&(pi->delta_time), pinfo);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+h225rassrt_draw(void *phs)
+{
+ h225rassrt_t *hs=(h225rassrt_t *)phs;
+ int i;
+ timestat_t *rtd_temp;
+
+ printf("======================================== H225 RAS Service Response Time ========================================\n");
+ printf("H225 RAS Service Response Time (SRT) Statistics:\n");
+ printf("RAS-Messages | Measurements | Min SRT | Max SRT | Avg SRT | Min in Frame | Max in Frame |\n");
+ for(i=0;i<NUM_RAS_STATS;i++) {
+ rtd_temp = &(hs->ras_rtd[i].stats);
+ if(rtd_temp->num){
+ printf("%s | %10u | %9.2f msec | %9.2f msec | %9.2f msec | %10u | %10u |\n",
+ val_to_str(i,ras_message_category,"Unknown "),rtd_temp->num,
+ nstime_to_msec(&(rtd_temp->min)), nstime_to_msec(&(rtd_temp->max)),
+ get_average(&(rtd_temp->tot), rtd_temp->num),
+ rtd_temp->min_num, rtd_temp->max_num
+ );
+ }
+ }
+ printf("================================================================================================================\n");
+ printf("RAS-Messages | Open REQ | Discarded RSP | Repeated REQ | Repeated RSP |\n");
+ for(i=0;i<NUM_RAS_STATS;i++) {
+ rtd_temp = &(hs->ras_rtd[i].stats);
+ if(rtd_temp->num){
+ printf("%s | %10u | %10u | %10u | %10u |\n",
+ val_to_str(i,ras_message_category,"Unknown "),
+ hs->ras_rtd[i].open_req_num, hs->ras_rtd[i].disc_rsp_num,
+ hs->ras_rtd[i].req_dup_num, hs->ras_rtd[i].rsp_dup_num
+ );
+ }
+ }
+ printf("================================================================================================================\n");
+
+}
+
+
+static void
+h225rassrt_init(const char *optarg, void* userdata _U_)
+{
+ h225rassrt_t *hs;
+ GString *error_string;
+
+ hs = g_malloc(sizeof(h225rassrt_t));
+ if(!strncmp(optarg,"h225,srt,",9)){
+ hs->filter=g_strdup(optarg+9);
+ } else {
+ hs->filter=NULL;
+ }
+
+ h225rassrt_reset(hs);
+
+ error_string=register_tap_listener("h225", hs, hs->filter, 0, NULL, h225rassrt_packet, h225rassrt_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(hs->filter);
+ g_free(hs);
+
+ fprintf(stderr, "tshark: Couldn't register h225,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_h225rassrt(void)
+{
+ register_stat_cmd_arg("h225,srt", h225rassrt_init,NULL);
+}
diff --git a/ui/cli/tap-hosts.c b/ui/cli/tap-hosts.c
new file mode 100644
index 0000000000..a840932782
--- /dev/null
+++ b/ui/cli/tap-hosts.c
@@ -0,0 +1,183 @@
+/* tap-hosts.c
+ *
+ * $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.
+ */
+
+/* Dump our collected IPv4- and IPv6-to-hostname mappings */
+
+#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 "globals.h"
+
+#include <epan/packet.h>
+#include <cfile.h>
+#include <epan/proto.h>
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/addr_resolv.h>
+
+/* Needed for addrinfo */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#if defined(_WIN32) && defined(INET6)
+# include <ws2tcpip.h>
+#endif
+
+#ifdef NEED_INET_V6DEFS_H
+# include "wsutil/inet_v6defs.h"
+#endif
+
+
+gboolean dump_v4 = FALSE;
+gboolean dump_v6 = FALSE;
+
+#define TAP_NAME "hosts"
+
+#define HOSTNAME_POS 48
+#define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
+static void
+hosts_draw(void *dummy _U_)
+{
+ struct addrinfo *ai;
+ struct sockaddr_in *sa4;
+ struct sockaddr_in6 *sa6;
+ char addr_str[ADDRSTRLEN];
+ int i, tab_count;
+
+ printf("# TShark hosts output\n");
+ printf("#\n");
+ printf("# Host data gathered from %s\n", cfile.filename);
+ printf("\n");
+
+ /* Dump the v4 addresses first, then v6 */
+ for (ai = get_addrinfo_list(); ai; ai = ai->ai_next) {
+ if (!dump_v4 || ai->ai_family != AF_INET) {
+ continue;
+ }
+
+ sa4 = (struct sockaddr_in *)(void *)ai->ai_addr;
+ if (inet_ntop(AF_INET, &(sa4->sin_addr.s_addr), addr_str, ADDRSTRLEN)) {
+ tab_count = (HOSTNAME_POS - (int)strlen(addr_str)) / 8;
+ printf("%s", addr_str);
+ for (i = 0; i < tab_count; i++)
+ printf("\t");
+ printf("%s\n", ai->ai_canonname);
+ }
+ }
+
+
+ for (ai = get_addrinfo_list(); ai; ai = ai->ai_next) {
+ if (!dump_v6 || ai->ai_family != AF_INET6) {
+ continue;
+ }
+
+ sa6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
+ if (inet_ntop(AF_INET6, sa6->sin6_addr.s6_addr, addr_str, ADDRSTRLEN)) {
+ tab_count = (HOSTNAME_POS - (int)strlen(addr_str)) / 8;
+ printf("%s", addr_str);
+ for (i = 0; i < tab_count; i++)
+ printf("\t");
+ printf("%s\n", ai->ai_canonname);
+ }
+ }
+}
+
+
+static void
+hosts_init(const char *optarg, void* userdata _U_)
+{
+ GString *error_string;
+ gchar **tokens;
+ gint opt_count;
+
+ dump_v4 = FALSE;
+ dump_v6 = FALSE;
+
+ if(strcmp(TAP_NAME, optarg)==0) {
+ /* No arguments; dump everything */
+ dump_v4 = TRUE;
+ dump_v6 = TRUE;
+ } else {
+ tokens = g_strsplit(optarg,",", 0);
+ opt_count=0;
+ while (tokens[opt_count]) {
+ if (strcmp("ipv4", tokens[opt_count]) == 0) {
+ dump_v4 = TRUE;
+ } else if (strcmp("ipv6", tokens[opt_count]) == 0) {
+ dump_v6 = TRUE;
+ } else if (opt_count > 0) {
+ fprintf(stderr, "tshark: invalid \"-z " TAP_NAME "[,ipv4|ipv6]\" argument\n");
+ exit(1);
+ }
+ opt_count++;
+ }
+ g_strfreev(tokens);
+ }
+
+ error_string=register_tap_listener("frame", NULL, NULL, TL_REQUIRES_PROTO_TREE,
+ NULL, NULL, hosts_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ fprintf(stderr, "tshark: Couldn't register " TAP_NAME " tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+void
+register_tap_listener_hosts(void)
+{
+ register_stat_cmd_arg(TAP_NAME, hosts_init, NULL);
+}
+
diff --git a/ui/cli/tap-httpstat.c b/ui/cli/tap-httpstat.c
new file mode 100644
index 0000000000..fc12fcd9b2
--- /dev/null
+++ b/ui/cli/tap-httpstat.c
@@ -0,0 +1,329 @@
+/* tap-httpstat.c
+ * tap-httpstat 2003 Jean-Michel FAYARD
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "epan/packet_info.h"
+#include "epan/value_string.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-http.h>
+
+
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _http_stats_t {
+ char *filter;
+ GHashTable *hash_responses;
+ GHashTable *hash_requests;
+} httpstat_t;
+
+/* used to keep track of the stats for a specific response code
+ * for example it can be { 3, 404, "Not Found" ,...}
+ * which means we captured 3 reply http/1.1 404 Not Found */
+typedef struct _http_response_code_t {
+ guint32 packets; /* 3 */
+ guint response_code; /* 404 */
+ const gchar *name; /* Not Found */
+ httpstat_t *sp;
+} http_response_code_t;
+
+/* used to keep track of the stats for a specific request string */
+typedef struct _http_request_methode_t {
+ gchar *response; /* eg. : GET */
+ guint32 packets;
+ httpstat_t *sp;
+} http_request_methode_t;
+
+
+static const value_string vals_status_code[] = {
+ { 100, "Continue" },
+ { 101, "Switching Protocols" },
+ { 199, "Informational - Others" },
+
+ { 200, "OK"},
+ { 201, "Created"},
+ { 202, "Accepted"},
+ { 203, "Non-authoritative Information"},
+ { 204, "No Content"},
+ { 205, "Reset Content"},
+ { 206, "Partial Content"},
+ { 299, "Success - Others"}, /* used to keep track of others Success packets */
+
+ { 300, "Multiple Choices"},
+ { 301, "Moved Permanently"},
+ { 302, "Moved Temporarily"},
+ { 303, "See Other"},
+ { 304, "Not Modified"},
+ { 305, "Use Proxy"},
+ { 399, "Redirection - Others"},
+
+ { 400, "Bad Request"},
+ { 401, "Unauthorized"},
+ { 402, "Payment Required"},
+ { 403, "Forbidden"},
+ { 404, "Not Found"},
+ { 405, "Method Not Allowed"},
+ { 406, "Not Acceptable"},
+ { 407, "Proxy Authentication Required"},
+ { 408, "Request Time-out"},
+ { 409, "Conflict"},
+ { 410, "Gone"},
+ { 411, "Length Required"},
+ { 412, "Precondition Failed"},
+ { 413, "Request Entity Too Large"},
+ { 414, "Request-URI Too Large"},
+ { 415, "Unsupported Media Type"},
+ { 499, "Client Error - Others"},
+
+ { 500, "Internal Server Error"},
+ { 501, "Not Implemented"},
+ { 502, "Bad Gateway"},
+ { 503, "Service Unavailable"},
+ { 504, "Gateway Time-out"},
+ { 505, "HTTP Version not supported"},
+ { 599, "Server Error - Others"},
+
+ { 0, NULL}
+} ;
+
+/* insert some entries */
+static void
+http_init_hash( httpstat_t *sp)
+{
+ int i;
+
+ sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal);
+
+ for (i=0 ; vals_status_code[i].strptr ; i++ )
+ {
+ gint *key = g_malloc (sizeof(gint));
+ http_response_code_t *sc = g_malloc (sizeof(http_response_code_t));
+ *key = vals_status_code[i].value;
+ sc->packets=0;
+ sc->response_code = *key;
+ sc->name=vals_status_code[i].strptr;
+ sc->sp = sp;
+ g_hash_table_insert( sc->sp->hash_responses, key, sc);
+ }
+ sp->hash_requests = g_hash_table_new( g_str_hash, g_str_equal);
+}
+static void
+http_draw_hash_requests( gchar *key _U_ , http_request_methode_t *data, gchar * format)
+{
+ if (data->packets==0)
+ return;
+ printf( format, data->response, data->packets);
+}
+
+static void
+http_draw_hash_responses( gint * key _U_ , http_response_code_t *data, char * format)
+{
+ if (data==NULL) {
+ g_warning("No data available, key=%d\n", *key);
+ exit(EXIT_FAILURE);
+ }
+ if (data->packets==0)
+ return;
+ /* " HTTP %3d %-35s %9d packets", */
+ printf(format, data->response_code, data->name, data->packets );
+}
+
+
+
+/* NOT USED at this moment */
+/*
+static void
+http_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
+{
+ g_free(key);
+ g_free(value);
+}
+*/
+static void
+http_reset_hash_responses(gchar *key _U_ , http_response_code_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+static void
+http_reset_hash_requests(gchar *key _U_ , http_request_methode_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+
+static void
+httpstat_reset(void *psp )
+{
+ httpstat_t *sp=psp;
+
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_responses, NULL);
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)http_reset_hash_requests, NULL);
+
+}
+
+static int
+httpstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ const http_info_value_t *value=pri;
+ httpstat_t *sp=(httpstat_t *) psp;
+
+ /* We are only interested in reply packets with a status code */
+ /* Request or reply packets ? */
+ if (value->response_code!=0) {
+ guint *key=g_malloc( sizeof(guint) );
+ http_response_code_t *sc;
+
+ *key=value->response_code;
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL){
+ /* non standard status code ; we classify it as others
+ * in the relevant category (Informational,Success,Redirection,Client Error,Server Error)
+ */
+ int i = value->response_code;
+ if ((i<100) || (i>=600)) {
+ return 0;
+ }
+ else if (i<200){
+ *key=199; /* Hopefully, this status code will never be used */
+ }
+ else if (i<300){
+ *key=299;
+ }
+ else if (i<400){
+ *key=399;
+ }
+ else if (i<500){
+ *key=499;
+ }
+ else{
+ *key=599;
+ }
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL)
+ return 0;
+ }
+ sc->packets++;
+ }
+ else if (value->request_method){
+ http_request_methode_t *sc;
+
+ sc = g_hash_table_lookup(
+ sp->hash_requests,
+ value->request_method);
+ if (sc==NULL){
+ sc=g_malloc( sizeof(http_request_methode_t) );
+ sc->response=g_strdup( value->request_method );
+ sc->packets=1;
+ sc->sp = sp;
+ g_hash_table_insert( sp->hash_requests, sc->response, sc);
+ } else {
+ sc->packets++;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+static void
+httpstat_draw(void *psp )
+{
+ httpstat_t *sp=psp;
+ printf("\n");
+ printf("===================================================================\n");
+ if (! sp->filter[0])
+ printf("HTTP Statistics\n");
+ else
+ printf("HTTP Statistics with filter %s\n", sp->filter);
+
+ printf( "* HTTP Status Codes in reply packets\n");
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)http_draw_hash_responses,
+ " HTTP %3d %s\n");
+ printf("* List of HTTP Request methods\n");
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)http_draw_hash_requests,
+ " %9s %d \n");
+ printf("===================================================================\n");
+}
+
+
+
+/* When called, this function will create a new instance of gtk_httpstat.
+ */
+static void
+gtk_httpstat_init(const char *optarg,void* userdata _U_)
+{
+ httpstat_t *sp;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if (!strncmp (optarg, "http,stat,", 10)){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+
+ sp = g_malloc( sizeof(httpstat_t) );
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ /*g_hash_table_foreach( http_status, (GHFunc)http_reset_hash_responses, NULL);*/
+
+
+ error_string = register_tap_listener(
+ "http",
+ sp,
+ filter,
+ 0,
+ httpstat_reset,
+ httpstat_packet,
+ httpstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->filter);
+ g_free(sp);
+ fprintf (stderr, "tshark: Couldn't register http,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ http_init_hash(sp);
+}
+
+void
+register_tap_listener_gtkhttpstat(void)
+{
+ register_stat_cmd_arg("http,stat,", gtk_httpstat_init,NULL);
+}
diff --git a/ui/cli/tap-icmpstat.c b/ui/cli/tap-icmpstat.c
new file mode 100644
index 0000000000..b8abbb2a5c
--- /dev/null
+++ b/ui/cli/tap-icmpstat.c
@@ -0,0 +1,319 @@
+/* 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;
+ guint min_frame;
+ guint max_frame;
+ 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);
+ memset(icmpstat, 0, sizeof(icmpstat_t));
+ icmpstat->min_msecs = 1.0 * G_MAXUINT;
+}
+
+
+static gint compare_doubles(gconstpointer a, gconstpointer b)
+{
+ double ad, bd;
+
+ ad = *(double *)a;
+ bd = *(double *)b;
+
+ if (ad < bd)
+ return -1;
+ if (ad > bd)
+ return 1;
+ return 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 _U_, 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_insert_sorted(icmpstat->rt_list, rt, compare_doubles);
+ icmpstat->num_resps++;
+ if (icmpstat->min_msecs > trans->resp_time) {
+ icmpstat->min_frame = trans->resp_frame;
+ icmpstat->min_msecs = trans->resp_time;
+ }
+ if (icmpstat->max_msecs < trans->resp_time) {
+ icmpstat->max_frame = trans->resp_frame;
+ 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;
+}
+
+
+/*
+ * Compute the mean, median and standard deviation.
+ */
+static void compute_stats(icmpstat_t *icmpstat, double *mean, double *med, double *sdev)
+{
+ GSList *slist = icmpstat->rt_list;
+ double diff;
+ double sq_diff_sum = 0.0;
+
+ if (icmpstat->num_resps == 0 || slist == NULL) {
+ *mean = 0.0;
+ *med = 0.0;
+ *sdev = 0.0;
+ return;
+ }
+
+ /* (arithmetic) mean */
+ *mean = icmpstat->tot_msecs / icmpstat->num_resps;
+
+ /* median: If we have an odd number of elements in our list, then the
+ * median is simply the middle element, otherwise the median is computed by
+ * averaging the 2 elements on either side of the mid-point. */
+ if (icmpstat->num_resps & 1)
+ *med = *(double *)g_slist_nth_data(slist, icmpstat->num_resps / 2);
+ else {
+ *med =
+ (*(double *)g_slist_nth_data(slist, (icmpstat->num_resps - 1) / 2) +
+ *(double *)g_slist_nth_data(slist, icmpstat->num_resps / 2)) / 2;
+ }
+
+ /* (sample) standard deviation */
+ for ( ; slist; slist = g_slist_next(slist)) {
+ diff = *(double *)slist->data - *mean;
+ sq_diff_sum += diff * diff;
+ }
+ if (icmpstat->num_resps > 1)
+ *sdev = sqrt(sq_diff_sum / (icmpstat->num_resps - 1));
+ else
+ *sdev = 0.0;
+}
+
+
+/* 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 mean, sdev, med;
+
+ printf("\n");
+ printf("==========================================================================\n");
+ printf("ICMP Service Response Time (SRT) Statistics (all times in ms):\n");
+ printf("Filter: %s\n", icmpstat->filter ? icmpstat->filter : "<none>");
+ printf("\nRequests Replies Lost %% Loss\n");
+
+ if (icmpstat->num_rqsts) {
+ lost = icmpstat->num_rqsts - icmpstat->num_resps;
+ compute_stats(icmpstat, &mean, &med, &sdev);
+
+ printf("%-10u%-10u%-10u%5.1f%%\n\n",
+ icmpstat->num_rqsts, icmpstat->num_resps, lost,
+ 100.0 * lost / icmpstat->num_rqsts);
+ printf("Minimum Maximum Mean Median SDeviation Min Frame Max Frame\n");
+ printf("%-10.3f%-10.3f%-10.3f%-10.3f%-10.3f %-10u%-10u\n",
+ icmpstat->min_msecs >= G_MAXUINT ? 0.0 : icmpstat->min_msecs,
+ icmpstat->max_msecs, mean, med, sdev,
+ icmpstat->min_frame, icmpstat->max_frame);
+ } else {
+ printf("0 0 0 0.0%%\n\n");
+ printf("Minimum Maximum Mean Median SDeviation Min Frame Max Frame\n");
+ printf("0.000 0.000 0.000 0.000 0.000 0 0\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_try_malloc(sizeof(icmpstat_t));
+ if (icmpstat == NULL) {
+ fprintf(stderr, "tshark: g_try_malloc() fatal error.\n");
+ exit(1);
+ }
+ memset(icmpstat, 0, sizeof(icmpstat_t));
+ icmpstat->min_msecs = 1.0 * G_MAXUINT;
+
+ 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);
+}
+
diff --git a/ui/cli/tap-icmpv6stat.c b/ui/cli/tap-icmpv6stat.c
new file mode 100644
index 0000000000..12659b26a7
--- /dev/null
+++ b/ui/cli/tap-icmpv6stat.c
@@ -0,0 +1,320 @@
+/* tap-icmpv6stat.c
+ * icmpv6stat 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 icmpv6 echo request/reply SRT statistics to tshark.
+ * It is only used by tshark and not wireshark
+ *
+ * It was based on tap-icmptat.c, which itself 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 ICMPv6 statistics */
+typedef struct _icmpv6stat_t {
+ char *filter;
+ GSList *rt_list;
+ guint num_rqsts;
+ guint num_resps;
+ guint min_frame;
+ guint max_frame;
+ double min_msecs;
+ double max_msecs;
+ double tot_msecs;
+} icmpv6stat_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
+icmpv6stat_reset(void *tapdata)
+{
+ icmpv6stat_t *icmpv6stat = tapdata;
+
+ g_slist_free(icmpv6stat->rt_list);
+ memset(icmpv6stat, 0, sizeof(icmpv6stat_t));
+ icmpv6stat->min_msecs = 1.0 * G_MAXUINT;
+}
+
+
+static gint compare_doubles(gconstpointer a, gconstpointer b)
+{
+ double ad, bd;
+
+ ad = *(double *)a;
+ bd = *(double *)b;
+
+ if (ad < bd)
+ return -1;
+ if (ad > bd)
+ return 1;
+ return 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
+ * "icmpv6" 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
+icmpv6stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *data)
+{
+ icmpv6stat_t *icmpv6stat = 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;
+ icmpv6stat->rt_list = g_slist_insert_sorted(icmpv6stat->rt_list, rt, compare_doubles);
+ icmpv6stat->num_resps++;
+ if (icmpv6stat->min_msecs > trans->resp_time) {
+ icmpv6stat->min_frame = trans->resp_frame;
+ icmpv6stat->min_msecs = trans->resp_time;
+ }
+ if (icmpv6stat->max_msecs < trans->resp_time) {
+ icmpv6stat->max_frame = trans->resp_frame;
+ icmpv6stat->max_msecs = trans->resp_time;
+ }
+ icmpv6stat->tot_msecs += trans->resp_time;
+ } else if (trans->rqst_frame)
+ icmpv6stat->num_rqsts++;
+ else
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * Compute the mean, median and standard deviation.
+ */
+static void compute_stats(icmpv6stat_t *icmpv6stat, double *mean, double *med, double *sdev)
+{
+ GSList *slist = icmpv6stat->rt_list;
+ double diff;
+ double sq_diff_sum = 0.0;
+
+ if (icmpv6stat->num_resps == 0 || slist == NULL) {
+ *mean = 0.0;
+ *med = 0.0;
+ *sdev = 0.0;
+ return;
+ }
+
+ /* (arithmetic) mean */
+ *mean = icmpv6stat->tot_msecs / icmpv6stat->num_resps;
+
+ /* median: If we have an odd number of elements in our list, then the
+ * median is simply the middle element, otherwise the median is computed by
+ * averaging the 2 elements on either side of the mid-point. */
+ if (icmpv6stat->num_resps & 1)
+ *med = *(double *)g_slist_nth_data(slist, icmpv6stat->num_resps / 2);
+ else {
+ *med =
+ (*(double *)g_slist_nth_data(slist, (icmpv6stat->num_resps - 1) / 2) +
+ *(double *)g_slist_nth_data(slist, icmpv6stat->num_resps / 2)) / 2;
+ }
+
+ /* (sample) standard deviation */
+ for ( ; slist; slist = g_slist_next(slist)) {
+ diff = *(double *)slist->data - *mean;
+ sq_diff_sum += diff * diff;
+ }
+ if (icmpv6stat->num_resps > 1)
+ *sdev = sqrt(sq_diff_sum / (icmpv6stat->num_resps - 1));
+ else
+ *sdev = 0.0;
+}
+
+
+/* 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 icmpv6stat_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
+icmpv6stat_draw(void *tapdata)
+{
+ icmpv6stat_t *icmpv6stat = tapdata;
+ unsigned int lost;
+ double mean, sdev, med;
+
+ printf("\n");
+ printf("==========================================================================\n");
+ printf("ICMPv6 Service Response Time (SRT) Statistics (all times in ms):\n");
+ printf("Filter: %s\n", icmpv6stat->filter ? icmpv6stat->filter : "<none>");
+ printf("\nRequests Replies Lost %% Loss\n");
+
+ if (icmpv6stat->num_rqsts) {
+ lost = icmpv6stat->num_rqsts - icmpv6stat->num_resps;
+ compute_stats(icmpv6stat, &mean, &med, &sdev);
+
+ printf("%-10u%-10u%-10u%5.1f%%\n\n",
+ icmpv6stat->num_rqsts, icmpv6stat->num_resps, lost,
+ 100.0 * lost / icmpv6stat->num_rqsts);
+ printf("Minimum Maximum Mean Median SDeviation Min Frame Max Frame\n");
+ printf("%-10.3f%-10.3f%-10.3f%-10.3f%-10.3f %-10u%-10u\n",
+ icmpv6stat->min_msecs >= G_MAXUINT ? 0.0 : icmpv6stat->min_msecs,
+ icmpv6stat->max_msecs, mean, med, sdev,
+ icmpv6stat->min_frame, icmpv6stat->max_frame);
+ } else {
+ printf("0 0 0 0.0%%\n\n");
+ printf("Minimum Maximum Mean Median SDeviation Min Frame Max Frame\n");
+ printf("0.000 0.000 0.000 0.000 0.000 0 0\n");
+ }
+ printf("==========================================================================\n");
+}
+
+
+/* When called, this function will create a new instance of icmpv6stat.
+ *
+ * This function is called from tshark when it parses the -z icmpv6, arguments
+ * and it creates a new instance to store statistics in and registers this new
+ * instance for the icmpv6 tap.
+ */
+static void
+icmpv6stat_init(const char *optarg, void* userdata _U_)
+{
+ icmpv6stat_t *icmpv6stat;
+ const char *filter = NULL;
+ GString *error_string;
+
+ if (strstr(optarg, "icmpv6,srt,"))
+ filter = optarg + strlen("icmpv6,srt,");
+
+ icmpv6stat = g_try_malloc(sizeof(icmpv6stat_t));
+ if (icmpv6stat == NULL) {
+ fprintf(stderr, "tshark: g_try_malloc() fatal error.\n");
+ exit(1);
+ }
+ memset(icmpv6stat, 0, sizeof(icmpv6stat_t));
+ icmpv6stat->min_msecs = 1.0 * G_MAXUINT;
+
+ if (filter)
+ icmpv6stat->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("icmpv6", icmpv6stat, icmpv6stat->filter,
+ TL_REQUIRES_NOTHING, icmpv6stat_reset, icmpv6stat_packet, icmpv6stat_draw);
+ if (error_string) {
+ /* error, we failed to attach to the tap. clean up */
+ if (icmpv6stat->filter)
+ g_free(icmpv6stat->filter);
+ g_free(icmpv6stat);
+
+ fprintf(stderr, "tshark: Couldn't register icmpv6,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_icmpv6stat(void)
+{
+ register_stat_cmd_arg("icmpv6,srt", icmpv6stat_init, NULL);
+}
+
diff --git a/ui/cli/tap-iostat.c b/ui/cli/tap-iostat.c
new file mode 100644
index 0000000000..1104edd6d6
--- /dev/null
+++ b/ui/cli/tap-iostat.c
@@ -0,0 +1,984 @@
+/* tap-iostat.c
+ * iostat 2002 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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/epan_dissect.h"
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/strutil.h>
+
+
+typedef struct _io_stat_t {
+ gint64 interval; /* unit is us */
+ guint32 num_items;
+ struct _io_stat_item_t *items;
+ const char **filters;
+} io_stat_t;
+
+#define CALC_TYPE_FRAMES 0
+#define CALC_TYPE_BYTES 1
+#define CALC_TYPE_FRAMES_AND_BYTES 2
+#define CALC_TYPE_COUNT 3
+#define CALC_TYPE_SUM 4
+#define CALC_TYPE_MIN 5
+#define CALC_TYPE_MAX 6
+#define CALC_TYPE_AVG 7
+#define CALC_TYPE_LOAD 8
+
+typedef struct _io_stat_item_t {
+ io_stat_t *parent;
+ struct _io_stat_item_t *next;
+ struct _io_stat_item_t *prev;
+ gint64 time; /* unit is us since start of capture */
+ int calc_type;
+ int hf_index;
+ guint64 frames;
+ guint64 num;
+ guint64 counter;
+ gfloat float_counter;
+ gdouble double_counter;
+} io_stat_item_t;
+
+#define NANOSECS_PER_SEC 1000000000
+
+static int
+iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
+{
+ io_stat_item_t *mit = arg;
+ io_stat_item_t *it;
+ gint64 current_time, ct;
+ GPtrArray *gp;
+ guint i;
+
+ current_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000;
+
+ /* the prev item before the main one is always the last interval we saw packets for */
+ it=mit->prev;
+
+ /* XXX for the time being, just ignore all frames that are in the past.
+ should be fixed in the future but hopefully it is uncommon */
+ if(current_time<it->time){
+ return FALSE;
+ }
+
+ /* we have moved into a new interval, we need to create a new struct */
+ ct = current_time;
+ while(ct >= (it->time + mit->parent->interval)){
+ it->next=g_malloc(sizeof(io_stat_item_t));
+ it->next->prev=it;
+ it->next->next=NULL;
+ it=it->next;
+ mit->prev=it;
+
+ it->time = it->prev->time + mit->parent->interval;
+ it->frames = 0;
+ it->counter = 0;
+ it->float_counter = 0;
+ it->double_counter = 0;
+ it->num = 0;
+ it->calc_type=it->prev->calc_type;
+ it->hf_index=it->prev->hf_index;
+ }
+
+ /* it will now give us the current structure to use to store the data in */
+ it->frames++;
+
+ switch(it->calc_type){
+ case CALC_TYPE_BYTES:
+ case CALC_TYPE_FRAMES:
+ case CALC_TYPE_FRAMES_AND_BYTES:
+ it->counter+=pinfo->fd->pkt_len;
+ break;
+ case CALC_TYPE_COUNT:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ it->counter+=gp->len;
+ }
+ break;
+ case CALC_TYPE_SUM:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ guint64 val;
+ nstime_t *new_time;
+
+ for(i=0;i<gp->len;i++){
+ switch(proto_registrar_get_ftype(it->hf_index)){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ it->counter+=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_UINT64:
+ it->counter+=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ it->counter+=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_INT64:
+ it->counter+=(gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_FLOAT:
+ it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_DOUBLE:
+ it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_RELATIVE_TIME:
+ new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ it->counter += val;
+ break;
+ }
+ }
+ }
+ break;
+ case CALC_TYPE_MIN:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ int type;
+ guint64 val;
+ gfloat float_val;
+ gdouble double_val;
+ nstime_t *new_time;
+
+ type=proto_registrar_get_ftype(it->hf_index);
+ for(i=0;i<gp->len;i++){
+ switch(type){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val<it->counter){
+ it->counter=val;
+ }
+ break;
+ case FT_UINT64:
+ val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val<it->counter){
+ it->counter=val;
+ }
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if((gint32)val<(gint32)(it->counter)){
+ it->counter=val;
+ }
+ break;
+ case FT_INT64:
+ val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if((gint64)val<(gint64)(it->counter)){
+ it->counter=val;
+ }
+ break;
+ case FT_FLOAT:
+ float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->float_counter=float_val;
+ } else if(float_val<it->float_counter){
+ it->float_counter=float_val;
+ }
+ break;
+ case FT_DOUBLE:
+ double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->double_counter=double_val;
+ } else if(double_val<it->double_counter){
+ it->double_counter=double_val;
+ }
+ break;
+ case FT_RELATIVE_TIME:
+ new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val<it->counter){
+ it->counter=val;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case CALC_TYPE_MAX:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ int type;
+ guint64 val;
+ gfloat float_val;
+ gdouble double_val;
+ nstime_t *new_time;
+
+ type=proto_registrar_get_ftype(it->hf_index);
+ for(i=0;i<gp->len;i++){
+ switch(type){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val>it->counter){
+ it->counter=val;
+ }
+ break;
+ case FT_UINT64:
+ val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val>it->counter){
+ it->counter=val;
+ }
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if((gint32)val>(gint32)(it->counter)){
+ it->counter=val;
+ }
+ break;
+ case FT_INT64:
+ val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if((gint64)val>(gint64)(it->counter)){
+ it->counter=val;
+ }
+ break;
+ case FT_FLOAT:
+ float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->float_counter=float_val;
+ } else if(float_val>it->float_counter){
+ it->float_counter=float_val;
+ }
+ break;
+ case FT_DOUBLE:
+ double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ if((it->frames==1)&&(i==0)){
+ it->double_counter=double_val;
+ } else if(double_val>it->double_counter){
+ it->double_counter=double_val;
+ }
+ break;
+ case FT_RELATIVE_TIME:
+ new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ if((it->frames==1)&&(i==0)){
+ it->counter=val;
+ } else if(val>it->counter){
+ it->counter=val;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case CALC_TYPE_AVG:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ int type;
+ guint64 val;
+ nstime_t *new_time;
+
+ type=proto_registrar_get_ftype(it->hf_index);
+ for(i=0;i<gp->len;i++){
+ it->num++;
+ switch(type){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter+=val;
+ break;
+ case FT_UINT64:
+ case FT_INT64:
+ val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
+ it->counter+=val;
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
+ it->counter+=val;
+ break;
+ case FT_FLOAT:
+ it->float_counter+=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_DOUBLE:
+ it->double_counter+=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
+ break;
+ case FT_RELATIVE_TIME:
+ new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
+ it->counter+=val;
+ break;
+ }
+ }
+ }
+ break;
+ case CALC_TYPE_LOAD:
+ gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
+ if(gp){
+ int type;
+
+ type=proto_registrar_get_ftype(it->hf_index);
+ if (type != FT_RELATIVE_TIME) {
+ fprintf(stderr,
+ "\ntshark: LOAD() is only supported for relative-time fiels such as smb.time\n"
+ );
+ exit(10);
+ }
+ for(i=0;i<gp->len;i++){
+ guint64 val;
+ int tival;
+ nstime_t *new_time;
+ io_stat_item_t *pit;
+
+ new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
+ val=(guint64)(new_time->secs)*1000000 + new_time->nsecs/1000;
+ tival = (int)(val % mit->parent->interval);
+ it->counter += tival;
+ val -= tival;
+ pit = it->prev;
+ while (val > 0) {
+ if (val < (guint64)mit->parent->interval) {
+ pit->counter += val;
+ val = 0;
+ break;
+ }
+
+ pit->counter += mit->parent->interval;
+ val -= mit->parent->interval;
+ pit = pit->prev;
+
+ }
+ }
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+iostat_draw(void *arg)
+{
+ io_stat_item_t *mit = arg;
+ io_stat_t *iot;
+ io_stat_item_t **items;
+ guint64 *frames;
+ guint64 *counters;
+ gfloat *float_counters;
+ gdouble *double_counters;
+ guint64 *num;
+ guint32 i;
+ guint32 borderLen=68;
+ gboolean more_items;
+ gint64 t;
+
+ iot=mit->parent;
+
+ printf("\n");
+
+ /* Display the table border */
+ for(i=0;i<iot->num_items;i++){
+ if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)
+ borderLen+=17;
+ }
+ if(iot->interval!=G_MAXINT32)
+ borderLen+=8;
+ if(iot->num_items>3)
+ borderLen+=(iot->num_items-3)*17;
+ for(i=0;i<borderLen;i++){
+ printf("=");
+ }
+ printf("\n");
+
+
+ printf("IO Statistics\n");
+ if(iot->interval!=G_MAXINT32)
+ printf("Interval: %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u secs\n",
+ iot->interval/1000000, iot->interval%1000000);
+
+ for(i=0;i<iot->num_items;i++){
+ printf("Column #%u: %s\n",i,iot->filters[i]?iot->filters[i]:"");
+ }
+ if(iot->interval==G_MAXINT32){
+ printf(" |");
+ } else {
+ printf(" |");
+ }
+ for(i=0;i<iot->num_items;i++){
+ if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES){
+ printf(" Column #%-2u |",i);
+ } else {
+ printf(" Column #%-2u |",i);
+ }
+ }
+ printf("\n");
+
+ if(iot->interval==G_MAXINT32) {
+ printf("Time |");
+ } else {
+ printf("Time |");
+ }
+ for(i=0;i<iot->num_items;i++){
+ switch(iot->items[i].calc_type){
+ case CALC_TYPE_FRAMES:
+ printf(" FRAMES |");
+ break;
+ case CALC_TYPE_BYTES:
+ printf(" BYTES |");
+ break;
+ case CALC_TYPE_FRAMES_AND_BYTES:
+ printf(" Frames | Bytes |");
+ break;
+ case CALC_TYPE_COUNT:
+ printf(" COUNT |");
+ break;
+ case CALC_TYPE_SUM:
+ printf(" SUM |");
+ break;
+ case CALC_TYPE_MIN:
+ printf(" MIN |");
+ break;
+ case CALC_TYPE_MAX:
+ printf(" MAX |");
+ break;
+ case CALC_TYPE_AVG:
+ printf(" AVG |");
+ break;
+ case CALC_TYPE_LOAD:
+ printf(" LOAD |");
+ break;
+ }
+ }
+ printf("\n");
+
+ items=g_malloc(sizeof(io_stat_item_t *)*iot->num_items);
+ frames=g_malloc(sizeof(guint64)*iot->num_items);
+ counters=g_malloc(sizeof(guint64)*iot->num_items);
+ float_counters=g_malloc(sizeof(gfloat)*iot->num_items);
+ double_counters=g_malloc(sizeof(gdouble)*iot->num_items);
+ num=g_malloc(sizeof(guint64)*iot->num_items);
+ /* preset all items at the first interval */
+ for(i=0;i<iot->num_items;i++){
+ items[i]=&iot->items[i];
+ }
+
+ /* loop the items until we run out of them all */
+ t=0;
+ do {
+ more_items=FALSE;
+ for(i=0;i<iot->num_items;i++){
+ frames[i]=0;
+ counters[i]=0;
+ float_counters[i]=0;
+ double_counters[i]=0;
+ num[i]=0;
+ }
+ for(i=0;i<iot->num_items;i++){
+ if(items[i] && (t>=(items[i]->time+iot->interval))){
+ items[i]=items[i]->next;
+ }
+
+ if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){
+ frames[i]=items[i]->frames;
+ counters[i]=items[i]->counter;
+ float_counters[i]=items[i]->float_counter;
+ double_counters[i]=items[i]->double_counter;
+ num[i]=items[i]->num;
+ }
+
+ if(items[i]){
+ more_items=TRUE;
+ }
+ }
+
+ if(more_items){
+ if(iot->interval==G_MAXINT32) {
+ printf("000.000- ");
+ } else {
+ printf("%04u.%06u-%04u.%06u ",
+ (int)(t/1000000),(int)(t%1000000),
+ (int)((t+iot->interval)/1000000),
+ (int)((t+iot->interval)%1000000));
+ }
+ for(i=0;i<iot->num_items;i++){
+ switch(iot->items[i].calc_type){
+ case CALC_TYPE_FRAMES:
+ printf(" %15" G_GINT64_MODIFIER "u ", frames[i]);
+ break;
+ case CALC_TYPE_BYTES:
+ printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
+ break;
+ case CALC_TYPE_FRAMES_AND_BYTES:
+ printf(" %15" G_GINT64_MODIFIER "u %15" G_GINT64_MODIFIER "u ", frames[i], counters[i]);
+ break;
+ case CALC_TYPE_COUNT:
+ printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
+ break;
+ case CALC_TYPE_SUM:
+ switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
+ break;
+ case FT_FLOAT:
+ printf(" %f ", float_counters[i]);
+ break;
+ case FT_DOUBLE:
+ printf(" %f ", double_counters[i]);
+ break;
+ case FT_RELATIVE_TIME:
+ counters[i] = (counters[i]+500)/1000;
+ printf(" %8u.%06u ",
+ (int)(counters[i]/1000000), (int)(counters[i]%1000000));
+ break;
+ }
+ break;
+ case CALC_TYPE_MIN:
+ switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
+ break;
+ case FT_FLOAT:
+ printf(" %f ", float_counters[i]);
+ break;
+ case FT_DOUBLE:
+ printf(" %f ", double_counters[i]);
+ break;
+ case FT_RELATIVE_TIME:
+ counters[i]=(counters[i]+500)/1000;
+ printf(" %8u.%06u ",
+ (int)(counters[i]/1000000), (int)(counters[i]%1000000));
+ break;
+ }
+ break;
+ case CALC_TYPE_MAX:
+ switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ printf(" %15u ", (int)(counters[i]));
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
+ break;
+ case FT_FLOAT:
+ printf(" %f ", float_counters[i]);
+ break;
+ case FT_DOUBLE:
+ printf(" %f ", double_counters[i]);
+ break;
+ case FT_RELATIVE_TIME:
+ counters[i]=(counters[i]+500)/1000;
+ printf(" %8u.%06u ",
+ (int)(counters[i]/1000000), (int)(counters[i]%1000000));
+ break;
+ }
+ break;
+ case CALC_TYPE_AVG:
+ if(num[i]==0){
+ num[i]=1;
+ }
+ switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ printf(" %15" G_GINT64_MODIFIER "u ", counters[i]/num[i]);
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ printf(" %15" G_GINT64_MODIFIER "d ", counters[i]/num[i]);
+ break;
+ case FT_FLOAT:
+ printf(" %f ", float_counters[i]/num[i]);
+ break;
+ case FT_DOUBLE:
+ printf(" %f ", double_counters[i]/num[i]);
+ break;
+ case FT_RELATIVE_TIME:
+ counters[i]=((counters[i]/num[i])+500)/1000;
+ printf(" %8u.%06u ",
+ (int)(counters[i]/1000000), (int)(counters[i]%1000000));
+ break;
+ }
+ break;
+
+ case CALC_TYPE_LOAD:
+ switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
+ case FT_RELATIVE_TIME:
+ printf("%8u.%06u ",
+ (int)(counters[i]/iot->interval), (int)((counters[i]%iot->interval)*1000000/iot->interval));
+ break;
+ }
+ break;
+
+ }
+ }
+ printf("\n");
+ }
+
+ t+=iot->interval;
+ } while(more_items);
+
+ for(i=0;i<borderLen;i++){
+ printf("=");
+ }
+ printf("\n");
+
+ g_free(items);
+ g_free(frames);
+ g_free(counters);
+ g_free(float_counters);
+ g_free(double_counters);
+ g_free(num);
+}
+
+
+typedef struct {
+ const char *func_name;
+ int calc_type;
+} calc_type_ent_t;
+
+static calc_type_ent_t calc_type_table[] = {
+ { "FRAMES", CALC_TYPE_FRAMES },
+ { "BYTES", CALC_TYPE_BYTES },
+ { "COUNT", CALC_TYPE_COUNT },
+ { "SUM", CALC_TYPE_SUM },
+ { "MIN", CALC_TYPE_MIN },
+ { "MAX", CALC_TYPE_MAX },
+ { "AVG", CALC_TYPE_AVG },
+ { "LOAD", CALC_TYPE_LOAD },
+ { NULL, 0 }
+};
+
+static void
+register_io_tap(io_stat_t *io, int i, const char *filter)
+{
+ GString *error_string;
+ const char *flt;
+ int j;
+ size_t namelen;
+ const char *p, *parenp;
+ char *field;
+ header_field_info *hfi;
+
+ io->items[i].prev=&io->items[i];
+ io->items[i].next=NULL;
+ io->items[i].parent=io;
+ io->items[i].time=0;
+ io->items[i].calc_type=CALC_TYPE_FRAMES_AND_BYTES;
+ io->items[i].frames=0;
+ io->items[i].counter=0;
+ io->items[i].num=0;
+ io->filters[i]=filter;
+ flt=filter;
+
+ field=NULL;
+ hfi=NULL;
+ for(j=0; calc_type_table[j].func_name; j++){
+ namelen=strlen(calc_type_table[j].func_name);
+ if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
+ io->items[i].calc_type=calc_type_table[j].calc_type;
+ if(*(filter+namelen)=='(') {
+ p=filter+namelen+1;
+ parenp=strchr(p, ')');
+ if(!parenp){
+ fprintf(stderr, "\ntshark: Closing parenthesis missing from calculated expression.\n");
+ exit(10);
+ }
+
+
+ if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){
+ if(parenp!=p) {
+ fprintf(stderr, "\ntshark: %s does require or allow a field name within the parens.\n",
+ calc_type_table[j].func_name);
+ exit(10);
+ }
+ } else {
+ if(parenp==p) {
+ /* bail out if a field name was not specified */
+ fprintf(stderr, "\ntshark: You didn't specify a field name for %s(*).\n",
+ calc_type_table[j].func_name);
+ exit(10);
+ }
+ }
+
+ field=g_malloc(parenp-p+1);
+ memcpy(field, p, parenp-p);
+ field[parenp-p] = '\0';
+ flt=parenp + 1;
+ if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
+ break;
+ hfi=proto_registrar_get_byname(field);
+ if(!hfi){
+ fprintf(stderr, "\ntshark: There is no field named '%s'.\n",
+ field);
+ g_free(field);
+ exit(10);
+ }
+
+ io->items[i].hf_index=hfi->id;
+ break;
+ }
+ } else {
+ if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
+ flt="";
+ }
+ }
+ if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES ||
+ io->items[i].calc_type==CALC_TYPE_FRAMES ||
+ io->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)){
+ /* check that the type is compatible */
+ switch(hfi->type){
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_UINT64:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ case FT_INT64:
+ /* these types support all calculations */
+ break;
+ case FT_FLOAT:
+ case FT_DOUBLE:
+ /* these types only support SUM, COUNT, MAX, MIN, AVG */
+ switch(io->items[i].calc_type){
+ case CALC_TYPE_SUM:
+ case CALC_TYPE_COUNT:
+ case CALC_TYPE_MAX:
+ case CALC_TYPE_MIN:
+ case CALC_TYPE_AVG:
+ break;
+ default:
+ fprintf(stderr,
+ "\ntshark: %s is a float field, so %s(*) calculations are not supported on it.",
+ field,
+ calc_type_table[j].func_name);
+ exit(10);
+ }
+ break;
+ case FT_RELATIVE_TIME:
+ /* this type only supports SUM, COUNT, MAX, MIN, AVG, LOAD */
+ switch(io->items[i].calc_type){
+ case CALC_TYPE_SUM:
+ case CALC_TYPE_COUNT:
+ case CALC_TYPE_MAX:
+ case CALC_TYPE_MIN:
+ case CALC_TYPE_AVG:
+ case CALC_TYPE_LOAD:
+ break;
+ default:
+ fprintf(stderr,
+ "\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
+ field,
+ calc_type_table[j].func_name);
+ exit(10);
+ }
+ break;
+ default:
+ /*
+ * XXX - support all operations on floating-point
+ * numbers?
+ */
+ if(io->items[i].calc_type!=CALC_TYPE_COUNT){
+ fprintf(stderr,
+ "\ntshark: %s doesn't have integral values, so %s(*) calculations are not supported on it.\n",
+ field,
+ calc_type_table[j].func_name);
+ exit(10);
+ }
+ break;
+ }
+ g_free(field);
+ }
+
+ error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL, iostat_packet, i?NULL:iostat_draw);
+ if(error_string){
+ g_free(io->items);
+ g_free(io);
+ fprintf(stderr, "\ntshark: Couldn't register io,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+static void
+iostat_init(const char *optarg, void* userdata _U_)
+{
+ gdouble interval_float;
+ gint64 interval;
+ int idx=0;
+ io_stat_t *io;
+ const char *filter=NULL;
+
+ if(sscanf(optarg,"io,stat,%lf,%n",&interval_float,&idx)==1){
+ if(idx){
+ if(*(optarg+idx)==',')
+ filter=optarg+idx+1;
+ else
+ filter=optarg+idx;
+ } else {
+ filter=NULL;
+ }
+ } else {
+ fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
+ exit(1);
+ }
+
+ /* if interval is 0, calculate statistics over the whole file
+ * by setting the interval to G_MAXINT32
+ */
+ if(interval_float==0) {
+ interval=G_MAXINT32;
+ } else {
+ /* make interval be number of us rounded to the nearest integer*/
+ interval=(gint64)(interval_float*1000000.0+0.5);
+ }
+
+ if(interval<1){
+ fprintf(stderr,
+ "\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
+ exit(10);
+ }
+
+ io=g_malloc(sizeof(io_stat_t));
+ io->interval=interval;
+ if((!filter)||(filter[0]==0)){
+ io->num_items=1;
+ io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
+ io->filters=g_malloc(sizeof(char *)*io->num_items);
+
+ register_io_tap(io, 0, NULL);
+ } else {
+ const char *str,*pos;
+ char *tmp;
+ int i;
+ /* find how many ',' separated filters we have */
+ str=filter;
+ io->num_items=1;
+ while((str=strchr(str,','))){
+ io->num_items++;
+ str++;
+ }
+
+ io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
+ io->filters=g_malloc(sizeof(char *)*io->num_items);
+
+ /* for each filter, register a tap listener */
+ i=0;
+ str=filter;
+ do{
+ pos=strchr(str,',');
+ if(pos==str){
+ register_io_tap(io, i, NULL);
+ } else if(pos==NULL) {
+ tmp=g_strdup(str);
+ register_io_tap(io, i, tmp);
+ } else {
+ tmp=g_malloc((pos-str)+1);
+ g_strlcpy(tmp,str,(pos-str)+1);
+ register_io_tap(io, i, tmp);
+ }
+ str=pos+1;
+ i++;
+ } while(pos);
+ }
+}
+
+void
+register_tap_listener_iostat(void)
+{
+ register_stat_cmd_arg("io,stat,", iostat_init, NULL);
+}
diff --git a/ui/cli/tap-iousers.c b/ui/cli/tap-iousers.c
new file mode 100644
index 0000000000..175ec28155
--- /dev/null
+++ b/ui/cli/tap-iousers.c
@@ -0,0 +1,780 @@
+/* tap-iousers.c
+ * iostat 2003 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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/packet.h>
+#include <epan/addr_resolv.h>
+#include <epan/tap.h>
+#include <epan/conversation.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-ip.h>
+#include <epan/dissectors/packet-ipv6.h>
+#include <epan/dissectors/packet-ipx.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-udp.h>
+#include <epan/dissectors/packet-eth.h>
+#include <epan/dissectors/packet-sctp.h>
+#include <epan/dissectors/packet-tr.h>
+#include <epan/dissectors/packet-scsi.h>
+#include <epan/dissectors/packet-fc.h>
+#include <epan/dissectors/packet-fddi.h>
+
+typedef struct _io_users_t {
+ const char *type;
+ char *filter;
+ struct _io_users_item_t *items;
+} io_users_t;
+
+typedef struct _io_users_item_t {
+ struct _io_users_item_t *next;
+ char *name1;
+ char *name2;
+ address addr1;
+ address addr2;
+ guint32 frames1;
+ guint32 frames2;
+ guint64 bytes1;
+ guint64 bytes2;
+} io_users_item_t;
+
+
+static int
+iousers_udpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vudph)
+{
+ io_users_t *iu=arg;
+ const e_udphdr *udph=vudph;
+ char name1[256],name2[256];
+ io_users_item_t *iui;
+ int direction=0;
+
+ if(udph->uh_sport>udph->uh_dport){
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
+ } else if(udph->uh_sport<udph->uh_dport){
+ direction=1;
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
+ } else if(CMP_ADDRESS(&udph->ip_src, &udph->ip_dst)>0){
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
+ } else {
+ direction=1;
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&udph->ip_src),get_udp_port(udph->uh_sport));
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&udph->ip_dst),get_udp_port(udph->uh_dport));
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!strcmp(iui->name1, name1))
+ && (!strcmp(iui->name2, name2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+/* iui->addr1=NULL;*/
+ iui->name1=g_strdup(name1);
+/* iui->addr2=NULL;*/
+ iui->name2=g_strdup(name2);
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(direction){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+
+static int
+iousers_sctp_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vsctp)
+{
+ io_users_t *iu=arg;
+ const struct _sctp_info* sctph = vsctp;
+ char name1[256],name2[256], s_sport[10], s_dport[10];
+ io_users_item_t *iui;
+ int direction=0;
+
+ g_snprintf(s_sport, sizeof s_sport, "%d",sctph->sport);
+ g_snprintf(s_dport, sizeof s_dport, "%d",sctph->dport);
+
+ if(sctph->sport > sctph->dport) {
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
+ } else if(sctph->sport < sctph->dport) {
+ direction=1;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
+ } else {
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&sctph->ip_src),s_sport);
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&sctph->ip_dst),s_dport);
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!strcmp(iui->name1, name1))
+ && (!strcmp(iui->name2, name2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+/* iui->addr1=NULL;*/
+ iui->name1=g_strdup(name1);
+/* iui->addr2=NULL;*/
+ iui->name2=g_strdup(name2);
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(direction){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+
+static int
+iousers_tcpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtcph)
+{
+ io_users_t *iu=arg;
+ const struct tcpheader *tcph=vtcph;
+ char name1[256],name2[256];
+ io_users_item_t *iui;
+ int direction=0;
+
+ if(tcph->th_sport>tcph->th_dport){
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
+ } else if(tcph->th_sport<tcph->th_dport){
+ direction=1;
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
+ } else if(CMP_ADDRESS(&tcph->ip_src, &tcph->ip_dst)>0){
+ direction=0;
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
+ } else {
+ direction=1;
+ g_snprintf(name2,256,"%s:%s",ep_address_to_str(&tcph->ip_src),get_tcp_port(tcph->th_sport));
+ g_snprintf(name1,256,"%s:%s",ep_address_to_str(&tcph->ip_dst),get_tcp_port(tcph->th_dport));
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!strcmp(iui->name1, name1))
+ && (!strcmp(iui->name2, name2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+/* iui->addr1=NULL;*/
+ iui->name1=g_strdup(name1);
+/* iui->addr2=NULL;*/
+ iui->name2=g_strdup(name2);
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(direction){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+
+static int
+iousers_ip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
+{
+ io_users_t *iu=arg;
+ const ws_ip *iph=vip;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&iph->ip_src, &iph->ip_dst)>0){
+ addr1=&iph->ip_src;
+ addr2=&iph->ip_dst;
+ } else {
+ addr2=&iph->ip_src;
+ addr1=&iph->ip_dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&iph->ip_dst, &iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_ipv6_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
+{
+ io_users_t *iu=arg;
+ const struct ip6_hdr *ip6h=vip;
+ address src, dst;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ /* Addresses aren't implemented as 'address' type in struct ip6_hdr */
+ src.type = dst.type = AT_IPv6;
+ src.len = dst.len = sizeof(struct e_in6_addr);
+ src.data = &ip6h->ip6_src;
+ dst.data = &ip6h->ip6_dst;
+
+ if(CMP_ADDRESS(&src, &dst)>0){
+ addr1=&src;
+ addr2=&dst;
+ } else {
+ addr2=&src;
+ addr1=&dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&dst, &iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_ipx_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vipx)
+{
+ io_users_t *iu=arg;
+ const ipxhdr_t *ipxh=vipx;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&ipxh->ipx_src, &ipxh->ipx_dst)>0){
+ addr1=&ipxh->ipx_src;
+ addr2=&ipxh->ipx_dst;
+ } else {
+ addr2=&ipxh->ipx_src;
+ addr1=&ipxh->ipx_dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&ipxh->ipx_dst, &iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_fc_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vfc)
+{
+ io_users_t *iu=arg;
+ const fc_hdr *fchdr=vfc;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&fchdr->s_id, &fchdr->d_id)<0){
+ addr1=&fchdr->s_id;
+ addr2=&fchdr->d_id;
+ } else {
+ addr2=&fchdr->s_id;
+ addr1=&fchdr->d_id;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&fchdr->d_id,&iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_eth_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
+{
+ io_users_t *iu=arg;
+ const eth_hdr *ehdr=veth;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
+ addr1=&ehdr->src;
+ addr2=&ehdr->dst;
+ } else {
+ addr2=&ehdr->src;
+ addr1=&ehdr->dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_fddi_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *veth)
+{
+ io_users_t *iu=arg;
+ const fddi_hdr *ehdr=veth;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&ehdr->src, &ehdr->dst)<0){
+ addr1=&ehdr->src;
+ addr2=&ehdr->dst;
+ } else {
+ addr2=&ehdr->src;
+ addr1=&ehdr->dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&ehdr->dst,&iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static int
+iousers_tr_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vtr)
+{
+ io_users_t *iu=arg;
+ const tr_hdr *trhdr=vtr;
+ const address *addr1, *addr2;
+ io_users_item_t *iui;
+
+ if(CMP_ADDRESS(&trhdr->src, &trhdr->dst)<0){
+ addr1=&trhdr->src;
+ addr2=&trhdr->dst;
+ } else {
+ addr2=&trhdr->src;
+ addr1=&trhdr->dst;
+ }
+
+ for(iui=iu->items;iui;iui=iui->next){
+ if((!CMP_ADDRESS(&iui->addr1, addr1))
+ &&(!CMP_ADDRESS(&iui->addr2, addr2)) ){
+ break;
+ }
+ }
+
+ if(!iui){
+ iui=g_malloc(sizeof(io_users_item_t));
+ iui->next=iu->items;
+ iu->items=iui;
+ COPY_ADDRESS(&iui->addr1, addr1);
+ iui->name1=g_strdup(ep_address_to_str(addr1));
+ COPY_ADDRESS(&iui->addr2, addr2);
+ iui->name2=g_strdup(ep_address_to_str(addr2));
+ iui->frames1=0;
+ iui->frames2=0;
+ iui->bytes1=0;
+ iui->bytes2=0;
+ }
+
+ if(!CMP_ADDRESS(&trhdr->dst,&iui->addr1)){
+ iui->frames1++;
+ iui->bytes1+=pinfo->fd->pkt_len;
+ } else {
+ iui->frames2++;
+ iui->bytes2+=pinfo->fd->pkt_len;
+ }
+
+ return 1;
+}
+
+static void
+iousers_draw(void *arg)
+{
+ io_users_t *iu = arg;
+ io_users_item_t *iui;
+ guint32 last_frames, max_frames;
+
+ printf("================================================================================\n");
+ printf("%s Conversations\n",iu->type);
+ printf("Filter:%s\n",iu->filter?iu->filter:"<No Filter>");
+ printf(" | <- | | -> | | Total |\n");
+ printf(" | Frames Bytes | | Frames Bytes | | Frames Bytes |\n");
+ max_frames=0xffffffff;
+ do {
+ last_frames=0;
+ for(iui=iu->items;iui;iui=iui->next){
+ guint32 tot_frames;
+ tot_frames=iui->frames1+iui->frames2;
+
+ if((tot_frames>last_frames)
+ &&(tot_frames<max_frames)){
+ last_frames=tot_frames;
+ }
+ }
+ for(iui=iu->items;iui;iui=iui->next){
+ guint32 tot_frames;
+ tot_frames=iui->frames1+iui->frames2;
+
+ if(tot_frames==last_frames){
+ printf("%-20s <-> %-20s %6d %9" G_GINT64_MODIFIER "d %6d %9" G_GINT64_MODIFIER "d %6d %9" G_GINT64_MODIFIER "d\n",
+ iui->name1, iui->name2,
+ iui->frames1, iui->bytes1,
+ iui->frames2, iui->bytes2,
+ iui->frames1+iui->frames2,
+ iui->bytes1+iui->bytes2
+ );
+ }
+ }
+ max_frames=last_frames;
+ } while(last_frames);
+ printf("================================================================================\n");
+}
+
+static void
+iousers_init(const char *optarg, void* userdata _U_)
+{
+ const char *filter=NULL;
+ const char *tap_type, *tap_type_name;
+ tap_packet_cb packet_func;
+ io_users_t *iu=NULL;
+ GString *error_string;
+
+ if(!strncmp(optarg,"conv,eth",8)){
+ if(optarg[8]==','){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+ tap_type="eth";
+ tap_type_name="Ethernet";
+ packet_func=iousers_eth_packet;
+ } else if(!strncmp(optarg,"conv,fc",7)){
+ if(optarg[7]==','){
+ filter=optarg+8;
+ } else {
+ filter=NULL;
+ }
+ tap_type="fc";
+ tap_type_name="Fibre Channel";
+ packet_func=iousers_fc_packet;
+ } else if(!strncmp(optarg,"conv,fddi",9)){
+ if(optarg[9]==','){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+ tap_type="fddi";
+ tap_type_name="FDDI";
+ packet_func=iousers_fddi_packet;
+ } else if(!strncmp(optarg,"conv,tcp",8)){
+ if(optarg[8]==','){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+ tap_type="tcp";
+ tap_type_name="TCP";
+ packet_func=iousers_tcpip_packet;
+ } else if(!strncmp(optarg,"conv,udp",8)){
+ if(optarg[8]==','){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+ tap_type="udp";
+ tap_type_name="UDP";
+ packet_func=iousers_udpip_packet;
+ } else if(!strncmp(optarg,"conv,tr",7)){
+ if(optarg[7]==','){
+ filter=optarg+8;
+ } else {
+ filter=NULL;
+ }
+ tap_type="tr";
+ tap_type_name="Token Ring";
+ packet_func=iousers_tr_packet;
+ } else if(!strncmp(optarg,"conv,ipx",8)){
+ if(optarg[8]==','){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+ tap_type="ipx";
+ tap_type_name="IPX";
+ packet_func=iousers_ipx_packet;
+ } else if(!strncmp(optarg,"conv,ipv6",9)){
+ if(optarg[9]==','){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+ tap_type="ipv6";
+ tap_type_name="IPv6";
+ packet_func=iousers_ipv6_packet;
+ } else if(!strncmp(optarg,"conv,ip",7)){
+ if(optarg[7]==','){
+ filter=optarg+8;
+ } else {
+ filter=NULL;
+ }
+ tap_type="ip";
+ tap_type_name="IPv4";
+ packet_func=iousers_ip_packet;
+ } else if(!strncmp(optarg,"conv,sctp",9)) {
+ if(optarg[9]==','){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+ tap_type="sctp";
+ tap_type_name="SCTP";
+ packet_func=iousers_sctp_packet;
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z conv,<type>[,<filter>]\" argument\n");
+ fprintf(stderr," <type> must be one of\n");
+ fprintf(stderr," \"eth\"\n");
+ fprintf(stderr," \"fc\"\n");
+ fprintf(stderr," \"fddi\"\n");
+ fprintf(stderr," \"ip\"\n");
+ fprintf(stderr," \"ipx\"\n");
+ fprintf(stderr," \"sctp\"\n");
+ fprintf(stderr," \"tcp\"\n");
+ fprintf(stderr," \"tr\"\n");
+ fprintf(stderr," \"udp\"\n");
+ exit(1);
+ }
+
+
+ iu=g_malloc(sizeof(io_users_t));
+ iu->items=NULL;
+ iu->type=tap_type_name;
+ if(filter){
+ iu->filter=g_strdup(filter);
+ } else {
+ iu->filter=NULL;
+ }
+
+ error_string=register_tap_listener(tap_type, iu, filter, 0, NULL, packet_func, iousers_draw);
+ if(error_string){
+ if(iu->items){
+ g_free(iu->items);
+ }
+ g_free(iu);
+ fprintf(stderr, "tshark: Couldn't register conversations tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+}
+
+void
+register_tap_listener_iousers(void)
+{
+ register_stat_cmd_arg("conv,", iousers_init, NULL);
+}
diff --git a/ui/cli/tap-macltestat.c b/ui/cli/tap-macltestat.c
new file mode 100644
index 0000000000..b91a55396f
--- /dev/null
+++ b/ui/cli/tap-macltestat.c
@@ -0,0 +1,527 @@
+/* tap-macltestat.c
+ * Copyright 2011 Martin Mathieson
+ *
+ * $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.
+ */
+
+
+#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.h>
+#include <epan/packet_info.h>
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-mac-lte.h>
+
+/**********************************************/
+/* Table column identifiers and title strings */
+
+enum {
+ RNTI_COLUMN,
+ RNTI_TYPE_COLUMN,
+ UEID_COLUMN,
+ UL_FRAMES_COLUMN,
+ UL_BYTES_COLUMN,
+ UL_BW_COLUMN,
+ UL_PADDING_PERCENT_COLUMN,
+ UL_RETX_FRAMES_COLUMN,
+ DL_FRAMES_COLUMN,
+ DL_BYTES_COLUMN,
+ DL_BW_COLUMN,
+ DL_CRC_FAILED_COLUMN,
+ DL_CRC_HIGH_CODE_RATE_COLUMN,
+ DL_CRC_PDSCH_LOST_COLUMN,
+ DL_CRC_DUPLICATE_NONZERO_RV_COLUMN,
+ DL_RETX_FRAMES_COLUMN,
+ NUM_UE_COLUMNS
+};
+
+
+static const gchar *ue_titles[] = { " RNTI", " Type", "UEId",
+ "UL Frames", "UL Bytes", "UL Mb/sec", " UL Pad %", "UL ReTX",
+ "DL Frames", "DL Bytes", "DL Mb/sec", "DL CRC Fail", "DL CRC HCR", "DL CRC PDSCH Lost", "DL CRC DupNonZeroRV", "DL ReTX"};
+
+
+/* Stats for one UE */
+typedef struct mac_lte_row_data {
+ /* Key for matching this row */
+ guint16 rnti;
+ guint8 rnti_type;
+ guint16 ueid;
+
+ gboolean is_predefined_data;
+
+ guint32 UL_frames;
+ guint32 UL_raw_bytes; /* all bytes */
+ guint32 UL_total_bytes; /* payload */
+ nstime_t UL_time_start;
+ nstime_t UL_time_stop;
+ guint32 UL_padding_bytes;
+ guint32 UL_CRC_errors;
+ guint32 UL_retx_frames;
+
+ guint32 DL_frames;
+ guint32 DL_total_bytes;
+ nstime_t DL_time_start;
+ nstime_t DL_time_stop;
+ guint32 DL_CRC_failures;
+ guint32 DL_CRC_high_code_rate;
+ guint32 DL_CRC_PDSCH_lost;
+ guint32 DL_CRC_Duplicate_NonZero_RV;
+ guint32 DL_retx_frames;
+
+} mac_lte_row_data;
+
+
+/* One row/UE in the UE table */
+typedef struct mac_lte_ep {
+ struct mac_lte_ep* next;
+ struct mac_lte_row_data stats;
+} mac_lte_ep_t;
+
+
+/* Common channel stats */
+typedef struct mac_lte_common_stats {
+ guint32 all_frames;
+ guint32 bch_frames;
+ guint32 bch_bytes;
+ guint32 pch_frames;
+ guint32 pch_bytes;
+ guint32 rar_frames;
+ guint32 rar_entries;
+
+ guint16 max_ul_ues_in_tti;
+ guint16 max_dl_ues_in_tti;
+} mac_lte_common_stats;
+
+
+/* Top-level struct for MAC LTE statistics */
+typedef struct mac_lte_stat_t {
+ /* Common stats */
+ mac_lte_common_stats common_stats;
+
+ /* Keep track of unique rntis & ueids */
+ guint8 used_ueids[65535];
+ guint8 used_rntis[65535];
+ guint16 number_of_ueids;
+ guint16 number_of_rntis;
+
+ mac_lte_ep_t *ep_list;
+} mac_lte_stat_t;
+
+
+/* Reset the statistics window */
+static void
+mac_lte_stat_reset(void *phs)
+{
+ mac_lte_stat_t* mac_lte_stat = (mac_lte_stat_t *)phs;
+ mac_lte_ep_t* list = mac_lte_stat->ep_list;
+
+ /* Reset counts of unique ueids & rntis */
+ memset(mac_lte_stat->used_ueids, 0, 65535);
+ mac_lte_stat->number_of_ueids = 0;
+ memset(mac_lte_stat->used_rntis, 0, 65535);
+ mac_lte_stat->number_of_rntis = 0;
+
+ /* Zero common stats */
+ memset(&(mac_lte_stat->common_stats), 0, sizeof(mac_lte_common_stats));
+
+ if (!list) {
+ return;
+ }
+
+ mac_lte_stat->ep_list = NULL;
+}
+
+
+/* Allocate a mac_lte_ep_t struct to store info for new UE */
+static mac_lte_ep_t* alloc_mac_lte_ep(struct mac_lte_tap_info *si, packet_info *pinfo _U_)
+{
+ mac_lte_ep_t* ep;
+
+ if (!si) {
+ return NULL;
+ }
+
+ if (!(ep = g_malloc(sizeof(mac_lte_ep_t)))) {
+ return NULL;
+ }
+
+ /* Copy SI data into ep->stats */
+ ep->stats.rnti = si->rnti;
+ ep->stats.rnti_type = si->rntiType;
+ ep->stats.ueid = si->ueid;
+
+ /* Counts for new UE are all 0 */
+ ep->stats.UL_frames = 0;
+ ep->stats.DL_frames = 0;
+ ep->stats.UL_total_bytes = 0;
+ ep->stats.UL_raw_bytes = 0;
+ ep->stats.UL_padding_bytes = 0;
+ ep->stats.DL_total_bytes = 0;
+ ep->stats.UL_CRC_errors = 0;
+ ep->stats.DL_CRC_failures = 0;
+ ep->stats.DL_CRC_high_code_rate = 0;
+ ep->stats.DL_CRC_PDSCH_lost = 0;
+ ep->stats.DL_CRC_Duplicate_NonZero_RV = 0;
+ ep->stats.UL_retx_frames = 0;
+ ep->stats.DL_retx_frames = 0;
+
+ ep->next = NULL;
+
+ return ep;
+}
+
+
+/* Update counts of unique rntis & ueids */
+static void update_ueid_rnti_counts(guint16 rnti, guint16 ueid, mac_lte_stat_t *hs)
+{
+ if (!hs->used_ueids[ueid]) {
+ hs->used_ueids[ueid] = TRUE;
+ hs->number_of_ueids++;
+ }
+ if (!hs->used_rntis[rnti]) {
+ hs->used_rntis[rnti] = TRUE;
+ hs->number_of_rntis++;
+ }
+}
+
+
+/* Process stat struct for a MAC LTE frame */
+static int
+mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
+ const void *phi)
+{
+ /* Get reference to stat window instance */
+ mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
+ mac_lte_ep_t *tmp = NULL, *te = NULL;
+
+ /* Cast tap info struct */
+ struct mac_lte_tap_info *si = (struct mac_lte_tap_info *)phi;
+
+ if (!hs) {
+ return 0;
+ }
+
+ hs->common_stats.all_frames++;
+
+ /* For common channels, just update global counters */
+ switch (si->rntiType) {
+ case P_RNTI:
+ hs->common_stats.pch_frames++;
+ hs->common_stats.pch_bytes += si->single_number_of_bytes;
+ return 1;
+ case SI_RNTI:
+ case NO_RNTI:
+ hs->common_stats.bch_frames++;
+ hs->common_stats.bch_bytes += si->single_number_of_bytes;
+ return 1;
+ case RA_RNTI:
+ hs->common_stats.rar_frames++;
+ hs->common_stats.rar_entries += si->number_of_rars;
+ return 1;
+ case C_RNTI:
+ case SPS_RNTI:
+ /* Drop through for per-UE update */
+ break;
+
+ default:
+ /* Error */
+ return 0;
+ }
+
+ /* Check max UEs/tti counter */
+ switch (si->direction) {
+ case DIRECTION_UPLINK:
+ hs->common_stats.max_ul_ues_in_tti =
+ MAX(hs->common_stats.max_ul_ues_in_tti, si->ueInTTI);
+ break;
+ case DIRECTION_DOWNLINK:
+ hs->common_stats.max_dl_ues_in_tti =
+ MAX(hs->common_stats.max_dl_ues_in_tti, si->ueInTTI);
+ break;
+ }
+
+ /* For per-UE data, must create a new row if none already existing */
+ if (!hs->ep_list) {
+ /* Allocate new list */
+ hs->ep_list = alloc_mac_lte_ep(si, pinfo);
+ /* Make it the first/only entry */
+ te = hs->ep_list;
+
+ /* Update counts of unique ueids & rntis */
+ update_ueid_rnti_counts(si->rnti, si->ueid, hs);
+ } else {
+ /* Look among existing rows for this RNTI */
+ for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
+ /* Match only by RNTI and UEId together */
+ if ((tmp->stats.rnti == si->rnti) &&
+ (tmp->stats.ueid == si->ueid)){
+ te = tmp;
+ break;
+ }
+ }
+
+ /* Not found among existing, so create a new one anyway */
+ if (te == NULL) {
+ if ((te = alloc_mac_lte_ep(si, pinfo))) {
+ /* Add new item to end of list */
+ mac_lte_ep_t *p = hs->ep_list;
+ while (p->next) {
+ p = p->next;
+ }
+ p->next = te;
+ te->next = NULL;
+
+ /* Update counts of unique ueids & rntis */
+ update_ueid_rnti_counts(si->rnti, si->ueid, hs);
+ }
+ }
+ }
+
+ /* Really should have a row pointer by now */
+ if (!te) {
+ return 0;
+ }
+
+ /* Update entry with details from si */
+ te->stats.rnti = si->rnti;
+ te->stats.is_predefined_data = si->isPredefinedData;
+
+ /* Uplink */
+ if (si->direction == DIRECTION_UPLINK) {
+ if (si->isPHYRetx) {
+ te->stats.UL_retx_frames++;
+ return 1;
+ }
+
+ if (si->crcStatusValid && (si->crcStatus != crc_success)) {
+ te->stats.UL_CRC_errors++;
+ return 1;
+ }
+
+ /* Update time range */
+ if (te->stats.UL_frames == 0) {
+ te->stats.UL_time_start = si->time;
+ }
+ te->stats.UL_time_stop = si->time;
+
+ te->stats.UL_frames++;
+
+ te->stats.UL_raw_bytes += si->raw_length;
+ te->stats.UL_padding_bytes += si->padding_bytes;
+
+ if (si->isPredefinedData) {
+ te->stats.UL_total_bytes += si->single_number_of_bytes;
+ }
+ else {
+ te->stats.UL_total_bytes += si->single_number_of_bytes;
+ }
+ }
+
+ /* Downlink */
+ else {
+ if (si->isPHYRetx) {
+ te->stats.DL_retx_frames++;
+ return 1;
+ }
+
+ if (si->crcStatusValid && (si->crcStatus != crc_success)) {
+ switch (si->crcStatus) {
+ case crc_fail:
+ te->stats.DL_CRC_failures++;
+ break;
+ case crc_high_code_rate:
+ te->stats.DL_CRC_high_code_rate++;
+ break;
+ case crc_pdsch_lost:
+ te->stats.DL_CRC_PDSCH_lost++;
+ break;
+ case crc_duplicate_nonzero_rv:
+ te->stats.DL_CRC_Duplicate_NonZero_RV++;
+ break;
+
+ default:
+ /* Something went wrong! */
+ break;
+ }
+ return 1;
+ }
+
+ /* Update time range */
+ if (te->stats.DL_frames == 0) {
+ te->stats.DL_time_start = si->time;
+ }
+ te->stats.DL_time_stop = si->time;
+
+ te->stats.DL_frames++;
+
+ if (si->isPredefinedData) {
+ te->stats.DL_total_bytes += si->single_number_of_bytes;
+ }
+ else {
+ te->stats.DL_total_bytes += si->single_number_of_bytes;
+ }
+
+ }
+
+ return 1;
+}
+
+
+/* Calculate and return a bandwidth figure, in Mbs */
+static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
+{
+ if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
+ float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
+ (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
+ return ((bytes * 8) / elapsed_ms) / 1000;
+ }
+ else {
+ return 0.0;
+ }
+}
+
+
+/* Output the accumulated stats */
+static void
+mac_lte_stat_draw(void *phs)
+{
+ gint i;
+ guint16 number_of_ues = 0;
+
+ /* Deref the struct */
+ mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
+ mac_lte_ep_t* list = hs->ep_list, *tmp = 0;
+
+ /* System data */
+ printf("System data:\n");
+ printf("============\n");
+ printf("Max UL UEs/TTI: %u Max DL UEs/TTI: %u\n\n",
+ hs->common_stats.max_ul_ues_in_tti, hs->common_stats.max_dl_ues_in_tti);
+
+ /* Common channel data */
+ printf("Common channel data:\n");
+ printf("====================\n");
+ printf("BCH Frames: %u ", hs->common_stats.bch_frames);
+ printf("BCH Bytes: %u ", hs->common_stats.bch_bytes);
+ printf("PCH Frames: %u ", hs->common_stats.pch_frames);
+ printf("PCH Bytes: %u ", hs->common_stats.pch_bytes);
+ printf("RAR Frames: %u ", hs->common_stats.rar_frames);
+ printf("RAR Entries: %u\n\n", hs->common_stats.rar_entries);
+
+
+ /* Per-UE table entries */
+
+ /* Set title to show how many UEs in table */
+ for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
+ printf("UL/DL-SCH data (%u entries - %u unique RNTIs, %u unique UEIds):\n",
+ number_of_ues, hs->number_of_rntis, hs->number_of_ueids);
+ printf("==================================================================\n");
+
+ /* Show column titles */
+ for (i=0; i < NUM_UE_COLUMNS; i++) {
+ printf("%s ", ue_titles[i]);
+ }
+ printf("\n");
+
+ /* Write a row for each UE */
+ for (tmp = list; tmp; tmp=tmp->next) {
+ /* Calculate bandwidth */
+ float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
+ &tmp->stats.UL_time_stop,
+ tmp->stats.UL_total_bytes);
+ float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
+ &tmp->stats.DL_time_stop,
+ tmp->stats.DL_total_bytes);
+
+ printf("%5u %7s %5u %10u %9u %10f %10f %8u %10u %9u %10f %12u %11u %18u %20u %8u\n",
+ tmp->stats.rnti,
+ (tmp->stats.rnti_type == C_RNTI) ? "C-RNTI" : "SPS-RNTI",
+ tmp->stats.ueid,
+ tmp->stats.UL_frames,
+ tmp->stats.UL_total_bytes,
+ UL_bw,
+ tmp->stats.UL_total_bytes ?
+ (((float)tmp->stats.UL_padding_bytes / (float)tmp->stats.UL_raw_bytes) * 100.0) :
+ 0.0,
+ tmp->stats.UL_retx_frames,
+ tmp->stats.DL_frames,
+ tmp->stats.DL_total_bytes,
+ DL_bw,
+ tmp->stats.DL_CRC_failures,
+ tmp->stats.DL_CRC_high_code_rate,
+ tmp->stats.DL_CRC_PDSCH_lost,
+ tmp->stats.DL_CRC_Duplicate_NonZero_RV,
+ tmp->stats.DL_retx_frames);
+ }
+}
+
+/* Create a new MAC LTE stats struct */
+static void mac_lte_stat_init(const char *optarg, void *userdata _U_)
+{
+ mac_lte_stat_t *hs;
+ const char *filter = NULL;
+ GString *error_string;
+
+ /* Check for a filter string */
+ if (strncmp(optarg, "mac-lte,stat,", 13) == 0) {
+ /* Skip those characters from filter to display */
+ filter = optarg + 13;
+ }
+ else {
+ /* No filter */
+ filter = NULL;
+ }
+
+ /* Create struct */
+ hs = g_malloc(sizeof(mac_lte_stat_t));
+ hs->ep_list = NULL;
+
+ error_string = register_tap_listener("mac-lte", hs,
+ filter, 0,
+ mac_lte_stat_reset,
+ mac_lte_stat_packet,
+ mac_lte_stat_draw);
+ if (error_string) {
+ g_string_free(error_string, TRUE);
+ g_free(hs);
+ exit(1);
+ }
+}
+
+
+/* Register this tap listener (need void on own so line register function found) */
+void
+register_tap_listener_mac_lte_stat(void)
+{
+ register_stat_cmd_arg("mac-lte,stat", mac_lte_stat_init, NULL);
+}
+
diff --git a/ui/cli/tap-megacostat.c b/ui/cli/tap-megacostat.c
new file mode 100644
index 0000000000..6e5186c688
--- /dev/null
+++ b/ui/cli/tap-megacostat.c
@@ -0,0 +1,148 @@
+/* tap-megacostat.c
+ * mgcpstat 2003 Lars Roland
+ * Copyright 2008, Ericsson AB
+ * By Balint Reczey <balint.reczey@ericsson.com>
+ *
+ * $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.
+ */
+
+#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/value_string.h"
+#include "epan/gcp.h"
+#include "timestats.h"
+#include <epan/prefs-int.h>
+
+#include "tap-megaco-common.h"
+
+
+
+static void
+megacostat_draw(void *pms)
+{
+ megacostat_t *ms=(megacostat_t *)pms;
+ int i;
+
+ /* printing results */
+ printf("\n");
+ printf("=====================================================================================================\n");
+ printf("MEGACO Response Time Delay (RTD) Statistics:\n");
+ printf("Filter for statistics: %s\n",ms->filter?ms->filter:"");
+ printf("Duplicate requests: %u\n",ms->req_dup_num);
+ printf("Duplicate responses: %u\n",ms->rsp_dup_num);
+ printf("Open requests: %u\n",ms->open_req_num);
+ printf("Discarded responses: %u\n",ms->disc_rsp_num);
+ printf(" Type | Messages | Min RTD | Max RTD | Avg RTD | Min in Frame | Max in Frame |\n");
+ for(i=0;i<NUM_TIMESTATS;i++) {
+ if(ms->rtd[i].num) {
+ printf("%5s | %7u | %8.2f msec | %8.2f msec | %8.2f msec | %10u | %10u |\n",
+ val_to_str(i,megaco_message_type,"Other"),ms->rtd[i].num,
+ nstime_to_msec(&(ms->rtd[i].min)), nstime_to_msec(&(ms->rtd[i].max)),
+ get_average(&(ms->rtd[i].tot), ms->rtd[i].num),
+ ms->rtd[i].min_num, ms->rtd[i].max_num
+ );
+ }
+ }
+ printf("=====================================================================================================\n");
+}
+
+
+static void
+megacostat_init(const char *optarg, void* userdata _U_)
+{
+ megacostat_t *ms;
+ int i;
+ GString *error_string;
+ pref_t *megaco_ctx_track,*h248_ctx_track;
+
+ megaco_ctx_track = prefs_find_preference(prefs_find_module("megaco"),"ctx_info");
+ h248_ctx_track = prefs_find_preference(prefs_find_module("h248"),"ctx_info");
+
+ if (!megaco_ctx_track || !h248_ctx_track) {
+ /* No such preferences */
+ return;
+ }
+
+ if (!*megaco_ctx_track->varp.boolp || !*h248_ctx_track->varp.boolp) {
+ printf("Track Context option at Protocols -> MEGACO and Protocols -> H248 preferences\n");
+ printf("has to be set to true to enable measurement of service response times.\n");
+ exit(1);
+ }
+
+ ms=g_malloc(sizeof(megacostat_t));
+ if(!strncmp(optarg,"megaco,rtd,",11)){
+ ms->filter=g_strdup(optarg+11);
+ } else {
+ ms->filter=NULL;
+ }
+
+ for(i=0;i<NUM_TIMESTATS;i++) {
+ ms->rtd[i].num=0;
+ ms->rtd[i].min_num=0;
+ ms->rtd[i].max_num=0;
+ ms->rtd[i].min.secs=0;
+ ms->rtd[i].min.nsecs=0;
+ ms->rtd[i].max.secs=0;
+ ms->rtd[i].max.nsecs=0;
+ ms->rtd[i].tot.secs=0;
+ ms->rtd[i].tot.nsecs=0;
+ }
+
+ ms->open_req_num=0;
+ ms->disc_rsp_num=0;
+ ms->req_dup_num=0;
+ ms->rsp_dup_num=0;
+
+ error_string=register_tap_listener("megaco", ms, ms->filter, 0, NULL, megacostat_packet, megacostat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ms->filter);
+ g_free(ms);
+
+ fprintf(stderr, "tshark: Couldn't register megaco,rtd tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_megacostat(void)
+{
+ /* We don't register this tap, if we don't have the megaco plugin loaded.*/
+ if (find_tap_id("megaco")) {
+ register_stat_cmd_arg("megaco,rtd", megacostat_init, NULL);
+ }
+}
+
diff --git a/ui/cli/tap-mgcpstat.c b/ui/cli/tap-mgcpstat.c
new file mode 100644
index 0000000000..f5b0b1ee79
--- /dev/null
+++ b/ui/cli/tap-mgcpstat.c
@@ -0,0 +1,230 @@
+/* tap-mgcpstat.c
+ * mgcpstat 2003 Lars Roland
+ *
+ * $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.
+ */
+
+#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/value_string.h"
+#include "epan/dissectors/packet-mgcp.h"
+#include "timestats.h"
+
+#define NUM_TIMESTATS 11
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _mgcpstat_t {
+ char *filter;
+ timestat_t rtd[NUM_TIMESTATS];
+ guint32 open_req_num;
+ guint32 disc_rsp_num;
+ guint32 req_dup_num;
+ guint32 rsp_dup_num;
+} mgcpstat_t;
+
+static const value_string mgcp_mesage_type[] = {
+ { 0, "Overall"},
+ { 1, "EPCF "},
+ { 2, "CRCX "},
+ { 3, "MDCX "},
+ { 4, "DLCX "},
+ { 5, "RQNT "},
+ { 6, "NTFY "},
+ { 7, "AUEP "},
+ { 8, "AUCX "},
+ { 9, "RSIP "},
+ { 0, NULL}
+};
+
+static int
+mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi)
+{
+ mgcpstat_t *ms=(mgcpstat_t *)pms;
+ const mgcp_info_t *mi=pmi;
+ nstime_t delta;
+ int ret = 0;
+
+ switch (mi->mgcp_type) {
+
+ case MGCP_REQUEST:
+ if(mi->is_duplicate){
+ /* Duplicate is ignored */
+ ms->req_dup_num++;
+ }
+ else {
+ ms->open_req_num++;
+ }
+ break;
+
+ case MGCP_RESPONSE:
+ if(mi->is_duplicate){
+ /* Duplicate is ignored */
+ ms->rsp_dup_num++;
+ }
+ else if (!mi->request_available) {
+ /* no request was seen */
+ ms->disc_rsp_num++;
+ }
+ else {
+ ms->open_req_num--;
+ /* calculate time delta between request and response */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &mi->req_time);
+
+ time_stat_update(&(ms->rtd[0]),&delta, pinfo);
+
+ if (g_ascii_strncasecmp(mi->code, "EPCF", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[1]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "CRCX", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[2]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "MDCX", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[3]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "DLCX", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[4]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "RQNT", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[5]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "NTFY", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[6]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "AUEP", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[7]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "AUCX", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[8]),&delta, pinfo);
+ }
+ else if (g_ascii_strncasecmp(mi->code, "RSIP", 4) == 0 ) {
+ time_stat_update(&(ms->rtd[9]),&delta, pinfo);
+ }
+ else {
+ time_stat_update(&(ms->rtd[10]),&delta, pinfo);
+ }
+
+ ret = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void
+mgcpstat_draw(void *pms)
+{
+ mgcpstat_t *ms=(mgcpstat_t *)pms;
+ int i;
+
+ /* printing results */
+ printf("\n");
+ printf("=====================================================================================================\n");
+ printf("MGCP Response Time Delay (RTD) Statistics:\n");
+ printf("Filter for statistics: %s\n",ms->filter?ms->filter:"");
+ printf("Duplicate requests: %u\n",ms->req_dup_num);
+ printf("Duplicate responses: %u\n",ms->rsp_dup_num);
+ printf("Open requests: %u\n",ms->open_req_num);
+ printf("Discarded responses: %u\n",ms->disc_rsp_num);
+ printf("Type | Messages | Min RTD | Max RTD | Avg RTD | Min in Frame | Max in Frame |\n");
+ for(i=0;i<NUM_TIMESTATS;i++) {
+ if(ms->rtd[i].num) {
+ printf("%s | %7u | %8.2f msec | %8.2f msec | %8.2f msec | %10u | %10u |\n",
+ val_to_str(i,mgcp_mesage_type,"Other "),ms->rtd[i].num,
+ nstime_to_msec(&(ms->rtd[i].min)), nstime_to_msec(&(ms->rtd[i].max)),
+ get_average(&(ms->rtd[i].tot), ms->rtd[i].num),
+ ms->rtd[i].min_num, ms->rtd[i].max_num
+ );
+ }
+ }
+ printf("=====================================================================================================\n");
+}
+
+
+static void
+mgcpstat_init(const char *optarg, void* userdata _U_)
+{
+ mgcpstat_t *ms;
+ int i;
+ GString *error_string;
+
+ ms=g_malloc(sizeof(mgcpstat_t));
+ if(!strncmp(optarg,"mgcp,rtd,",9)){
+ ms->filter=g_strdup(optarg+9);
+ } else {
+ ms->filter=NULL;
+ }
+
+ for(i=0;i<NUM_TIMESTATS;i++) {
+ ms->rtd[i].num=0;
+ ms->rtd[i].min_num=0;
+ ms->rtd[i].max_num=0;
+ ms->rtd[i].min.secs=0;
+ ms->rtd[i].min.nsecs=0;
+ ms->rtd[i].max.secs=0;
+ ms->rtd[i].max.nsecs=0;
+ ms->rtd[i].tot.secs=0;
+ ms->rtd[i].tot.nsecs=0;
+ }
+
+ ms->open_req_num=0;
+ ms->disc_rsp_num=0;
+ ms->req_dup_num=0;
+ ms->rsp_dup_num=0;
+
+ error_string=register_tap_listener("mgcp", ms, ms->filter, 0, NULL, mgcpstat_packet, mgcpstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ms->filter);
+ g_free(ms);
+
+ fprintf(stderr, "tshark: Couldn't register mgcp,rtd tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_mgcpstat(void)
+{
+ /* We don't register this tap, if we don't have the mgcp plugin loaded.*/
+ if (find_tap_id("mgcp")) {
+ register_stat_cmd_arg("mgcp,rtd", mgcpstat_init, NULL);
+ }
+}
+
diff --git a/ui/cli/tap-protocolinfo.c b/ui/cli/tap-protocolinfo.c
new file mode 100644
index 0000000000..a3f2b37666
--- /dev/null
+++ b/ui/cli/tap-protocolinfo.c
@@ -0,0 +1,144 @@
+/* tap-protocolinfo.c
+ * protohierstat 2002 Ronnie Sahlberg
+ *
+ * $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 Protocol Column Info tap for tshark */
+
+#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/epan_dissect.h"
+#include "epan/column-utils.h"
+#include "epan/proto.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/strutil.h>
+
+typedef struct _pci_t {
+ char *filter;
+ int hf_index;
+} pci_t;
+
+
+static int
+protocolinfo_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
+{
+ pci_t *rs=prs;
+ GPtrArray *gp;
+ guint i;
+ char *str;
+
+ /*
+ * XXX - there needs to be a way for "protocolinfo_init()" to
+ * find out whether the columns are being generated and, if not,
+ * to report an error and exit, as the whole point of this tap
+ * is to modify the columns, and if the columns aren't being
+ * displayed, that makes this tap somewhat pointless.
+ *
+ * To prevent a crash, we check whether INFO column is writable
+ * and, if not, we report that error and exit.
+ */
+ if (!check_col(pinfo->cinfo, COL_INFO)) {
+ fprintf(stderr, "tshark: the proto,colinfo tap doesn't work if the INFO column isn't being printed.\n");
+ exit(1);
+ }
+ gp=proto_get_finfo_ptr_array(edt->tree, rs->hf_index);
+ if(!gp){
+ return 0;
+ }
+
+ for(i=0;i<gp->len;i++){
+ str=proto_construct_match_selected_string(gp->pdata[i], NULL);
+ if(str){
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s",str);
+ }
+ }
+ return 0;
+}
+
+
+
+static void
+protocolinfo_init(const char *optarg, void* userdata _U_)
+{
+ pci_t *rs;
+ const char *field=NULL;
+ const char *filter=NULL;
+ header_field_info *hfi;
+ GString *error_string;
+
+ if(!strncmp("proto,colinfo,",optarg,14)){
+ filter=optarg+14;
+ field=strchr(filter,',');
+ if(field){
+ field+=1; /* skip the ',' */
+ }
+ }
+ if(!field){
+ fprintf(stderr, "tshark: invalid \"-z proto,colinfo,<filter>,<field>\" argument\n");
+ exit(1);
+ }
+
+ hfi=proto_registrar_get_byname(field);
+ if(!hfi){
+ fprintf(stderr, "tshark: Field \"%s\" doesn't exist.\n", field);
+ exit(1);
+ }
+
+ rs=g_malloc(sizeof(pci_t));
+ rs->hf_index=hfi->id;
+ if((field-filter)>1){
+ rs->filter=g_malloc(field-filter);
+ g_strlcpy(rs->filter,filter,(field-filter));
+ } else {
+ rs->filter=NULL;
+ }
+
+ error_string=register_tap_listener("frame", rs, rs->filter, TL_REQUIRES_PROTO_TREE, NULL, protocolinfo_packet, NULL);
+ if(error_string){
+ /* error, we failed to attach to the tap. complain and clean up */
+ fprintf(stderr, "tshark: Couldn't register proto,colinfo tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ g_free(rs->filter);
+ g_free(rs);
+
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_protocolinfo(void)
+{
+ register_stat_cmd_arg("proto,colinfo,", protocolinfo_init,NULL);
+}
+
diff --git a/ui/cli/tap-protohierstat.c b/ui/cli/tap-protohierstat.c
new file mode 100644
index 0000000000..89eac20d1c
--- /dev/null
+++ b/ui/cli/tap-protohierstat.c
@@ -0,0 +1,220 @@
+/* tap-protohierstat.c
+ * protohierstat 2002 Ronnie Sahlberg
+ *
+ * $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 ProtocolHierarchyStatistics for tshark */
+
+#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/epan_dissect.h"
+#include "epan/proto.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+
+typedef struct _phs_t {
+ struct _phs_t *sibling;
+ struct _phs_t *child;
+ struct _phs_t *parent;
+ char *filter;
+ int protocol;
+ const char *proto_name;
+ guint32 frames;
+ guint64 bytes;
+} phs_t;
+
+
+static phs_t *
+new_phs_t(phs_t *parent)
+{
+ phs_t *rs;
+ rs=g_malloc(sizeof(phs_t));
+ rs->sibling=NULL;
+ rs->child=NULL;
+ rs->parent=parent;
+ rs->filter=NULL;
+ rs->protocol=-1;
+ rs->proto_name=NULL;
+ rs->frames=0;
+ rs->bytes=0;
+ return rs;
+}
+
+
+static int
+protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
+{
+ phs_t *rs=prs;
+ phs_t *tmprs;
+ proto_node *node;
+ field_info *fi;
+
+ if(!edt){
+ return 0;
+ }
+ if(!edt->tree){
+ return 0;
+ }
+ if(!edt->tree->first_child){
+ return 0;
+ }
+
+ for(node=edt->tree->first_child;node;node=node->next){
+ fi=PNODE_FINFO(node);
+
+ /* first time we saw a protocol at this leaf */
+ if(rs->protocol==-1){
+ rs->protocol=fi->hfinfo->id;
+ rs->proto_name=fi->hfinfo->abbrev;
+ rs->frames=1;
+ rs->bytes=pinfo->fd->pkt_len;
+ rs->child=new_phs_t(rs);
+ rs=rs->child;
+ continue;
+ }
+
+ /* find this protocol in the list of siblings */
+ for(tmprs=rs;tmprs;tmprs=tmprs->sibling){
+ if(tmprs->protocol==fi->hfinfo->id){
+ break;
+ }
+ }
+
+ /* not found, then we must add it to the end of the list */
+ if(!tmprs){
+ for(tmprs=rs;tmprs->sibling;tmprs=tmprs->sibling)
+ ;
+ tmprs->sibling=new_phs_t(rs->parent);
+ rs=tmprs->sibling;
+ rs->protocol=fi->hfinfo->id;
+ rs->proto_name=fi->hfinfo->abbrev;
+ } else {
+ rs=tmprs;
+ }
+
+ rs->frames++;
+ rs->bytes+=pinfo->fd->pkt_len;
+
+ if(!rs->child){
+ rs->child=new_phs_t(rs);
+ }
+ rs=rs->child;
+ }
+ return 1;
+}
+
+static void
+phs_draw(phs_t *rs, int indentation)
+{
+ int i, stroff;
+#define MAXPHSLINE 80
+ char str[MAXPHSLINE];
+ for(;rs;rs=rs->sibling){
+ if(rs->protocol==-1){
+ return;
+ }
+ str[0]=0;
+ stroff=0;
+ for(i=0;i<indentation;i++){
+ if(i>15){
+ stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "...");
+ break;
+ }
+ stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, " ");
+ }
+ g_snprintf(str+stroff, MAXPHSLINE-stroff, "%s", rs->proto_name);
+ printf("%-40s frames:%d bytes:%" G_GINT64_MODIFIER "d\n",str, rs->frames, rs->bytes);
+ phs_draw(rs->child, indentation+1);
+ }
+}
+
+static void
+protohierstat_draw(void *prs)
+{
+ phs_t *rs=prs;
+
+ printf("\n");
+ printf("===================================================================\n");
+ printf("Protocol Hierarchy Statistics\n");
+ printf("Filter: %s\n\n",rs->filter?rs->filter:"");
+ phs_draw(rs,0);
+ printf("===================================================================\n");
+}
+
+
+static void
+protohierstat_init(const char *optarg, void* userdata _U_)
+{
+ phs_t *rs;
+ int pos=0;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if(strcmp("io,phs",optarg)==0){
+ /* No arguments */
+ } else if(sscanf(optarg,"io,phs,%n",&pos)==0){
+ if(pos){
+ filter=optarg+pos;
+ }
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z io,phs[,<filter>]\" argument\n");
+ exit(1);
+ }
+
+ rs=new_phs_t(NULL);
+
+ if(filter){
+ rs->filter=g_strdup(filter);
+ } else {
+ rs->filter=NULL;
+ }
+
+ error_string=register_tap_listener("frame", rs, filter, TL_REQUIRES_PROTO_TREE, NULL, protohierstat_packet, protohierstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(rs->filter);
+ g_free(rs);
+
+ fprintf(stderr, "tshark: Couldn't register io,phs tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_protohierstat(void)
+{
+ register_stat_cmd_arg("io,phs", protohierstat_init, NULL);
+}
+
diff --git a/ui/cli/tap-radiusstat.c b/ui/cli/tap-radiusstat.c
new file mode 100644
index 0000000000..dd44e87c24
--- /dev/null
+++ b/ui/cli/tap-radiusstat.c
@@ -0,0 +1,243 @@
+/* tap-radiusstat.c
+ * Copyright 2006 Alejandro Vaquero <alejandrovaquero@yahoo.com>
+ *
+ * $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.
+ */
+
+#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/value_string.h"
+#include <epan/dissectors/packet-radius.h>
+#include "timestats.h"
+
+typedef enum _radius_category {
+ RADIUS_CAT_OVERALL = 0,
+ RADIUS_CAT_ACCESS,
+ RADIUS_CAT_ACCOUNTING,
+ RADIUS_CAT_PASSWORD,
+ RADIUS_CAT_RESOURCE_FREE,
+ RADIUS_CAT_RESOURCE_QUERY,
+ RADIUS_CAT_NAS_REBOOT,
+ RADIUS_CAT_EVENT,
+ RADIUS_CAT_DISCONNECT,
+ RADIUS_CAT_COA,
+ RADIUS_CAT_OTHERS,
+ RADIUS_CAT_NUM_TIMESTATS
+} radius_category;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _radiusstat_t {
+ char *filter;
+ timestat_t rtd[RADIUS_CAT_NUM_TIMESTATS];
+ guint32 open_req_num;
+ guint32 disc_rsp_num;
+ guint32 req_dup_num;
+ guint32 rsp_dup_num;
+} radiusstat_t;
+
+
+
+
+static const value_string radius_message_code[] = {
+ { RADIUS_CAT_OVERALL, "Overall "},
+ { RADIUS_CAT_ACCESS, "Access "},
+ { RADIUS_CAT_ACCOUNTING, "Accounting "},
+ { RADIUS_CAT_PASSWORD, "Password "},
+ { RADIUS_CAT_RESOURCE_FREE, "Resource Free "},
+ { RADIUS_CAT_RESOURCE_QUERY, "Resource Query"},
+ { RADIUS_CAT_NAS_REBOOT, "NAS Reboot "},
+ { RADIUS_CAT_EVENT, "Event "},
+ { RADIUS_CAT_DISCONNECT, "Disconnect "},
+ { RADIUS_CAT_COA, "CoA "},
+ { RADIUS_CAT_OTHERS, "Other "},
+ { 0, NULL}
+};
+
+static int
+radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ radiusstat_t *rs=(radiusstat_t *)prs;
+ const radius_info_t *ri=pri;
+ nstime_t delta;
+ int ret = 0;
+
+ switch (ri->code) {
+
+ case RADIUS_PKT_TYPE_ACCESS_REQUEST:
+ case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST:
+ case RADIUS_PKT_TYPE_PASSWORD_REQUEST:
+ case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST:
+ case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST:
+ case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST:
+ case RADIUS_PKT_TYPE_EVENT_REQUEST:
+ case RADIUS_PKT_TYPE_DISCONNECT_REQUEST:
+ case RADIUS_PKT_TYPE_COA_REQUEST:
+ if(ri->is_duplicate){
+ /* Duplicate is ignored */
+ rs->req_dup_num++;
+ }
+ else {
+ rs->open_req_num++;
+ }
+ break;
+
+ case RADIUS_PKT_TYPE_ACCESS_ACCEPT:
+ case RADIUS_PKT_TYPE_ACCESS_REJECT:
+ case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE:
+ case RADIUS_PKT_TYPE_PASSWORD_ACK:
+ case RADIUS_PKT_TYPE_PASSWORD_REJECT:
+ case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE:
+ case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE:
+ case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE:
+ case RADIUS_PKT_TYPE_EVENT_RESPONSE:
+ case RADIUS_PKT_TYPE_DISCONNECT_ACK:
+ case RADIUS_PKT_TYPE_DISCONNECT_NAK:
+ case RADIUS_PKT_TYPE_COA_ACK:
+ case RADIUS_PKT_TYPE_COA_NAK:
+ if(ri->is_duplicate){
+ /* Duplicate is ignored */
+ rs->rsp_dup_num++;
+ }
+ else if (!ri->request_available) {
+ /* no request was seen */
+ rs->disc_rsp_num++;
+ }
+ else {
+ rs->open_req_num--;
+ /* calculate time delta between request and response */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
+
+ time_stat_update(&(rs->rtd[RADIUS_CAT_OVERALL]),&delta, pinfo);
+
+ if (ri->code == RADIUS_PKT_TYPE_ACCESS_ACCEPT || ri->code == RADIUS_PKT_TYPE_ACCESS_REJECT) {
+ time_stat_update(&(rs->rtd[RADIUS_CAT_ACCESS]),&delta, pinfo);
+ }
+ else if (ri->code == RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE) {
+ time_stat_update(&(rs->rtd[RADIUS_CAT_ACCOUNTING]),&delta, pinfo);
+ }
+ else {
+ time_stat_update(&(rs->rtd[RADIUS_CAT_OTHERS]),&delta, pinfo);
+ }
+
+ ret = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void
+radiusstat_draw(void *prs)
+{
+ radiusstat_t *rs=(radiusstat_t *)prs;
+ int i;
+
+ /* printing results */
+ printf("\n");
+ printf("===========================================================================================================\n");
+ printf("RADIUS Response Time Delay (RTD) Statistics:\n");
+ printf("Filter for statistics: %s\n",rs->filter?rs->filter:"");
+ printf("Duplicate requests: %u\n",rs->req_dup_num);
+ printf("Duplicate responses: %u\n",rs->rsp_dup_num);
+ printf("Open requests: %u\n",rs->open_req_num);
+ printf("Discarded responses: %u\n",rs->disc_rsp_num);
+ printf("Type | Messages | Min RTD | Max RTD | Avg RTD | Min in Frame | Max in Frame |\n");
+ for(i=0;i<RADIUS_CAT_NUM_TIMESTATS;i++) {
+ if(rs->rtd[i].num) {
+ printf("%s | %7u | %8.2f msec | %8.2f msec | %8.2f msec | %10u | %10u |\n",
+ val_to_str(i,radius_message_code,"Other "),rs->rtd[i].num,
+ nstime_to_msec(&(rs->rtd[i].min)), nstime_to_msec(&(rs->rtd[i].max)),
+ get_average(&(rs->rtd[i].tot), rs->rtd[i].num),
+ rs->rtd[i].min_num, rs->rtd[i].max_num
+ );
+ }
+ }
+ printf("===========================================================================================================\n");
+}
+
+
+static void
+radiusstat_init(const char *optarg, void* userdata _U_)
+{
+ radiusstat_t *rs;
+ int i;
+ GString *error_string;
+
+ rs=g_malloc(sizeof(radiusstat_t));
+ if(!strncmp(optarg,"radius,rtd,",11)){
+ rs->filter=g_strdup(optarg+11);
+ } else {
+ rs->filter=NULL;
+ }
+
+ for(i=0;i<RADIUS_CAT_NUM_TIMESTATS;i++) {
+ rs->rtd[i].num=0;
+ rs->rtd[i].min_num=0;
+ rs->rtd[i].max_num=0;
+ rs->rtd[i].min.secs=0;
+ rs->rtd[i].min.nsecs=0;
+ rs->rtd[i].max.secs=0;
+ rs->rtd[i].max.nsecs=0;
+ rs->rtd[i].tot.secs=0;
+ rs->rtd[i].tot.nsecs=0;
+ }
+
+ rs->open_req_num=0;
+ rs->disc_rsp_num=0;
+ rs->req_dup_num=0;
+ rs->rsp_dup_num=0;
+
+ error_string=register_tap_listener("radius", rs, rs->filter, 0, NULL, radiusstat_packet, radiusstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(rs->filter);
+ g_free(rs);
+
+ fprintf(stderr, "tshark: Couldn't register radius,rtd tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_radiusstat(void)
+{
+ register_stat_cmd_arg("radius,rtd", radiusstat_init, NULL);
+}
+
diff --git a/ui/cli/tap-rlcltestat.c b/ui/cli/tap-rlcltestat.c
new file mode 100644
index 0000000000..d1c3d74999
--- /dev/null
+++ b/ui/cli/tap-rlcltestat.c
@@ -0,0 +1,411 @@
+/* tap-rlclte_stat.c
+ * Copyright 2011 Martin Mathieson
+ *
+ * $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.
+ */
+
+
+#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.h>
+#include <epan/packet_info.h>
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-rlc-lte.h>
+
+
+enum {
+ UEID_COLUMN,
+ UL_FRAMES_COLUMN,
+ UL_BYTES_COLUMN,
+ UL_BW_COLUMN,
+ UL_ACKS_COLUMN,
+ UL_NACKS_COLUMN,
+ UL_MISSING_COLUMN,
+ DL_FRAMES_COLUMN,
+ DL_BYTES_COLUMN,
+ DL_BW_COLUMN,
+ DL_ACKS_COLUMN,
+ DL_NACKS_COLUMN,
+ DL_MISSING_COLUMN,
+ NUM_UE_COLUMNS
+};
+
+static const gchar *ue_titles[] = { " UEId",
+ "UL Frames", "UL Bytes", " UL Mbs", "UL ACKs", "UL NACKs", "UL Missed",
+ "DL Frames", "DL Bytes", " DL Mbs", "DL ACKs", "DL NACKs", "DL Missed"};
+
+/* Stats for one UE */
+typedef struct rlc_lte_row_data {
+ /* Key for matching this row */
+ guint16 ueid;
+
+ gboolean is_predefined_data;
+
+ guint32 UL_frames;
+ guint32 UL_total_bytes;
+ nstime_t UL_time_start;
+ nstime_t UL_time_stop;
+ guint32 UL_total_acks;
+ guint32 UL_total_nacks;
+ guint32 UL_total_missing;
+
+ guint32 DL_frames;
+ guint32 DL_total_bytes;
+ nstime_t DL_time_start;
+ nstime_t DL_time_stop;
+ guint32 DL_total_acks;
+ guint32 DL_total_nacks;
+ guint32 DL_total_missing;
+
+} rlc_lte_row_data;
+
+
+/* Common channel stats */
+typedef struct rlc_lte_common_stats {
+ guint32 bcch_frames;
+ guint32 bcch_bytes;
+ guint32 pcch_frames;
+ guint32 pcch_bytes;
+} rlc_lte_common_stats;
+
+
+/* One row/UE in the UE table */
+typedef struct rlc_lte_ep {
+ struct rlc_lte_ep* next;
+ struct rlc_lte_row_data stats;
+} rlc_lte_ep_t;
+
+
+/* Used to keep track of all RLC LTE statistics */
+typedef struct rlc_lte_stat_t {
+ rlc_lte_ep_t *ep_list;
+ guint32 total_frames;
+
+ /* Common stats */
+ rlc_lte_common_stats common_stats;
+} rlc_lte_stat_t;
+
+
+
+/* Reset RLC stats */
+static void
+rlc_lte_stat_reset(void *phs)
+{
+ rlc_lte_stat_t* rlc_lte_stat = (rlc_lte_stat_t *)phs;
+ rlc_lte_ep_t* list = rlc_lte_stat->ep_list;
+
+ rlc_lte_stat->total_frames = 0;
+ memset(&rlc_lte_stat->common_stats, 0, sizeof(rlc_lte_common_stats));
+
+ if (!list) {
+ return;
+ }
+
+ rlc_lte_stat->ep_list = NULL;
+}
+
+
+/* Allocate a rlc_lte_ep_t struct to store info for new UE */
+static rlc_lte_ep_t* alloc_rlc_lte_ep(struct rlc_lte_tap_info *si, packet_info *pinfo _U_)
+{
+ rlc_lte_ep_t* ep;
+
+ if (!si) {
+ return NULL;
+ }
+
+ if (!(ep = g_malloc(sizeof(rlc_lte_ep_t)))) {
+ return NULL;
+ }
+
+ /* Copy SI data into ep->stats */
+ ep->stats.ueid = si->ueid;
+
+ /* Counts for new UE are all 0 */
+ ep->stats.UL_frames = 0;
+ ep->stats.DL_frames = 0;
+ ep->stats.UL_total_bytes = 0;
+ ep->stats.DL_total_bytes = 0;
+ memset(&ep->stats.DL_time_start, 0, sizeof(nstime_t));
+ memset(&ep->stats.DL_time_stop, 0, sizeof(nstime_t));
+ ep->stats.UL_total_acks = 0;
+ ep->stats.DL_total_acks = 0;
+ ep->stats.UL_total_nacks = 0;
+ ep->stats.DL_total_nacks = 0;
+ ep->stats.UL_total_missing = 0;
+ ep->stats.DL_total_missing = 0;
+
+ ep->next = NULL;
+
+ return ep;
+}
+
+
+/* Process stat struct for a RLC LTE frame */
+static int
+rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
+ const void *phi)
+{
+ /* Get reference to stats struct */
+ rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
+ rlc_lte_ep_t *tmp = NULL, *te = NULL;
+
+ /* Cast tap info struct */
+ struct rlc_lte_tap_info *si = (struct rlc_lte_tap_info *)phi;
+
+ /* Need this */
+ if (!hs) {
+ return 0;
+ }
+
+ /* Inc top-level frame count */
+ hs->total_frames++;
+
+ /* Common channel stats */
+ switch (si->channelType) {
+ case CHANNEL_TYPE_BCCH_BCH:
+ case CHANNEL_TYPE_BCCH_DL_SCH:
+ hs->common_stats.bcch_frames++;
+ hs->common_stats.bcch_bytes += si->pduLength;
+ return 1;
+
+ case CHANNEL_TYPE_PCCH:
+ hs->common_stats.pcch_frames++;
+ hs->common_stats.pcch_bytes += si->pduLength;
+ return 1;
+
+ default:
+ break;
+ }
+
+ /* For per-UE data, must create a new row if none already existing */
+ if (!hs->ep_list) {
+ /* Allocate new list */
+ hs->ep_list = alloc_rlc_lte_ep(si, pinfo);
+ /* Make it the first/only entry */
+ te = hs->ep_list;
+ } else {
+ /* Look among existing rows for this UEId */
+ for (tmp = hs->ep_list; (tmp != NULL); tmp = tmp->next) {
+ if (tmp->stats.ueid == si->ueid) {
+ te = tmp;
+ break;
+ }
+ }
+
+ /* Not found among existing, so create a new one anyway */
+ if (te == NULL) {
+ if ((te = alloc_rlc_lte_ep(si, pinfo))) {
+ /* Add new item to end of list */
+ rlc_lte_ep_t *p = hs->ep_list;
+ while (p->next) {
+ p = p->next;
+ }
+ p->next = te;
+ te->next = NULL;
+ }
+ }
+ }
+
+ /* Really should have a row pointer by now */
+ if (!te) {
+ return 0;
+ }
+
+ /* Update entry with details from si */
+ te->stats.ueid = si->ueid;
+
+ /* Top-level traffic stats */
+ if (si->direction == DIRECTION_UPLINK) {
+ /* Update time range */
+ if (te->stats.UL_frames == 0) {
+ te->stats.UL_time_start = si->time;
+ }
+ te->stats.UL_time_stop = si->time;
+
+ te->stats.UL_frames++;
+ te->stats.UL_total_bytes += si->pduLength;
+ }
+ else {
+ /* Update time range */
+ if (te->stats.DL_frames == 0) {
+ te->stats.DL_time_start = si->time;
+ }
+ te->stats.DL_time_stop = si->time;
+
+ te->stats.DL_frames++;
+ te->stats.DL_total_bytes += si->pduLength;
+ }
+
+
+ if (si->direction == DIRECTION_UPLINK) {
+ if (si->isControlPDU) {
+ te->stats.UL_total_acks++;
+ }
+ te->stats.UL_total_nacks += si->noOfNACKs;
+ te->stats.UL_total_missing += si->missingSNs;
+ }
+ else {
+ if (si->isControlPDU) {
+ te->stats.DL_total_acks++;
+ }
+ te->stats.DL_total_nacks += si->noOfNACKs;
+ te->stats.DL_total_missing += si->missingSNs;
+ }
+
+ return 1;
+}
+
+
+/* Calculate and return a bandwidth figure, in Mbs */
+static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
+{
+ if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
+ float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
+ (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
+ return ((bytes * 8) / elapsed_ms) / 1000;
+ }
+ else {
+ return 0.0;
+ }
+}
+
+
+
+
+/* (Re)draw RLC stats */
+static void
+rlc_lte_stat_draw(void *phs)
+{
+ guint16 number_of_ues = 0;
+ gint i;
+
+ /* Look up the statistics struct */
+ rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
+ rlc_lte_ep_t* list = hs->ep_list, *tmp = 0;
+
+ /* Common channel data */
+ printf("Common Data:\n");
+ printf("==============\n");
+ printf("BCCH Frames: %u BCCH Bytes: %u PCCH Frames: %u PCCH Bytes: %u\n\n",
+ hs->common_stats.bcch_frames, hs->common_stats.bcch_bytes,
+ hs->common_stats.pcch_frames, hs->common_stats.pcch_bytes);
+
+ /* Per-UE table entries */
+
+
+ /* Set title that shows how many UEs currently in table */
+ for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
+ printf("Per UE Data - %u UEs (%u frames)\n", number_of_ues, hs->total_frames);
+ printf("==========================================\n");
+
+ /* Show column titles */
+ for (i=0; i < NUM_UE_COLUMNS; i++) {
+ printf("%s ", ue_titles[i]);
+ }
+ printf("\n");
+
+ /* For each row/UE in the model */
+ for (tmp = list; tmp; tmp=tmp->next) {
+ /* Calculate bandwidth */
+ float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
+ &tmp->stats.UL_time_stop,
+ tmp->stats.UL_total_bytes);
+ float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
+ &tmp->stats.DL_time_stop,
+ tmp->stats.DL_total_bytes);
+
+ printf("%5u %10u %9u %10f %8u %9u %10u %10u %9u %10f %8u %9u %10u\n",
+ tmp->stats.ueid,
+ tmp->stats.UL_frames,
+ tmp->stats.UL_total_bytes, UL_bw,
+ tmp->stats.UL_total_acks,
+ tmp->stats.UL_total_nacks,
+ tmp->stats.UL_total_missing,
+ tmp->stats.DL_frames,
+ tmp->stats.DL_total_bytes, DL_bw,
+ tmp->stats.DL_total_acks,
+ tmp->stats.DL_total_nacks,
+ tmp->stats.DL_total_missing);
+ }
+}
+
+
+
+
+/* Create a new RLC LTE stats struct */
+static void rlc_lte_stat_init(const char *optarg, void *userdata _U_)
+{
+ rlc_lte_stat_t *hs;
+ const char *filter = NULL;
+ GString *error_string;
+
+ /* Check for a filter string */
+ if (strncmp(optarg, "rlc-lte,stat,", 13) == 0) {
+ /* Skip those characters from filter to display */
+ filter = optarg + 13;
+ }
+ else {
+ /* No filter */
+ filter = NULL;
+ }
+
+ /* Create top-level struct */
+ hs = g_malloc(sizeof(rlc_lte_stat_t));
+ memset(hs, 0, sizeof(rlc_lte_stat_t));
+ hs->ep_list = NULL;
+
+
+ /**********************************************/
+ /* Register the tap listener */
+ /**********************************************/
+
+ error_string = register_tap_listener("rlc-lte", hs,
+ filter, 0,
+ rlc_lte_stat_reset,
+ rlc_lte_stat_packet,
+ rlc_lte_stat_draw);
+ if (error_string) {
+ g_string_free(error_string, TRUE);
+ g_free(hs);
+ exit(1);
+ }
+
+}
+
+
+/* Register this tap listener (need void on own so line register function found) */
+void
+register_tap_listener_rlc_lte_stat(void)
+{
+ register_stat_cmd_arg("rlc-lte,stat", rlc_lte_stat_init, NULL);
+}
+
diff --git a/ui/cli/tap-rpcprogs.c b/ui/cli/tap-rpcprogs.c
new file mode 100644
index 0000000000..accc64c00d
--- /dev/null
+++ b/ui/cli/tap-rpcprogs.c
@@ -0,0 +1,240 @@
+/* tap-rpcprogs.c
+ * rpcstat 2002 Ronnie Sahlberg
+ *
+ * $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 rpc call/reply SRT statistics to tshark.
+ * It is only used by tshark and not wireshark
+ */
+
+#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-rpc.h>
+
+#define MICROSECS_PER_SEC 1000000
+#define NANOSECS_PER_SEC 1000000000
+
+/* used to keep track of statistics for a specific program/version */
+typedef struct _rpc_program_t {
+ struct _rpc_program_t *next;
+ guint32 program;
+ guint32 version;
+ int num;
+ nstime_t min;
+ nstime_t max;
+ nstime_t tot;
+} rpc_program_t;
+
+static rpc_program_t *prog_list=NULL;
+static int already_enabled=0;
+
+static int
+rpcprogs_packet(void *dummy1 _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ const rpc_call_info_value *ri=pri;
+ nstime_t delta;
+ rpc_program_t *rp=NULL;
+
+ if(!prog_list){
+ /* the list was empty */
+ rp=g_malloc(sizeof(rpc_program_t));
+ rp->next=NULL;
+ rp->program=ri->prog;
+ rp->version=ri->vers;
+ rp->num=0;
+ rp->min.secs=0;
+ rp->min.nsecs=0;
+ rp->max.secs=0;
+ rp->max.nsecs=0;
+ rp->tot.secs=0;
+ rp->tot.nsecs=0;
+ prog_list=rp;
+ } else if((ri->prog==prog_list->program)
+ &&(ri->vers==prog_list->version)){
+ rp=prog_list;
+ } else if( (ri->prog<prog_list->program)
+ ||((ri->prog==prog_list->program)&&(ri->vers<prog_list->version))){
+ /* we should be first entry in list */
+ rp=g_malloc(sizeof(rpc_program_t));
+ rp->next=prog_list;
+ rp->program=ri->prog;
+ rp->version=ri->vers;
+ rp->num=0;
+ rp->min.secs=0;
+ rp->min.nsecs=0;
+ rp->max.secs=0;
+ rp->max.nsecs=0;
+ rp->tot.secs=0;
+ rp->tot.nsecs=0;
+ prog_list=rp;
+ } else {
+ /* we go somewhere else in the list */
+ for(rp=prog_list;rp;rp=rp->next){
+ if((rp->next)
+ && (rp->next->program==ri->prog)
+ && (rp->next->version==ri->vers)){
+ rp=rp->next;
+ break;
+ }
+ if((!rp->next)
+ || (rp->next->program>ri->prog)
+ || ( (rp->next->program==ri->prog)
+ &&(rp->next->version>ri->vers))){
+ rpc_program_t *trp;
+ trp=g_malloc(sizeof(rpc_program_t));
+ trp->next=rp->next;
+ trp->program=ri->prog;
+ trp->version=ri->vers;
+ trp->num=0;
+ trp->min.secs=0;
+ trp->min.nsecs=0;
+ trp->max.secs=0;
+ trp->max.nsecs=0;
+ trp->tot.secs=0;
+ trp->tot.nsecs=0;
+ rp->next=trp;
+ rp=trp;
+ break;
+ }
+ }
+ }
+
+
+ /* we are only interested in reply packets */
+ if(ri->request || !rp){
+ return 0;
+ }
+
+ /* calculate time delta between request and reply */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
+
+ if((rp->max.secs==0)
+ && (rp->max.nsecs==0) ){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ if((rp->min.secs==0)
+ && (rp->min.nsecs==0) ){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs<rp->min.secs)
+ ||( (delta.secs==rp->min.secs)
+ &&(delta.nsecs<rp->min.nsecs) ) ){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs>rp->max.secs)
+ ||( (delta.secs==rp->max.secs)
+ &&(delta.nsecs>rp->max.nsecs) ) ){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ rp->tot.secs += delta.secs;
+ rp->tot.nsecs += delta.nsecs;
+ if(rp->tot.nsecs > NANOSECS_PER_SEC){
+ rp->tot.nsecs -= NANOSECS_PER_SEC;
+ rp->tot.secs++;
+ }
+ rp->num++;
+
+ return 1;
+}
+
+
+static void
+rpcprogs_draw(void *dummy _U_)
+{
+ guint64 td;
+ rpc_program_t *rp;
+ char str[64];
+
+ printf("\n");
+ printf("==========================================================\n");
+ printf("ONC-RPC Program Statistics:\n");
+ printf("Program Version Calls Min SRT Max SRT Avg SRT\n");
+ for(rp=prog_list;rp;rp=rp->next){
+ /* Only display procs with non-zero calls */
+ if(rp->num==0){
+ continue;
+ }
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(rp->tot.secs)) * NANOSECS_PER_SEC + rp->tot.nsecs;
+ td = ((td / rp->num) + 500) / 1000;
+
+ g_snprintf(str, sizeof(str), "%s(%d)",rpc_prog_name(rp->program),rp->program);
+ printf("%-15s %2d %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ str,
+ rp->version,
+ rp->num,
+ (int)(rp->min.secs),(rp->min.nsecs+500)/1000,
+ (int)(rp->max.secs),(rp->max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+ printf("===================================================================\n");
+}
+
+
+static void
+rpcprogs_init(const char *optarg _U_, void* userdata _U_)
+{
+ GString *error_string;
+
+ if(already_enabled){
+ return;
+ }
+ already_enabled=1;
+
+ error_string=register_tap_listener("rpc", NULL, NULL, 0, NULL, rpcprogs_packet, rpcprogs_draw);
+ if(error_string){
+ fprintf(stderr,"tshark: Couldn't register rpc,programs tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_rpcprogs(void)
+{
+ register_stat_cmd_arg("rpc,programs", rpcprogs_init, NULL);
+}
+
+
diff --git a/ui/cli/tap-rpcstat.c b/ui/cli/tap-rpcstat.c
new file mode 100644
index 0000000000..3f7245f425
--- /dev/null
+++ b/ui/cli/tap-rpcstat.c
@@ -0,0 +1,355 @@
+/* tap-rpcstat.c
+ * rpcstat 2002 Ronnie Sahlberg
+ *
+ * $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 rpc call/reply SRT statistics to tshark.
+ * It is only used by tshark and not wireshark.
+ *
+ * It serves as an example on how to use the tap api.
+ */
+
+#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-rpc.h>
+
+#define MICROSECS_PER_SEC 1000000
+#define NANOSECS_PER_SEC 1000000000
+
+/* used to keep track of statistics for a specific procedure */
+typedef struct _rpc_procedure_t {
+ const char *proc;
+ int num;
+ nstime_t min;
+ nstime_t max;
+ nstime_t tot;
+} rpc_procedure_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _rpcstat_t {
+ const char *prog;
+ char *filter;
+ guint32 program;
+ guint32 version;
+ guint32 num_procedures;
+ rpc_procedure_t *procedures;
+} rpcstat_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
+rpcstat_reset(void *prs)
+{
+ rpcstat_t *rs=prs;
+ guint32 i;
+
+ for(i=0;i<rs->num_procedures;i++){
+ rs->procedures[i].num=0;
+ rs->procedures[i].min.secs=0;
+ rs->procedures[i].min.nsecs=0;
+ rs->procedures[i].max.secs=0;
+ rs->procedures[i].max.nsecs=0;
+ rs->procedures[i].tot.secs=0;
+ rs->procedures[i].tot.nsecs=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 as we do below in
+ * this example 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
+ * "rpc" tap, the third parameter type is rpc_call_info_value.
+ *
+ * The filtering we do is just to check the rpc_call_info_value struct that we
+ * were called for the proper program and version. We didn't apply a filter
+ * when we registered so we will be called for ALL rpc packets and not just
+ * the ones we are collecting stats for.
+ *
+ * function returns :
+ * 0: no updates, no need to call (*draw) later
+ * !0: state has changed, call (*draw) sometime later
+ */
+static int
+rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ rpcstat_t *rs=prs;
+ const rpc_call_info_value *ri=pri;
+ nstime_t delta;
+ rpc_procedure_t *rp;
+
+ if(ri->proc>=rs->num_procedures){
+ /* dont handle this since its outside of known table */
+ return 0;
+ }
+ /* we are only interested in reply packets */
+ if(ri->request){
+ return 0;
+ }
+ /* we are only interested in certain program/versions */
+ if( (ri->prog!=rs->program) || (ri->vers!=rs->version) ){
+ return 0;
+ }
+
+ rp=&(rs->procedures[ri->proc]);
+
+ /* calculate time delta between request and reply */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
+
+ if(rp->num==0){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ if(rp->num==0){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs<rp->min.secs)
+ ||( (delta.secs==rp->min.secs)
+ &&(delta.nsecs<rp->min.nsecs) ) ){
+ rp->min.secs=delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+
+ if( (delta.secs>rp->max.secs)
+ ||( (delta.secs==rp->max.secs)
+ &&(delta.nsecs>rp->max.nsecs) ) ){
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+
+ rp->tot.secs += delta.secs;
+ rp->tot.nsecs += delta.nsecs;
+ if(rp->tot.nsecs > NANOSECS_PER_SEC){
+ rp->tot.nsecs -= NANOSECS_PER_SEC;
+ rp->tot.secs++;
+ }
+
+ rp->num++;
+
+ return 1;
+}
+
+/* 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 rpcstat_t can thus change
+ * beneath us. Beware!
+ */
+static void
+rpcstat_draw(void *prs)
+{
+ rpcstat_t *rs=prs;
+ guint32 i;
+ guint64 td;
+ printf("\n");
+ printf("=======================================================\n");
+ printf("%s Version %d SRT Statistics:\n", rs->prog, rs->version);
+ printf("Filter: %s\n",rs->filter?rs->filter:"");
+ printf("Procedure Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0;i<rs->num_procedures;i++){
+ if(rs->procedures[i].num==0){
+ continue;
+ }
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
+ td = ((td / rs->procedures[i].num) + 500) / 1000;
+
+ printf("%-15s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ rs->procedures[i].proc,
+ rs->procedures[i].num,
+ (int)(rs->procedures[i].min.secs),(rs->procedures[i].min.nsecs+500)/1000,
+ (int)(rs->procedures[i].max.secs),(rs->procedures[i].max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+ printf("=======================================================\n");
+}
+
+static guint32 rpc_program=0;
+static guint32 rpc_version=0;
+static gint32 rpc_min_proc=-1;
+static gint32 rpc_max_proc=-1;
+
+static void *
+rpcstat_find_procs(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
+{
+ rpc_proc_info_key *k=(rpc_proc_info_key *)key;
+
+ if(k->prog!=rpc_program){
+ return NULL;
+ }
+ if(k->vers!=rpc_version){
+ return NULL;
+ }
+ if(rpc_min_proc==-1){
+ rpc_min_proc=k->proc;
+ rpc_max_proc=k->proc;
+ }
+ if((gint32)k->proc<rpc_min_proc){
+ rpc_min_proc=k->proc;
+ }
+ if((gint32)k->proc>rpc_max_proc){
+ rpc_max_proc=k->proc;
+ }
+
+ return NULL;
+}
+
+
+/* When called, this function will create a new instance of rpcstat.
+ *
+ * program and version are which onc-rpc program/version we want to collect
+ * statistics for.
+ *
+ * This function is called from tshark when it parses the -z rpc, arguments and
+ * it creates a new instance to store statistics in and registers this new
+ * instance for the rpc tap.
+ */
+static void
+rpcstat_init(const char *optarg, void* userdata _U_)
+{
+ rpcstat_t *rs;
+ guint32 i;
+ int program, version;
+ int pos=0;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if(sscanf(optarg,"rpc,srt,%d,%d,%n",&program,&version,&pos)==2){
+ if(pos){
+ filter=optarg+pos;
+ } else {
+ filter=NULL;
+ }
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
+ exit(1);
+ }
+
+ rs=g_malloc(sizeof(rpcstat_t));
+ rs->prog=rpc_prog_name(program);
+ rs->program=program;
+ rs->version=version;
+ if(filter){
+ rs->filter=g_strdup(filter);
+ } else {
+ rs->filter=NULL;
+ }
+ rpc_program=program;
+ rpc_version=version;
+ rpc_min_proc=-1;
+ rpc_max_proc=-1;
+ g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
+ if(rpc_min_proc==-1){
+ fprintf(stderr,"tshark: Invalid -z rpc,srt,%d,%d\n",rpc_program,rpc_version);
+ fprintf(stderr," Program:%d version:%d isn't supported by tshark.\n", rpc_program, rpc_version);
+ exit(1);
+ }
+
+
+ rs->num_procedures=rpc_max_proc+1;
+ rs->procedures=g_malloc(sizeof(rpc_procedure_t)*(rs->num_procedures+1));
+ for(i=0;i<rs->num_procedures;i++){
+ rs->procedures[i].proc=rpc_proc_name(program, version, i);
+ rs->procedures[i].num=0;
+ rs->procedures[i].min.secs=0;
+ rs->procedures[i].min.nsecs=0;
+ rs->procedures[i].max.secs=0;
+ rs->procedures[i].max.nsecs=0;
+ rs->procedures[i].tot.secs=0;
+ rs->procedures[i].tot.nsecs=0;
+ }
+
+/* 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.
+ * (Perhaps the user only wants the stats for nis+ traffic for certain objects?)
+ */
+
+ error_string=register_tap_listener("rpc", rs, filter, 0, rpcstat_reset, rpcstat_packet, rpcstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(rs->procedures);
+ g_free(rs->filter);
+ g_free(rs);
+
+ fprintf(stderr, "tshark: Couldn't register rpc,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_rpcstat(void)
+{
+ register_stat_cmd_arg("rpc,srt,", rpcstat_init,NULL);
+}
+
diff --git a/ui/cli/tap-rtp.c b/ui/cli/tap-rtp.c
new file mode 100644
index 0000000000..2741ea84b7
--- /dev/null
+++ b/ui/cli/tap-rtp.c
@@ -0,0 +1,162 @@
+/* tap-rtp.c
+ * RTP TAP for tshark
+ *
+ * $Id$
+ *
+ * Copyright 2008, Ericsson AB
+ * By Balint Reczey <balint.reczey@ericsson.com>
+ *
+ * based on ui/gtk/rtp_stream_dlg.c
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * 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 TAP provides statistics for RTP streams
+ */
+
+#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 <locale.h>
+#include "epan/packet_info.h"
+#include "epan/value_string.h"
+#include <epan/tap.h>
+#include <epan/rtp_pt.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/addr_resolv.h>
+#include "tap-rtp-common.h"
+
+/* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark.
+ */
+static rtpstream_tapinfo_t the_tapinfo_struct =
+ {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE};
+
+static void
+rtp_streams_stat_draw(void *arg _U_)
+{
+
+
+ GList *list;
+ rtp_stream_info_t* strinfo;
+ gchar *payload_type;
+ guint32 expected;
+ gint32 lost;
+ double perc;
+ char *savelocale;
+
+ printf("========================= RTP Streams ========================\n");
+ printf("%15s %5s %15s %5s %10s %16s %5s %12s %15s %15s %15s %s\n","Src IP addr", "Port", "Dest IP addr", "Port", "SSRC", "Payload", "Pkts", "Lost", "Max Delta(ms)", "Max Jitter(ms)", "Mean Jitter(ms)", "Problems?");
+
+ /* save the current locale */
+ savelocale = setlocale(LC_NUMERIC, NULL);
+ /* switch to "C" locale to avoid problems with localized decimal separators
+ in g_snprintf("%f") functions */
+ setlocale(LC_NUMERIC, "C");
+
+ list = the_tapinfo_struct.strinfo_list;
+
+ list = g_list_first(list);
+ while (list)
+ {
+ strinfo = (rtp_stream_info_t*)(list->data);
+
+ /* payload type */
+ if(strinfo->pt>95){
+ if(strinfo->info_payload_type_str != NULL){
+ payload_type = g_strdup(strinfo->info_payload_type_str);
+ }else{
+ payload_type = g_strdup_printf("Unknown(%u)",strinfo->pt);
+ }
+
+ }else{
+ payload_type = g_strdup(val_to_str_ext(strinfo->pt, &rtp_payload_type_vals_ext,
+ "Unknown (%u)"));
+ }
+
+ /* packet count, lost packets */
+ expected = (strinfo->rtp_stats.stop_seq_nr + strinfo->rtp_stats.cycles*65536)
+ - strinfo->rtp_stats.start_seq_nr + 1;
+ lost = expected - strinfo->rtp_stats.total_nr;
+ if (expected){
+ perc = (double)(lost*100)/(double)expected;
+ } else {
+ perc = 0;
+ }
+
+ printf("%15s %5u %15s %5u 0x%08X %16s %5u %5d (%.1f%%) %15.2f %15.2f %15.2f %s\n",
+ get_addr_name(&(strinfo->src_addr)),
+ strinfo->src_port,
+ get_addr_name(&(strinfo->dest_addr)),
+ strinfo->dest_port,
+ strinfo->ssrc,
+ payload_type,
+ strinfo->npackets,
+ lost, perc,
+ strinfo->rtp_stats.max_delta,
+ strinfo->rtp_stats.max_jitter,
+ strinfo->rtp_stats.mean_jitter,
+ (strinfo->problem)?"X":"");
+
+ list = g_list_next(list);
+
+
+ }
+
+ printf("==============================================================\n");
+ /* restore previous locale setting */
+ setlocale(LC_NUMERIC, savelocale);
+}
+
+
+static void
+rtp_streams_stat_init(const char *optarg _U_, void* userdata _U_)
+{
+ GString *err_p;
+
+ err_p =
+ register_tap_listener("rtp", &the_tapinfo_struct, NULL, 0,
+ rtpstream_reset_cb,
+ rtpstream_packet,
+ rtp_streams_stat_draw);
+
+ if (err_p != NULL)
+ {
+ g_string_free(err_p, TRUE);
+
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_rtp_streams(void)
+{
+ register_stat_cmd_arg("rtp,streams", rtp_streams_stat_init,NULL);
+}
diff --git a/ui/cli/tap-rtspstat.c b/ui/cli/tap-rtspstat.c
new file mode 100644
index 0000000000..feb8c8bd8e
--- /dev/null
+++ b/ui/cli/tap-rtspstat.c
@@ -0,0 +1,282 @@
+/* tap-rtspstat.c
+ * tap-rtspstat March 2011
+ *
+ * Stephane GORSE (Orange Labs / France Telecom)
+ * Copied from Jean-Michel FAYARD's works (HTTP)
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "epan/packet_info.h"
+#include "epan/value_string.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "register.h"
+#include <epan/dissectors/packet-rtsp.h>
+
+
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _rtsp_stats_t {
+ char *filter;
+ GHashTable *hash_responses;
+ GHashTable *hash_requests;
+} rtspstat_t;
+
+/* used to keep track of the stats for a specific response code
+ * for example it can be { 3, 404, "Not Found" ,...}
+ * which means we captured 3 reply rtsp/1.1 404 Not Found */
+typedef struct _rtsp_response_code_t {
+ guint32 packets; /* 3 */
+ guint response_code; /* 404 */
+ const gchar *name; /* Not Found */
+ rtspstat_t *sp;
+} rtsp_response_code_t;
+
+/* used to keep track of the stats for a specific request string */
+typedef struct _rtsp_request_methode_t {
+ gchar *response; /* eg. : SETUP */
+ guint32 packets;
+ rtspstat_t *sp;
+} rtsp_request_methode_t;
+
+
+/* insert some entries */
+static void
+rtsp_init_hash( rtspstat_t *sp)
+{
+ int i;
+
+ sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal);
+
+ for (i=0 ; rtsp_status_code_vals[i].strptr ; i++ )
+ {
+ gint *key = g_malloc (sizeof(gint));
+ rtsp_response_code_t *sc = g_malloc (sizeof(rtsp_response_code_t));
+ *key = rtsp_status_code_vals[i].value;
+ sc->packets=0;
+ sc->response_code = *key;
+ sc->name=rtsp_status_code_vals[i].strptr;
+ sc->sp = sp;
+ g_hash_table_insert( sc->sp->hash_responses, key, sc);
+ }
+ sp->hash_requests = g_hash_table_new( g_str_hash, g_str_equal);
+}
+static void
+rtsp_draw_hash_requests( gchar *key _U_ , rtsp_request_methode_t *data, gchar * format)
+{
+ if (data->packets==0)
+ return;
+ printf( format, data->response, data->packets);
+}
+
+static void
+rtsp_draw_hash_responses( gint * key _U_ , rtsp_response_code_t *data, char * format)
+{
+ if (data==NULL) {
+ g_warning("No data available, key=%d\n", *key);
+ exit(EXIT_FAILURE);
+ }
+ if (data->packets==0)
+ return;
+ /* " RTSP %3d %-35s %9d packets", */
+ printf(format, data->response_code, data->name, data->packets );
+}
+
+
+
+/* NOT USED at this moment */
+/*
+static void
+rtsp_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
+{
+ g_free(key);
+ g_free(value);
+}
+*/
+static void
+rtsp_reset_hash_responses(gchar *key _U_ , rtsp_response_code_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+static void
+rtsp_reset_hash_requests(gchar *key _U_ , rtsp_request_methode_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+
+static void
+rtspstat_reset(void *psp )
+{
+ rtspstat_t *sp=psp;
+
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_reset_hash_responses, NULL);
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)rtsp_reset_hash_requests, NULL);
+
+}
+
+static int
+rtspstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ const rtsp_info_value_t *value=pri;
+ rtspstat_t *sp=(rtspstat_t *) psp;
+
+ /* We are only interested in reply packets with a status code */
+ /* Request or reply packets ? */
+ if (value->response_code!=0) {
+ guint *key=g_malloc( sizeof(guint) );
+ rtsp_response_code_t *sc;
+
+ *key=value->response_code;
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL){
+ /* non standard status code ; we classify it as others
+ * in the relevant category (Informational,Success,Redirection,Client Error,Server Error)
+ */
+ int i = value->response_code;
+ if ((i<100) || (i>=600)) {
+ return 0;
+ }
+ else if (i<200){
+ *key=199; /* Hopefully, this status code will never be used */
+ }
+ else if (i<300){
+ *key=299;
+ }
+ else if (i<400){
+ *key=399;
+ }
+ else if (i<500){
+ *key=499;
+ }
+ else{
+ *key=599;
+ }
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL)
+ return 0;
+ }
+ sc->packets++;
+ }
+ else if (value->request_method){
+ rtsp_request_methode_t *sc;
+
+ sc = g_hash_table_lookup(
+ sp->hash_requests,
+ value->request_method);
+ if (sc==NULL){
+ sc=g_malloc( sizeof(rtsp_request_methode_t) );
+ sc->response=g_strdup( value->request_method );
+ sc->packets=1;
+ sc->sp = sp;
+ g_hash_table_insert( sp->hash_requests, sc->response, sc);
+ } else {
+ sc->packets++;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+static void
+rtspstat_draw(void *psp )
+{
+ rtspstat_t *sp=psp;
+ printf("\n");
+ printf("===================================================================\n");
+ if (! sp->filter[0])
+ printf("RTSP Statistics\n");
+ else
+ printf("RTSP Statistics with filter %s\n", sp->filter);
+
+ printf( "* RTSP Status Codes in reply packets\n");
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_draw_hash_responses,
+ " RTSP %3d %s\n");
+ printf("* List of RTSP Request methods\n");
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)rtsp_draw_hash_requests,
+ " %9s %d \n");
+ printf("===================================================================\n");
+}
+
+
+
+/* When called, this function will create a new instance of gtk_rtspstat.
+ */
+static void
+gtk_rtspstat_init(const char *optarg,void* userdata _U_)
+{
+ rtspstat_t *sp;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if (!strncmp (optarg, "rtsp,stat,", 10)){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+
+ sp = g_malloc( sizeof(rtspstat_t) );
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ /*g_hash_table_foreach( rtsp_status, (GHFunc)rtsp_reset_hash_responses, NULL);*/
+
+
+ error_string = register_tap_listener(
+ "rtsp",
+ sp,
+ filter,
+ 0,
+ rtspstat_reset,
+ rtspstat_packet,
+ rtspstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->filter);
+ g_free(sp);
+ fprintf (stderr, "tshark: Couldn't register rtsp,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ rtsp_init_hash(sp);
+}
+
+void
+register_tap_listener_gtkrtspstat(void)
+{
+ register_stat_cmd_arg("rtsp,stat,", gtk_rtspstat_init,NULL);
+}
diff --git a/ui/cli/tap-scsistat.c b/ui/cli/tap-scsistat.c
new file mode 100644
index 0000000000..c12d78cb72
--- /dev/null
+++ b/ui/cli/tap-scsistat.c
@@ -0,0 +1,264 @@
+/* tap-scsistat.c 2010 Chris Costa and Cal Turney
+ *
+ * $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.
+ */
+
+#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/epan.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/tap.h>
+#include <epan/conversation.h>
+#include <epan/dissectors/packet-scsi.h>
+#include <epan/dissectors/packet-fc.h>
+#include <epan/dissectors/packet-scsi-sbc.h>
+#include <epan/dissectors/packet-scsi-ssc.h>
+#include <epan/dissectors/packet-scsi-smc.h>
+#include <epan/dissectors/packet-scsi-osd.h>
+
+static guint8 scsi_program=0;
+
+/* used to keep track of statistics for a specific procedure */
+typedef struct _scsi_procedure_t {
+ const char *proc;
+ int num;
+ nstime_t min;
+ nstime_t max;
+ nstime_t tot;
+} scsi_procedure_t;
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _scsistat_t {
+ guint8 cmdset;
+ char *filter;
+ const value_string *cdbnames;
+ const char *prog;
+#define MAX_PROCEDURES 256
+ scsi_procedure_t *procedures;
+} scsistat_t;
+
+#define NANOSECS_PER_SEC 1000000000
+
+static void
+scsistat_reset(void *prs)
+{
+ scsistat_t *rs=prs;
+ guint32 i;
+
+ for(i=0; i < MAX_PROCEDURES; i++) {
+ rs->procedures[i].num=0;
+ rs->procedures[i].min.secs=0;
+ rs->procedures[i].min.nsecs=0;
+ rs->procedures[i].max.secs=0;
+ rs->procedures[i].max.nsecs=0;
+ rs->procedures[i].tot.secs=0;
+ rs->procedures[i].tot.nsecs=0;
+ }
+}
+
+static int
+scsistat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ scsistat_t *rs = prs;
+ const scsi_task_data_t *ri = pri;
+ nstime_t delta;
+ scsi_procedure_t *rp;
+
+ /* we are only interested in response packets */
+ if(ri->type!=SCSI_PDU_TYPE_RSP) {
+ return 0;
+ }
+ /* we are only interested in a specific commandset */
+ if( (!ri->itl) || ((ri->itl->cmdset&SCSI_CMDSET_MASK)!=rs->cmdset) ) {
+ return 0;
+ }
+ /* check that the opcode looks sane */
+ if( (!ri->itlq) || (ri->itlq->scsi_opcode > 255) ) {
+ return 0;
+ }
+
+ rp=&(rs->procedures[ri->itlq->scsi_opcode]);
+
+ /* calculate time delta between request and reply */
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->itlq->fc_time);
+
+ if(rp->num==0) {
+ rp->max.secs=delta.secs;
+ rp->max.nsecs=delta.nsecs;
+ }
+ if(rp->num==0) {
+ rp->min.secs= delta.secs;
+ rp->min.nsecs=delta.nsecs;
+ }
+ if( (delta.secs < rp->min.secs)
+ ||( (delta.secs == rp->min.secs)
+ &&(delta.nsecs < rp->min.nsecs) ) ) {
+ rp->min.secs = delta.secs;
+ rp->min.nsecs= delta.nsecs;
+ }
+ if( (delta.secs > rp->max.secs)
+ ||( (delta.secs == rp->max.secs)
+ &&(delta.nsecs > rp->max.nsecs) ) ) {
+ rp->max.secs = delta.secs;
+ rp->max.nsecs= delta.nsecs;
+ }
+ rp->tot.secs += delta.secs;
+ rp->tot.nsecs += delta.nsecs;
+ if(rp->tot.nsecs > NANOSECS_PER_SEC) {
+ rp->tot.nsecs -= NANOSECS_PER_SEC;
+ rp->tot.secs++;
+ }
+ rp->num++;
+ return 1;
+}
+
+static void
+scsistat_draw(void *prs)
+{
+ scsistat_t *rs=prs;
+ guint32 i;
+ guint64 td;
+
+ printf("\n");
+ printf("===========================================================\n");
+ printf("SCSI %s SRT Statistics:\n", rs->prog);
+ printf("Filter: %s\n", rs->filter?rs->filter:"");
+ printf("Procedure Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0; i < MAX_PROCEDURES; i++) {
+ if(rs->procedures[i].num==0) {
+ continue;
+ }
+ /* scale it to units of 1us.*/
+ td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
+ td = ((td / rs->procedures[i].num) + 500) / 1000;
+
+ printf("%-19s %6d %3d.%06u %3d.%06u %3d.%06u \n",
+ rs->procedures[i].proc,
+ rs->procedures[i].num,
+ (int)(rs->procedures[i].min.secs),
+ (rs->procedures[i].min.nsecs+500)/1000,
+ (int)(rs->procedures[i].max.secs),
+ (rs->procedures[i].max.nsecs+500)/1000,
+ (int)(td/1000000), (int)(td%1000000)
+ );
+ }
+ printf("===========================================================\n");
+}
+
+static void
+scsistat_init(const char *optarg, void* userdata _U_)
+{
+ scsistat_t *rs;
+ guint32 i;
+ int program, pos;
+ const char *filter=NULL;
+ GString *error_string;
+
+ pos=0;
+ if(sscanf(optarg, "scsi,srt,%d,%n", &program, &pos)==1) {
+ if(pos) {
+ filter=optarg+pos;
+ } else {
+ filter=NULL;
+ }
+ } else {
+ fprintf(stderr, "tshark: invalid \"-z scsi,srt,<cmdset>[,<filter>]\" argument\n");
+ exit(1);
+ }
+
+ scsi_program=program;
+ rs=g_malloc(sizeof(scsistat_t));
+ if(filter) {
+ rs->filter=g_strdup(filter);
+ } else {
+ rs->filter=NULL;
+ }
+ rs->cmdset=program;
+
+ switch(program) {
+ case SCSI_DEV_SBC:
+ rs->prog="SBC (disk)";
+ rs->cdbnames=scsi_sbc_vals;
+ break;
+ case SCSI_DEV_SSC:
+ rs->prog="SSC (tape)";
+ rs->cdbnames=scsi_ssc_vals;
+ break;
+ case SCSI_DEV_CDROM:
+ rs->prog="MMC (cd/dvd)";
+ rs->cdbnames=scsi_mmc_vals;
+ break;
+ case SCSI_DEV_SMC:
+ rs->prog="SMC (tape robot)";
+ rs->cdbnames=scsi_smc_vals;
+ break;
+ case SCSI_DEV_OSD:
+ rs->prog="OSD (object based)";
+ rs->cdbnames=scsi_osd_vals;
+ break;
+ default:
+ /* Default to the SBC (disk), since this is what EMC SCSI seem to always be */
+ rs->cmdset=0;
+ rs->prog="SBC (disk)";
+ rs->cdbnames=scsi_sbc_vals;
+ break;
+ }
+ rs->procedures=g_malloc(sizeof(scsi_procedure_t)*MAX_PROCEDURES);
+ for(i=0; i < MAX_PROCEDURES; i++) {
+ rs->procedures[i].proc=val_to_str(i, rs->cdbnames, "Unknown-0x%02x");
+ rs->procedures[i].num=0;
+ rs->procedures[i].min.secs=0;
+ rs->procedures[i].min.nsecs=0;
+ rs->procedures[i].max.secs=0;
+ rs->procedures[i].max.nsecs=0;
+ rs->procedures[i].tot.secs=0;
+ rs->procedures[i].tot.nsecs=0;
+ }
+ error_string=register_tap_listener("scsi", rs, filter, 0, scsistat_reset, scsistat_packet, scsistat_draw);
+ if(error_string) {
+ /* error, we failed to attach to the tap. clean up */
+ g_free(rs->procedures);
+ g_free(rs->filter);
+ g_free(rs);
+
+ fprintf(stderr, "tshark: Couldn't register scsi,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+void
+register_tap_listener_scsistat(void)
+{
+ register_stat_cmd_arg("scsi,srt,", scsistat_init, NULL);
+}
+
diff --git a/ui/cli/tap-sctpchunkstat.c b/ui/cli/tap-sctpchunkstat.c
new file mode 100644
index 0000000000..fcb8285240
--- /dev/null
+++ b/ui/cli/tap-sctpchunkstat.c
@@ -0,0 +1,254 @@
+/* tap_sctpchunkstat.c
+ * SCTP chunk counter for wireshark
+ * Copyright 2005 Oleg Terletsky <oleg.terletsky@comverse.com>
+ *
+ * $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.
+ */
+
+#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/addr_resolv.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include <epan/dissectors/packet-sctp.h>
+#include <epan/to_str.h>
+
+typedef struct sctp_ep {
+ struct sctp_ep* next;
+ address src;
+ address dst;
+ guint16 sport;
+ guint16 dport;
+ guint32 chunk_count[256];
+} sctp_ep_t;
+
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _sctpstat_t {
+ char* filter;
+ guint32 number_of_packets;
+ sctp_ep_t* ep_list;
+} sctpstat_t;
+
+
+#define SCTP_DATA_CHUNK_ID 0
+#define SCTP_INIT_CHUNK_ID 1
+#define SCTP_INIT_ACK_CHUNK_ID 2
+#define SCTP_SACK_CHUNK_ID 3
+#define SCTP_HEARTBEAT_CHUNK_ID 4
+#define SCTP_HEARTBEAT_ACK_CHUNK_ID 5
+#define SCTP_ABORT_CHUNK_ID 6
+#define SCTP_SHUTDOWN_CHUNK_ID 7
+#define SCTP_SHUTDOWN_ACK_CHUNK_ID 8
+#define SCTP_ERROR_CHUNK_ID 9
+#define SCTP_COOKIE_ECHO_CHUNK_ID 10
+#define SCTP_COOKIE_ACK_CHUNK_ID 11
+#define SCTP_ECNE_CHUNK_ID 12
+#define SCTP_CWR_CHUNK_ID 13
+#define SCTP_SHUTDOWN_COMPLETE_CHUNK_ID 14
+#define SCTP_AUTH_CHUNK_ID 0x16
+#define SCTP_ASCONF_ACK_CHUNK_ID 0x80
+#define SCTP_PKTDROP_CHUNK_ID 0x81
+#define SCTP_FORWARD_TSN_CHUNK_ID 0xC0
+#define SCTP_ASCONF_CHUNK_ID 0xC1
+#define SCTP_IETF_EXT 0xFF
+
+#define CHUNK_TYPE_OFFSET 0
+#define CHUNK_TYPE(x)(tvb_get_guint8((x), CHUNK_TYPE_OFFSET))
+
+static void
+sctpstat_reset(void *phs)
+{
+ sctpstat_t* sctp_stat = (sctpstat_t *)phs;
+ sctp_ep_t* list = (sctp_ep_t*)sctp_stat->ep_list;
+ sctp_ep_t* tmp = NULL;
+ guint16 chunk_type;
+
+ if(!list)
+ return;
+
+ for(tmp = list; tmp ; tmp=tmp->next)
+ for(chunk_type = 0; chunk_type < 256; chunk_type++)
+ tmp->chunk_count[chunk_type] = 0;
+
+ sctp_stat->number_of_packets = 0;
+}
+
+
+static sctp_ep_t*
+alloc_sctp_ep(const struct _sctp_info *si)
+{
+ sctp_ep_t* ep;
+ guint16 chunk_type;
+
+ if(!si)
+ return NULL;
+
+ if (!(ep = g_malloc(sizeof(sctp_ep_t))))
+ return NULL;
+
+ COPY_ADDRESS(&ep->src,&si->ip_src);
+ COPY_ADDRESS(&ep->dst,&si->ip_dst);
+ ep->sport = si->sport;
+ ep->dport = si->dport;
+ ep->next = NULL;
+ for(chunk_type = 0; chunk_type < 256; chunk_type++)
+ ep->chunk_count[chunk_type] = 0;
+ return ep;
+}
+
+
+
+
+static int
+sctpstat_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi)
+{
+
+ sctpstat_t *hs=(sctpstat_t *)phs;
+ sctp_ep_t *tmp = NULL, *te = NULL;
+ const struct _sctp_info *si = (const struct _sctp_info *) phi;
+ guint32 tvb_number;
+ guint8 chunk_type;
+
+ if (!hs)
+ return (0);
+
+ hs->number_of_packets++;
+
+ if(!hs->ep_list) {
+ hs->ep_list = alloc_sctp_ep(si);
+ te = hs->ep_list;
+ } else {
+ for(tmp=hs->ep_list ; tmp ; tmp=tmp->next)
+ {
+ if((!CMP_ADDRESS(&tmp->src,&si->ip_src)) &&
+ (!CMP_ADDRESS(&tmp->dst,&si->ip_dst)) &&
+ (tmp->sport == si->sport) &&
+ (tmp->dport == si->dport))
+ {
+ te = tmp;
+ break;
+ }
+ }
+ if(!te) {
+ if ((te = alloc_sctp_ep(si))) {
+ te->next = hs->ep_list;
+ hs->ep_list = te;
+ }
+ }
+ }
+
+ if(!te)
+ return (0);
+
+
+ if (si->number_of_tvbs > 0) {
+ chunk_type = CHUNK_TYPE(si->tvb[0]);
+ if ((chunk_type == SCTP_INIT_CHUNK_ID) ||
+ (chunk_type == SCTP_INIT_ACK_CHUNK_ID)) {
+ te->chunk_count[chunk_type]++;
+ } else {
+ for(tvb_number = 0; tvb_number < si->number_of_tvbs; tvb_number++)
+ te->chunk_count[CHUNK_TYPE(si->tvb[tvb_number])]++;
+ }
+ }
+ return (1);
+}
+
+
+static void
+sctpstat_draw(void *phs)
+{
+ sctpstat_t *hs=(sctpstat_t *)phs;
+ sctp_ep_t* list = hs->ep_list, *tmp;
+
+ printf("-------------------------------------------- SCTP Statistics --------------------------------------------------------------------------\n");
+ printf("| Total packets RX/TX %u\n", hs->number_of_packets);
+ printf("---------------------------------------------------------------------------------------------------------------------------------------\n");
+ printf("| Source IP |PortA| Dest. IP |PortB| DATA | SACK | HBEAT |HBEATACK| INIT | INITACK| COOKIE |COOKIACK| ABORT | ERROR |\n");
+ printf("---------------------------------------------------------------------------------------------------------------------------------------\n");
+
+ for(tmp = list ; tmp ; tmp=tmp->next) {
+ printf("|%15s|%5u|%15s|%5u|%8u|%8u|%8u|%8u|%8u|%8u|%8u|%8u|%8u|%8u|\n",
+ ep_address_to_str(&tmp->src),tmp->sport,
+ ep_address_to_str(&tmp->dst),tmp->dport,
+ tmp->chunk_count[SCTP_DATA_CHUNK_ID],
+ tmp->chunk_count[SCTP_SACK_CHUNK_ID],
+ tmp->chunk_count[SCTP_HEARTBEAT_CHUNK_ID],
+ tmp->chunk_count[SCTP_HEARTBEAT_ACK_CHUNK_ID],
+ tmp->chunk_count[SCTP_INIT_CHUNK_ID],
+ tmp->chunk_count[SCTP_INIT_ACK_CHUNK_ID],
+ tmp->chunk_count[SCTP_COOKIE_ECHO_CHUNK_ID],
+ tmp->chunk_count[SCTP_COOKIE_ACK_CHUNK_ID],
+ tmp->chunk_count[SCTP_ABORT_CHUNK_ID],
+ tmp->chunk_count[SCTP_ERROR_CHUNK_ID]);
+ }
+ printf("---------------------------------------------------------------------------------------------------------------------------------------\n");
+}
+
+
+static void
+sctpstat_init(const char *optarg, void* userdata _U_)
+{
+ sctpstat_t *hs;
+ GString *error_string;
+
+ hs = (sctpstat_t *)g_malloc(sizeof(sctpstat_t));
+ if(!strncmp(optarg,"sctp,stat,",11)){
+ hs->filter=g_strdup(optarg+11);
+ } else {
+ hs->filter=NULL;
+ }
+ hs->ep_list = NULL;
+ hs->number_of_packets = 0;
+
+ sctpstat_reset(hs);
+
+ error_string=register_tap_listener("sctp", hs, hs->filter, 0, NULL, sctpstat_packet, sctpstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(hs->filter);
+ g_free(hs);
+
+ fprintf(stderr, "tshark: Couldn't register sctp,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_sctpstat(void)
+{
+ register_stat_cmd_arg("sctp,stat", sctpstat_init,NULL);
+}
diff --git a/ui/cli/tap-sipstat.c b/ui/cli/tap-sipstat.c
new file mode 100644
index 0000000000..b8273219ba
--- /dev/null
+++ b/ui/cli/tap-sipstat.c
@@ -0,0 +1,443 @@
+/* tap_sipstat.c
+ * sip message counter for wireshark
+ *
+ * $Id$
+ * Copied from ui/gtk/sip_stat.c and tap-httpstat.c
+ *
+ * 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.
+ */
+
+#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/value_string.h"
+#include <epan/dissectors/packet-sip.h>
+
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _sip_stats_t {
+ char *filter;
+ guint32 packets; /* number of sip packets, including continuations */
+ guint32 resent_packets;
+ guint32 average_setup_time;
+ guint32 max_setup_time;
+ guint32 min_setup_time;
+ guint32 no_of_completed_calls;
+ guint64 total_setup_time;
+ GHashTable *hash_responses;
+ GHashTable *hash_requests;
+} sipstat_t;
+
+/* used to keep track of the stats for a specific response code
+ * for example it can be { 3, 404, "Not Found" ,...}
+ * which means we captured 3 reply sip/1.1 404 Not Found */
+typedef struct _sip_response_code_t {
+ guint32 packets; /* 3 */
+ guint response_code; /* 404 */
+ const gchar *name; /* Not Found */
+ sipstat_t *sp;
+} sip_response_code_t;
+
+/* used to keep track of the stats for a specific request string */
+typedef struct _sip_request_method_t {
+ gchar *response; /* eg. : INVITE */
+ guint32 packets;
+ sipstat_t *sp;
+} sip_request_method_t;
+
+/* TODO: extra codes to be added from SIP extensions? */
+static const value_string vals_status_code[] = {
+ { 100, "Trying"},
+ { 180, "Ringing"},
+ { 181, "Call Is Being Forwarded"},
+ { 182, "Queued"},
+ { 183, "Session Progress"},
+ { 199, "Informational - Others" },
+
+ { 200, "OK"},
+ { 202, "Accepted"},
+ { 204, "No Notification"},
+ { 299, "Success - Others"}, /* used to keep track of other Success packets */
+
+ { 300, "Multiple Choices"},
+ { 301, "Moved Permanently"},
+ { 302, "Moved Temporarily"},
+ { 305, "Use Proxy"},
+ { 380, "Alternative Service"},
+ { 399, "Redirection - Others"},
+
+ { 400, "Bad Request"},
+ { 401, "Unauthorized"},
+ { 402, "Payment Required"},
+ { 403, "Forbidden"},
+ { 404, "Not Found"},
+ { 405, "Method Not Allowed"},
+ { 406, "Not Acceptable"},
+ { 407, "Proxy Authentication Required"},
+ { 408, "Request Timeout"},
+ { 410, "Gone"},
+ { 412, "Conditional Request Failed"},
+ { 413, "Request Entity Too Large"},
+ { 414, "Request-URI Too Long"},
+ { 415, "Unsupported Media Type"},
+ { 416, "Unsupported URI Scheme"},
+ { 420, "Bad Extension"},
+ { 421, "Extension Required"},
+ { 422, "Session Timer Too Small"},
+ { 423, "Interval Too Brief"},
+ { 428, "Use Identity Header"},
+ { 429, "Provide Referrer Identity"},
+ { 430, "Flow Failed"},
+ { 433, "Anonymity Disallowed"},
+ { 436, "Bad Identity-Info"},
+ { 437, "Unsupported Certificate"},
+ { 438, "Invalid Identity Header"},
+ { 439, "First Hop Lacks Outbound Support"},
+ { 440, "Max-Breadth Exceeded"},
+ { 470, "Consent Needed"},
+ { 480, "Temporarily Unavailable"},
+ { 481, "Call/Transaction Does Not Exist"},
+ { 482, "Loop Detected"},
+ { 483, "Too Many Hops"},
+ { 484, "Address Incomplete"},
+ { 485, "Ambiguous"},
+ { 486, "Busy Here"},
+ { 487, "Request Terminated"},
+ { 488, "Not Acceptable Here"},
+ { 489, "Bad Event"},
+ { 491, "Request Pending"},
+ { 493, "Undecipherable"},
+ { 494, "Security Agreement Required"},
+ { 499, "Client Error - Others"},
+
+ { 500, "Server Internal Error"},
+ { 501, "Not Implemented"},
+ { 502, "Bad Gateway"},
+ { 503, "Service Unavailable"},
+ { 504, "Server Time-out"},
+ { 505, "Version Not Supported"},
+ { 513, "Message Too Large"},
+ { 599, "Server Error - Others"},
+
+ { 600, "Busy Everywhere"},
+ { 603, "Decline"},
+ { 604, "Does Not Exist Anywhere"},
+ { 606, "Not Acceptable"},
+ { 699, "Global Failure - Others"},
+
+ { 0, NULL}
+};
+
+/* Create tables for responses and requests */
+static void
+sip_init_hash(sipstat_t *sp)
+{
+ int i;
+
+ /* Create responses table */
+ sp->hash_responses = g_hash_table_new(g_int_hash, g_int_equal);
+
+ /* Add all response codes */
+ for (i=0 ; vals_status_code[i].strptr ; i++)
+ {
+ gint *key = g_malloc (sizeof(gint));
+ sip_response_code_t *sc = g_malloc (sizeof(sip_response_code_t));
+ *key = vals_status_code[i].value;
+ sc->packets=0;
+ sc->response_code = *key;
+ sc->name=vals_status_code[i].strptr;
+ sc->sp = sp;
+ g_hash_table_insert(sc->sp->hash_responses, key, sc);
+ }
+
+ /* Create empty requests table */
+ sp->hash_requests = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+static void
+sip_draw_hash_requests( gchar *key _U_ , sip_request_method_t *data, gchar * format)
+{
+ if (data->packets==0)
+ return;
+ printf( format, data->response, data->packets);
+}
+
+static void
+sip_draw_hash_responses( gint * key _U_ , sip_response_code_t *data, char * format)
+{
+ if (data==NULL) {
+ g_warning("C'est quoi ce borderl key=%d\n", *key);
+ exit(EXIT_FAILURE);
+ }
+ if (data->packets==0)
+ return;
+ printf(format, data->response_code, data->name, data->packets );
+}
+
+/* NOT USED at this moment */
+/*
+static void
+sip_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
+{
+ g_free(key);
+ g_free(value);
+}
+*/
+
+static void
+sip_reset_hash_responses(gchar *key _U_ , sip_response_code_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+static void
+sip_reset_hash_requests(gchar *key _U_ , sip_request_method_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+
+static void
+sipstat_reset(void *psp )
+{
+ sipstat_t *sp=psp;
+ if (sp) {
+ sp->packets = 0;
+ sp->resent_packets = 0;
+ sp->average_setup_time = 0;
+ sp->max_setup_time = 0;
+ sp->min_setup_time = 0;
+ sp->no_of_completed_calls = 0;
+ sp->total_setup_time = 0;
+
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)sip_reset_hash_responses, NULL);
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)sip_reset_hash_requests, NULL);
+ }
+}
+
+
+/* Main entry point to SIP tap */
+static int
+sipstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ const sip_info_value_t *value=pri;
+ sipstat_t *sp = (sipstat_t *)psp;
+
+ /* Total number of packets, including continuation packets */
+ sp->packets++;
+
+ /* Calculate average setup time */
+ if (value->setup_time){
+ sp->no_of_completed_calls++;
+ /* Check if it's the first value */
+ if ( sp->total_setup_time == 0 ){
+ sp->average_setup_time = value->setup_time;
+ sp->total_setup_time = value->setup_time;
+ sp->max_setup_time = value->setup_time;
+ sp->min_setup_time = value->setup_time;
+ }else{
+ sp->total_setup_time = sp->total_setup_time + value->setup_time;
+ if (sp->max_setup_time < value->setup_time){
+ sp->max_setup_time = value->setup_time;
+ }
+ if (sp->min_setup_time > value->setup_time){
+ sp->min_setup_time = value->setup_time;
+ }
+ /* Calculate average */
+ sp->average_setup_time = (guint32)(sp->total_setup_time / sp->no_of_completed_calls);
+ }
+ }
+
+ /* Update resent count if flag set */
+ if (value->resend)
+ {
+ sp->resent_packets++;
+ }
+
+
+ /* Looking at both requests and responses */
+ if (value->response_code != 0)
+ {
+ /* Responses */
+ guint *key = g_malloc(sizeof(guint));
+ sip_response_code_t *sc;
+
+ /* Look up response code in hash table */
+ *key = value->response_code;
+ sc = g_hash_table_lookup(sp->hash_responses, key);
+ if (sc==NULL)
+ {
+ /* Non-standard status code ; we classify it as others
+ * in the relevant category
+ * (Informational,Success,Redirection,Client Error,Server Error,Global Failure)
+ */
+ int i = value->response_code;
+ if ((i<100) || (i>=700))
+ {
+ /* Forget about crazy values */
+ return 0;
+ }
+ else if (i<200)
+ {
+ *key=199; /* Hopefully, this status code will never be used */
+ }
+ else if (i<300)
+ {
+ *key=299;
+ }
+ else if (i<400)
+ {
+ *key=399;
+ }
+ else if (i<500)
+ {
+ *key=499;
+ }
+ else if (i<600)
+ {
+ *key=599;
+ }
+ else
+ {
+ *key = 699;
+ }
+
+ /* Now look up this fallback code to get its text description */
+ sc = g_hash_table_lookup(sp->hash_responses, key);
+ if (sc==NULL)
+ {
+ return 0;
+ }
+ }
+ sc->packets++;
+ }
+ else if (value->request_method)
+ {
+ /* Requests */
+ sip_request_method_t *sc;
+
+ /* Look up the request method in the table */
+ sc = g_hash_table_lookup(sp->hash_requests, value->request_method);
+ if (sc == NULL)
+ {
+ /* First of this type. Create structure and initialise */
+ sc=g_malloc(sizeof(sip_request_method_t));
+ sc->response = g_strdup(value->request_method);
+ sc->packets = 1;
+ sc->sp = sp;
+ /* Insert it into request table */
+ g_hash_table_insert(sp->hash_requests, sc->response, sc);
+ }
+ else
+ {
+ /* Already existed, just update count for that method */
+ sc->packets++;
+ }
+ /* g_free(value->request_method); */
+ }
+ else
+ {
+ /* No request method set. Just ignore */
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+sipstat_draw(void *psp )
+{
+ sipstat_t *sp=psp;
+ printf("\n");
+ printf("===================================================================\n");
+ if (sp->filter == NULL)
+ printf("SIP Statistics\n");
+ else
+ printf("SIP Statistics with filter %s\n", sp->filter);
+
+ printf("\nNumber of SIP messages: %d", sp->packets);
+ printf("\nNumber of resent SIP messages: %d\n", sp->resent_packets);
+ printf( "\n* SIP Status Codes in reply packets\n");
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)sip_draw_hash_responses,
+ " SIP %3d %-15s : %5d Packets\n");
+ printf("\n* List of SIP Request methods\n");
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)sip_draw_hash_requests,
+ " %-15s : %5d Packets\n");
+ printf( "\n* Average setup time %d ms\n Min %d ms\n Max %d ms\n", sp->average_setup_time, sp->min_setup_time, sp->max_setup_time);
+ printf("===================================================================\n");
+}
+
+static void
+sipstat_init(const char *optarg, void* userdata _U_)
+{
+ sipstat_t *sp;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if (strncmp (optarg, "sip,stat,", 9) == 0){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+
+ sp = g_malloc( sizeof(sipstat_t) );
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ /*g_hash_table_foreach( sip_status, (GHFunc)sip_reset_hash_responses, NULL);*/
+
+
+ error_string = register_tap_listener(
+ "sip",
+ sp,
+ filter,
+ 0,
+ sipstat_reset,
+ sipstat_packet,
+ sipstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->filter);
+ g_free(sp);
+ fprintf (stderr, "tshark: Couldn't register sip,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ sp->packets = 0;
+ sp->resent_packets = 0;
+ sip_init_hash(sp);
+}
+
+void
+register_tap_listener_sipstat(void)
+{
+ register_stat_cmd_arg("sip,stat", sipstat_init,NULL);
+}
diff --git a/ui/cli/tap-smbsids.c b/ui/cli/tap-smbsids.c
new file mode 100644
index 0000000000..2955bcfbed
--- /dev/null
+++ b/ui/cli/tap-smbsids.c
@@ -0,0 +1,100 @@
+/* tap-smbsids.c
+ * smbstat 2003 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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/dissectors/packet-smb-sidsnooping.h>
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "epan/value_string.h"
+#include <epan/dissectors/packet-smb.h>
+
+
+static int
+smbsids_packet(void *pss _U_, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *psi _U_)
+{
+ return 1;
+}
+
+static void
+enum_sids(gpointer key _U_, gpointer value, gpointer userdata _U_)
+{
+ sid_name *sn=(sid_name *)value;
+
+ printf("%-60s %s\n", sn->sid, sn->name);
+ return;
+}
+
+static void
+smbsids_draw(void *pss _U_)
+{
+ printf("\n");
+ printf("===================================================================\n");
+ printf("SMB SID List:\n");
+ g_hash_table_foreach(sid_name_table, enum_sids, NULL);
+ printf("===================================================================\n");
+}
+
+
+static void
+smbsids_init(const char *optarg _U_, void* userdata _U_)
+{
+ GString *error_string;
+
+ if(!sid_name_snooping){
+ fprintf(stderr,"The -z smb,sids function needs SMB/SID-Snooping to be enabled.\n");
+ fprintf(stderr,"Either enable Edit/Preferences/Protocols/SMB/Snoop SID name mappings in wireshark\n");
+ fprintf(stderr,"or override the preference file by specifying\n");
+ fprintf(stderr," -o \"smb.sid_name_snooping=TRUE\"\n");
+ fprintf(stderr,"on the tshark command line.\n");
+ exit(1);
+ }
+
+
+ error_string=register_tap_listener("smb", NULL, NULL, 0, NULL, smbsids_packet, smbsids_draw);
+ if(error_string){
+ fprintf(stderr, "tshark: Couldn't register smb,sids tap:%s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_smbsids(void)
+{
+ register_stat_cmd_arg("smb,sids", smbsids_init,NULL);
+}
+
diff --git a/ui/cli/tap-smbstat.c b/ui/cli/tap-smbstat.c
new file mode 100644
index 0000000000..2a3439e6e1
--- /dev/null
+++ b/ui/cli/tap-smbstat.c
@@ -0,0 +1,260 @@
+/* tap-smbstat.c
+ * smbstat 2003 Ronnie Sahlberg
+ *
+ * $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.
+ */
+
+#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/value_string.h"
+#include <epan/dissectors/packet-smb.h>
+#include "timestats.h"
+
+#define MICROSECS_PER_SEC 1000000
+#define NANOSECS_PER_SEC 1000000000
+
+/* used to keep track of the statistics for an entire program interface */
+typedef struct _smbstat_t {
+ char *filter;
+ timestat_t proc[256];
+ timestat_t trans2[256];
+ timestat_t nt_trans[256];
+} smbstat_t;
+
+
+
+static int
+smbstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *psi)
+{
+ smbstat_t *ss=(smbstat_t *)pss;
+ const smb_info_t *si=psi;
+ nstime_t t, deltat;
+ timestat_t *sp=NULL;
+
+ /* we are only interested in reply packets */
+ if(si->request){
+ return 0;
+ }
+ /* if we havnt seen the request, just ignore it */
+ if(!si->sip){
+ return 0;
+ }
+
+ if(si->cmd==0xA0 && si->sip->extra_info_type == SMB_EI_NTI){
+ smb_nt_transact_info_t *sti=(smb_nt_transact_info_t *)si->sip->extra_info;
+
+ /*nt transaction*/
+ if(sti){
+ sp=&(ss->nt_trans[sti->subcmd]);
+ }
+ } else if(si->cmd==0x32 && si->sip->extra_info_type == SMB_EI_T2I){
+ smb_transact2_info_t *st2i=(smb_transact2_info_t *)si->sip->extra_info;
+
+ /*transaction2*/
+ if(st2i){
+ sp=&(ss->trans2[st2i->subcmd]);
+ }
+ } else {
+ sp=&(ss->proc[si->cmd]);
+ }
+
+ /* calculate time delta between request and reply */
+ t=pinfo->fd->abs_ts;
+ nstime_delta(&deltat, &t, &si->sip->req_time);
+
+ if(sp){
+ time_stat_update(sp,&deltat, pinfo);
+ }
+
+ return 1;
+}
+
+static void
+smbstat_draw(void *pss)
+{
+ smbstat_t *ss=(smbstat_t *)pss;
+ guint32 i;
+ guint64 td;
+ printf("\n");
+ printf("=================================================================\n");
+ printf("SMB SRT Statistics:\n");
+ printf("Filter: %s\n",ss->filter?ss->filter:"");
+ printf("Commands Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0;i<256;i++){
+ /* nothing seen, nothing to do */
+ if(ss->proc[i].num==0){
+ continue;
+ }
+
+ /* we deal with transaction2 later */
+ if(i==0x32){
+ continue;
+ }
+
+ /* we deal with nt transaction later */
+ if(i==0xA0){
+ continue;
+ }
+
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(ss->proc[i].tot.secs)) * NANOSECS_PER_SEC + ss->proc[i].tot.nsecs;
+
+ td = ((td / ss->proc[i].num) + 500) / 1000;
+
+ printf("%-25s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ val_to_str_ext(i, &smb_cmd_vals_ext, "Unknown (0x%02x)"),
+ ss->proc[i].num,
+ (int)(ss->proc[i].min.secs),(ss->proc[i].min.nsecs+500)/1000,
+ (int)(ss->proc[i].max.secs),(ss->proc[i].max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+
+ printf("\n");
+ printf("Transaction2 Commands Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0;i<256;i++){
+ /* nothing seen, nothing to do */
+ if(ss->trans2[i].num==0){
+ continue;
+ }
+
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(ss->trans2[i].tot.secs)) * NANOSECS_PER_SEC + ss->trans2[i].tot.nsecs;
+ td = ((td / ss->trans2[i].num) + 500) / 1000;
+
+ printf("%-25s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ val_to_str_ext(i, &trans2_cmd_vals_ext, "Unknown (0x%02x)"),
+ ss->trans2[i].num,
+ (int)(ss->trans2[i].min.secs),(ss->trans2[i].min.nsecs+500)/1000,
+ (int)(ss->trans2[i].max.secs),(ss->trans2[i].max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+
+ printf("\n");
+ printf("NT Transaction Commands Calls Min SRT Max SRT Avg SRT\n");
+ for(i=0;i<256;i++){
+ /* nothing seen, nothing to do */
+ if(ss->nt_trans[i].num==0){
+ continue;
+ }
+ /* Scale the average SRT in units of 1us and round to the nearest us. */
+ td = ((guint64)(ss->nt_trans[i].tot.secs)) * NANOSECS_PER_SEC + ss->nt_trans[i].tot.nsecs;
+ td = ((td / ss->nt_trans[i].num) + 500) / 1000;
+
+ printf("%-25s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
+ val_to_str_ext(i, &nt_cmd_vals_ext, "Unknown (0x%02x)"),
+ ss->nt_trans[i].num,
+ (int)(ss->nt_trans[i].min.secs),(ss->nt_trans[i].min.nsecs+500)/1000,
+ (int)(ss->nt_trans[i].max.secs),(ss->nt_trans[i].max.nsecs+500)/1000,
+ td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
+ );
+ }
+
+ printf("=================================================================\n");
+}
+
+
+static void
+smbstat_init(const char *optarg,void* userdata _U_)
+{
+ smbstat_t *ss;
+ guint32 i;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if(!strncmp(optarg,"smb,srt,",8)){
+ filter=optarg+8;
+ } else {
+ filter=NULL;
+ }
+
+ ss=g_malloc(sizeof(smbstat_t));
+ if(filter){
+ ss->filter=g_strdup(filter);
+ } else {
+ ss->filter=NULL;
+ }
+
+ for(i=0;i<256;i++){
+ ss->proc[i].num=0;
+ ss->proc[i].min_num=0;
+ ss->proc[i].max_num=0;
+ ss->proc[i].min.secs=0;
+ ss->proc[i].min.nsecs=0;
+ ss->proc[i].max.secs=0;
+ ss->proc[i].max.nsecs=0;
+ ss->proc[i].tot.secs=0;
+ ss->proc[i].tot.nsecs=0;
+
+ ss->trans2[i].num=0;
+ ss->trans2[i].min_num=0;
+ ss->trans2[i].max_num=0;
+ ss->trans2[i].min.secs=0;
+ ss->trans2[i].min.nsecs=0;
+ ss->trans2[i].max.secs=0;
+ ss->trans2[i].max.nsecs=0;
+ ss->trans2[i].tot.secs=0;
+ ss->trans2[i].tot.nsecs=0;
+
+ ss->nt_trans[i].num=0;
+ ss->nt_trans[i].min_num=0;
+ ss->nt_trans[i].max_num=0;
+ ss->nt_trans[i].min.secs=0;
+ ss->nt_trans[i].min.nsecs=0;
+ ss->nt_trans[i].max.secs=0;
+ ss->nt_trans[i].max.nsecs=0;
+ ss->nt_trans[i].tot.secs=0;
+ ss->nt_trans[i].tot.nsecs=0;
+ }
+
+ error_string=register_tap_listener("smb", ss, filter, 0, NULL, smbstat_packet, smbstat_draw);
+ if(error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(ss->filter);
+ g_free(ss);
+
+ fprintf(stderr, "tshark: Couldn't register smb,srt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+
+void
+register_tap_listener_smbstat(void)
+{
+ register_stat_cmd_arg("smb,srt", smbstat_init,NULL);
+}
+
diff --git a/ui/cli/tap-stats_tree.c b/ui/cli/tap-stats_tree.c
new file mode 100644
index 0000000000..e9568b306c
--- /dev/null
+++ b/ui/cli/tap-stats_tree.c
@@ -0,0 +1,145 @@
+/* tap-stats_tree.c
+ * tshark's tap implememntation of stats_tree
+ * 2005, Luis E. G. Ontanon
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <epan/stats_tree_priv.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/report_err.h>
+
+/* actually unused */
+struct _st_node_pres {
+ void *dummy;
+};
+
+struct _tree_pres {
+ void** dummy;
+};
+
+struct _tree_cfg_pres {
+ gchar *init_string;
+};
+
+static void
+draw_stats_tree(void *psp)
+{
+ stats_tree *st = (stats_tree *)psp;
+ GString *s;
+ gchar *fmt;
+ stat_node *child;
+
+ s = g_string_new("\n===================================================================\n");
+ fmt = g_strdup_printf(" %%s%%-%us%%12s\t%%12s\t%%12s\n",stats_tree_branch_max_namelen(&st->root,0));
+ g_string_append_printf(s,fmt,"",st->cfg->name,"value","rate","percent");
+ g_free(fmt);
+ g_string_append_printf(s,"-------------------------------------------------------------------\n");
+
+ for (child = st->root.children; child; child = child->next ) {
+ stats_tree_branch_to_str(child,s,0);
+ }
+
+ s = g_string_append(s,"\n===================================================================\n");
+
+ printf("%s",s->str);
+
+}
+
+static void
+init_stats_tree(const char *optarg, void *userdata _U_)
+{
+ char *abbr = stats_tree_get_abbr(optarg);
+ GString *error_string;
+ stats_tree_cfg *cfg = NULL;
+ stats_tree *st = NULL;
+
+ if (abbr) {
+ cfg = stats_tree_get_cfg_by_abbr(abbr);
+
+ if (cfg != NULL) {
+ if (strncmp (optarg, cfg->pr->init_string, strlen(cfg->pr->init_string)) == 0){
+ st = stats_tree_new(cfg,NULL,optarg+strlen(cfg->pr->init_string));
+ } else {
+ report_failure("Wrong stats_tree (%s) found when looking at ->init_string",abbr);
+ return;
+ }
+ } else {
+ report_failure("no such stats_tree (%s) found in stats_tree registry",abbr);
+ return;
+ }
+
+ g_free(abbr);
+
+ } else {
+ report_failure("could not obtain stats_tree abbr (%s) from arg '%s'",abbr,optarg);
+ return;
+ }
+
+ error_string = register_tap_listener(st->cfg->tapname,
+ st,
+ st->filter,
+ st->cfg->flags,
+ stats_tree_reset,
+ stats_tree_packet,
+ draw_stats_tree);
+
+ if (error_string) {
+ report_failure("stats_tree for: %s failed to attach to the tap: %s",cfg->name,error_string->str);
+ return;
+ }
+
+ if (cfg->init) cfg->init(st);
+
+}
+
+void
+register_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_)
+{
+ stats_tree_cfg *cfg = (stats_tree_cfg *)v;
+
+ cfg->pr = (tree_cfg_pres *)g_malloc(sizeof(tree_cfg_pres));
+ cfg->pr->init_string = g_strdup_printf("%s,tree", cfg->abbr);
+
+ register_stat_cmd_arg(cfg->pr->init_string, init_stats_tree, NULL);
+
+}
+
+static void
+free_tree_presentation(stats_tree *st)
+{
+ g_free(st->pr);
+}
+
+
+void
+register_tap_listener_stats_tree_stat(void)
+{
+ stats_tree_presentation(register_stats_tree_tap, NULL, NULL, NULL, NULL,
+ NULL, free_tree_presentation, NULL, NULL, NULL);
+}
diff --git a/ui/cli/tap-sv.c b/ui/cli/tap-sv.c
new file mode 100644
index 0000000000..db3f84f8f8
--- /dev/null
+++ b/ui/cli/tap-sv.c
@@ -0,0 +1,87 @@
+/* tap-sv.c
+ * Copyright 2008 Michael Bernhard
+ *
+ * $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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.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/nstime.h>
+#include <epan/dissectors/packet-sv.h>
+
+static int
+sv_packet(void *prs _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
+{
+ int i;
+ const sv_frame_data * sv_data = pri;
+
+ printf("%f %u ", nstime_to_sec(&pinfo->fd->rel_ts), sv_data->smpCnt);
+
+ for(i = 0; i < sv_data->num_phsMeas; i++) {
+ printf("%d ", sv_data->phsMeas[i].value);
+ }
+
+ printf("\n");
+
+ return 0;
+}
+
+static void
+svstat_init(const char *optarg _U_, void* userdata _U_)
+{
+ GString *error_string;
+
+ error_string = register_tap_listener(
+ "sv",
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ sv_packet,
+ NULL);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ fprintf(stderr, "tshark: Couldn't register sv,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+
+void
+register_tap_listener_sv(void)
+{
+ register_stat_cmd_arg("sv", svstat_init, NULL);
+}
diff --git a/ui/cli/tap-wspstat.c b/ui/cli/tap-wspstat.c
new file mode 100644
index 0000000000..40bce6cefc
--- /dev/null
+++ b/ui/cli/tap-wspstat.c
@@ -0,0 +1,286 @@
+/* tap-rpcstat.c
+ * wspstat 2003 Jean-Michel FAYARD
+ *
+ * $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 WSP statistics to tshark.
+ * It is only used by tshark and not wireshark
+ *
+ */
+
+#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/value_string.h"
+#include <epan/dissectors/packet-wsp.h>
+
+/* used to keep track of the stats for a specific PDU type*/
+typedef struct _wsp_pdu_t {
+ const gchar *type;
+ guint32 packets;
+} wsp_pdu_t;
+/* used to keep track of SRT statistics */
+typedef struct _wsp_status_code_t {
+ const gchar *name;
+ guint32 packets;
+} wsp_status_code_t;
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _wsp_stats_t {
+ char *filter;
+ wsp_pdu_t *pdu_stats;
+ guint32 num_pdus;
+ GHashTable *hash;
+} wspstat_t;
+
+static void
+wsp_reset_hash(gchar *key _U_ , wsp_status_code_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+static void
+wsp_print_statuscode(gint *key, wsp_status_code_t *data, char* format)
+{
+ if (data && (data->packets!=0))
+ printf(format, *key, data->packets ,data->name);
+}
+static void
+wsp_free_hash_table( gpointer key, gpointer value, gpointer user_data _U_ )
+{
+ g_free(key);
+ g_free(value);
+}
+static void
+wspstat_reset(void *psp)
+{
+ wspstat_t *sp=psp;
+ guint32 i;
+
+ for(i=1;i<=sp->num_pdus;i++)
+ {
+ sp->pdu_stats[i].packets=0;
+ }
+ g_hash_table_foreach( sp->hash, (GHFunc)wsp_reset_hash, NULL);
+}
+
+
+/* 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.
+ *
+ * We didnt apply a filter when we registered so we will be called for
+ * ALL packets and not just the ones we are collecting stats for.
+ *
+ */
+static gint
+pdut2index(gint pdut)
+{
+ if (pdut<=0x09) return pdut;
+ if (pdut>=0x40){
+ if (pdut <= 0x44){
+ return pdut-54;
+ } else if (pdut==0x60||pdut==0x61){
+ return pdut-81;
+ }
+ }
+ return 0;
+}
+static gint
+index2pdut(gint pdut)
+{
+ if (pdut<=0x09)
+ return pdut;
+ if (pdut<=14)
+ return pdut+54;
+ if (pdut<=16)
+ return pdut+81;
+ return 0;
+}
+static int
+wspstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ wspstat_t *sp=psp;
+ const wsp_info_value_t *value=pri;
+ gint idx = pdut2index(value->pdut);
+ int retour=0;
+
+ if (value->status_code != 0) {
+ gint *key=g_malloc( sizeof(gint) );
+ wsp_status_code_t *sc;
+ *key=value->status_code ;
+ sc = g_hash_table_lookup(
+ sp->hash,
+ key);
+ if (!sc) {
+ sc = g_malloc( sizeof(wsp_status_code_t) );
+ sc -> packets = 1;
+ sc -> name = NULL;
+ g_hash_table_insert(
+ sp->hash,
+ key,
+ sc);
+ } else {
+ sc->packets++;
+ }
+ retour=1;
+ }
+
+
+
+ if (idx!=0) {
+ sp->pdu_stats[ idx ].packets++;
+ retour = 1;
+ }
+ return retour;
+}
+
+
+/* This callback is used when tshark wants us to draw/update our
+ * data to the output device. Since this is tshark only output is
+ * stdout.
+ * TShark will only call this callback once, which is when tshark has
+ * finished reading all packets and exists.
+ * If used with wireshark this may be called any time, perhaps once every 3
+ * seconds or so.
+ * This function may even be called in parallell with (*reset) or (*draw)
+ * so make sure there are no races. The data in the rpcstat_t can thus change
+ * beneath us. Beware.
+ */
+static void
+wspstat_draw(void *psp)
+{
+ wspstat_t *sp=psp;
+ guint32 i;
+
+ printf("\n");
+ printf("===================================================================\n");
+ printf("WSP Statistics:\n");
+ printf("%-23s %9s || %-23s %9s\n","PDU Type", "Packets", "PDU Type", "Packets");
+ for(i=1; i<= ((sp->num_pdus+1)/2) ; i++)
+ {
+ guint32 ii=i+sp->num_pdus/2;
+ printf("%-23s %9d", sp->pdu_stats[i ].type, sp->pdu_stats[i ].packets);
+ printf(" || ");
+ if (ii< (sp->num_pdus) )
+ printf("%-23s %9d\n", sp->pdu_stats[ii].type, sp->pdu_stats[ii].packets);
+ else
+ printf("\n");
+ }
+ printf("\nStatus code in reply packets\n");
+ printf( "Status Code Packets Description\n");
+ g_hash_table_foreach( sp->hash, (GHFunc) wsp_print_statuscode,
+ " 0x%02X %9d %s\n" ) ;
+ printf("===================================================================\n");
+}
+
+/* When called, this function will create a new instance of wspstat.
+ * program and version are whick onc-rpc program/version we want to
+ * collect statistics for.
+ * This function is called from tshark when it parses the -z wsp, arguments
+ * and it creates a new instance to store statistics in and registers this
+ * new instance for the wsp tap.
+ */
+static void
+wspstat_init(const char *optarg, void* userdata _U_)
+{
+ wspstat_t *sp;
+ const char *filter=NULL;
+ guint32 i;
+ GString *error_string;
+ wsp_status_code_t *sc;
+ const value_string *wsp_vals_status_p;
+
+ if (!strncmp (optarg, "wsp,stat," , 9)){
+ filter=optarg+9;
+ } else {
+ filter=NULL;
+ }
+
+
+ sp = g_malloc( sizeof(wspstat_t) );
+ sp->hash = g_hash_table_new( g_int_hash, g_int_equal);
+ wsp_vals_status_p = VALUE_STRING_EXT_VS_P(&wsp_vals_status_ext);
+ for (i=0 ; wsp_vals_status_p[i].strptr ; i++ )
+ {
+ gint *key;
+ sc=g_malloc( sizeof(wsp_status_code_t) );
+ key=g_malloc( sizeof(gint) );
+ sc->packets=0;
+ sc->name=wsp_vals_status_p[i].strptr;
+ *key=wsp_vals_status_p[i].value;
+ g_hash_table_insert(
+ sp->hash,
+ key,
+ sc);
+ }
+ sp->num_pdus = 16;
+ sp->pdu_stats=g_malloc( (sp->num_pdus+1) * sizeof( wsp_pdu_t) );
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ for (i=0;i<sp->num_pdus; i++)
+ {
+ sp->pdu_stats[i].packets=0;
+ sp->pdu_stats[i].type = match_strval_ext( index2pdut( i ), &wsp_vals_pdu_type_ext) ;
+ }
+
+ error_string = register_tap_listener(
+ "wsp",
+ sp,
+ filter,
+ 0,
+ wspstat_reset,
+ wspstat_packet,
+ wspstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->pdu_stats);
+ g_free(sp->filter);
+ g_free(sp);
+ g_hash_table_foreach( sp->hash, (GHFunc) wsp_free_hash_table, NULL ) ;
+ g_hash_table_destroy( sp->hash );
+ fprintf(stderr, "tshark: Couldn't register wsp,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+}
+void
+register_tap_listener_wspstat(void)
+{
+ register_stat_cmd_arg("wsp,stat,", wspstat_init,NULL);
+}