diff options
Diffstat (limited to 'ui/cli/tap-expert.c')
-rw-r--r-- | ui/cli/tap-expert.c | 287 |
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); +} |