summaryrefslogtreecommitdiffstats
path: root/ui/cli/tap-expert.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui/cli/tap-expert.c')
-rw-r--r--ui/cli/tap-expert.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/ui/cli/tap-expert.c b/ui/cli/tap-expert.c
new file mode 100644
index 00000000..3fcf0e7f
--- /dev/null
+++ b/ui/cli/tap-expert.c
@@ -0,0 +1,287 @@
+/* tap-expert.c
+ * Copyright 2011 Martin Mathieson
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <epan/packet.h>
+#include <epan/tap.h>
+#include <epan/stat_tap_ui.h>
+#include <epan/expert.h>
+#include <wsutil/ws_assert.h>
+
+void register_tap_listener_expert_info(void);
+
+/* Tap data */
+typedef enum severity_level_t {
+ comment_level = 0,
+ chat_level,
+ 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 = comment_level;
+
+typedef struct expert_entry
+{
+ guint32 group;
+ int frequency;
+ const gchar *protocol;
+ gchar *summary;
+} 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 = (expert_tapdata_t *)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 tap_packet_status
+expert_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_,
+ const void *pointer, tap_flags_t flags _U_)
+{
+ const expert_info_t *ei = (const expert_info_t *)pointer;
+ expert_tapdata_t *data = (expert_tapdata_t *)tapdata;
+ severity_level_t severity_level;
+ expert_entry tmp_entry;
+ expert_entry *entry;
+ guint n;
+
+ switch (ei->severity) {
+ case PI_COMMENT:
+ severity_level = comment_level;
+ break;
+ 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:
+ ws_assert_not_reached();
+ return TAP_PACKET_DONT_REDRAW;
+ }
+
+ /* Don't store details at a lesser severity than we are interested in */
+ if (severity_level < lowest_report_level) {
+ return TAP_PACKET_REDRAW; /* XXX - TAP_PACKET_DONT_REDRAW? */
+ }
+
+ /* 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 TAP_PACKET_REDRAW;
+ }
+ }
+
+ /* Else Add new item to end of list for severity level */
+ entry = &tmp_entry;
+ /* 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;
+ /* Store a copy of the expert entry */
+ g_array_append_val(data->ei_array[severity_level], tmp_entry);
+
+ return TAP_PACKET_REDRAW;
+}
+
+/* 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;
+ gchar *tmp_str;
+
+ /* 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 (%d)\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);
+ tmp_str = val_to_str_wmem(NULL, ei->group, expert_group_vals, "Unknown (%d)");
+ printf("%12d %10s %18s %s\n",
+ ei->frequency,
+ tmp_str,
+ ei->protocol, ei->summary);
+ wmem_free(NULL, tmp_str);
+ }
+}
+
+/* (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");
+ draw_items_for_severity(hs->ei_array[comment_level], "Comments");
+}
+
+static void
+expert_tapdata_free(expert_tapdata_t* hs)
+{
+ for (int n = 0; n < max_level; n++) {
+ g_array_free(hs->ei_array[n], TRUE);
+ }
+ g_string_chunk_free(hs->text);
+ g_free(hs);
+}
+
+/* Create a new expert stats struct */
+static void expert_stat_init(const char *opt_arg, 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(opt_arg, "expert", 6) == 0) {
+ /* Skip those characters */
+ args = opt_arg + 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;
+ } else if (g_ascii_strncasecmp(args, ",comment", 8) == 0) {
+ lowest_report_level = comment_level;
+ args += 8;
+ }
+ }
+
+ /* Second (optional) arg is a filter string */
+ if (args != NULL) {
+ if (args[0] == ',') {
+ filter = args+1;
+ }
+ }
+
+ /* Create top-level struct */
+ hs = g_new0(expert_tapdata_t, 1);
+
+ /* 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_entry), 1000);
+ }
+
+ /**********************************************/
+ /* Register the tap listener */
+ /**********************************************/
+
+ error_string = register_tap_listener("expert", hs,
+ filter, 0,
+ expert_stat_reset,
+ expert_stat_packet,
+ expert_stat_draw,
+ (tap_finish_cb)expert_tapdata_free);
+ if (error_string) {
+ printf("Expert tap error (%s)!\n", error_string->str);
+ g_string_free(error_string, TRUE);
+ expert_tapdata_free(hs);
+ exit(1);
+ }
+}
+
+static stat_tap_ui expert_stat_ui = {
+ REGISTER_STAT_GROUP_GENERIC,
+ NULL,
+ "expert",
+ expert_stat_init,
+ 0,
+ NULL
+};
+
+/* Register this tap listener (need void on own so line register function found) */
+void
+register_tap_listener_expert_info(void)
+{
+ register_stat_tap_ui(&expert_stat_ui, NULL);
+}