aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/libwireshark0.symbols14
-rw-r--r--epan/CMakeLists.txt1
-rw-r--r--epan/Makefile.am2
-rw-r--r--epan/dissectors/packet-frame.c118
-rw-r--r--epan/dissectors/packet-tcp.c164
-rw-r--r--epan/sequence_analysis.c275
-rw-r--r--epan/sequence_analysis.h196
-rw-r--r--ui/gtk/flow_graph.c88
-rw-r--r--ui/gtk/lbm_uimflow_dlg.c2
-rw-r--r--ui/qt/sequence_diagram.cpp2
-rw-r--r--ui/qt/sequence_dialog.cpp52
-rw-r--r--ui/qt/sequence_dialog.h2
-rw-r--r--ui/qt/voip_calls_dialog.cpp2
-rw-r--r--ui/tap-sequence-analysis.c374
-rw-r--r--ui/tap-sequence-analysis.h84
15 files changed, 819 insertions, 557 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols
index c6c7283a66..220b020e5d 100644
--- a/debian/libwireshark0.symbols
+++ b/debian/libwireshark0.symbols
@@ -1293,6 +1293,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
register_postdissector@Base 1.9.1
register_postseq_cleanup_routine@Base 1.9.1
register_rtd_table@Base 1.99.8
+ register_seq_analysis@Base 2.5.0
register_shutdown_routine@Base 2.3.0
register_srt_table@Base 1.99.8
register_stat_tap_table_ui@Base 2.1.0
@@ -1364,6 +1365,19 @@ libwireshark.so.0 libwireshark0 #MINVER#
scsi_smc_vals_ext@Base 1.12.0~rc1
scsi_ssc_vals_ext@Base 1.12.0~rc1
sctp_port_to_display@Base 1.99.2
+ sequence_analysis_find_by_name@Base 2.5.0
+ sequence_analysis_free_nodes@Base 2.5.0
+ sequence_analysis_get_name@Base 2.5.0
+ sequence_analysis_get_nodes@Base 2.5.0
+ sequence_analysis_get_packet_func@Base 2.5.0
+ sequence_analysis_get_tap_flags@Base 2.5.0
+ sequence_analysis_get_tap_listener_name@Base 2.5.0
+ sequence_analysis_get_ui_name@Base 2.5.0
+ sequence_analysis_info_free@Base 2.5.0
+ sequence_analysis_info_new@Base 2.5.0
+ sequence_analysis_list_free@Base 2.5.0
+ sequence_analysis_list_sort@Base 2.5.0
+ sequence_analysis_table_iterate_tables@Base 2.5.0
serv_name_lookup@Base 2.1.0
set_actual_length@Base 1.9.1
set_column_custom_fields@Base 2.1.0
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt
index 02cfcc5fa2..3f6d04266e 100644
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -256,6 +256,7 @@ set(LIBWIRESHARK_FILES
reedsolomon.c
req_resp_hdrs.c
rtd_table.c
+ sequence_analysis.c
show_exception.c
srt_table.c
stat_tap_ui.c
diff --git a/epan/Makefile.am b/epan/Makefile.am
index b1c4afb693..d782b03f1f 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -106,6 +106,7 @@ LIBWIRESHARK_SRC = \
reedsolomon.c \
req_resp_hdrs.c \
rtd_table.c \
+ sequence_analysis.c \
show_exception.c \
srt_table.c \
stat_tap_ui.c \
@@ -263,6 +264,7 @@ LIBWIRESHARK_INCLUDES_PUBLIC = \
rtd_table.h \
rtp_pt.h \
sctpppids.h \
+ sequence_analysis.h \
show_exception.h \
slow_protocol_subtypes.h \
sminmpec.h \
diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c
index aa9d1f443a..9b9a0dbaf6 100644
--- a/epan/dissectors/packet-frame.c
+++ b/epan/dissectors/packet-frame.c
@@ -35,16 +35,20 @@
#include <epan/timestamp.h>
#include <epan/prefs.h>
#include <epan/to_str.h>
+#include <epan/sequence_analysis.h>
#include <wiretap/wtap.h>
#include <epan/tap.h>
#include <epan/expert.h>
#include <wsutil/wsgcrypt.h>
#include <wsutil/str_util.h>
+#include <epan/proto_data.h>
#include <wmem/wmem.h>
#include "packet-frame.h"
+#include "packet-icmp.h"
#include "log.h"
+#include <epan/column-info.h>
#include <epan/color_filters.h>
void proto_register_frame(void);
@@ -157,6 +161,118 @@ static const value_string packet_word_reception_types[] = {
static dissector_table_t wtap_encap_dissector_table;
static dissector_table_t wtap_fts_rec_dissector_table;
+/****************************************************************************/
+/* whenever a frame packet is seen by the tap listener */
+/* Add a new frame into the graph */
+static gboolean
+frame_seq_analysis_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_)
+{
+ seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
+
+ if ((sainfo->all_packets) || (pinfo->fd->flags.passed_dfilter == 1)) {
+ gchar *protocol = NULL;
+ gchar *colinfo = NULL;
+ seq_analysis_item_t *sai = NULL;
+
+ if (sainfo->any_addr) {
+ if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) {
+ sai = g_new0(seq_analysis_item_t, 1);
+ copy_address(&(sai->src_addr),&(pinfo->net_src));
+ copy_address(&(sai->dst_addr),&(pinfo->net_dst));
+ }
+
+ } else {
+ if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) {
+ sai = g_new0(seq_analysis_item_t, 1);
+ copy_address(&(sai->src_addr),&(pinfo->src));
+ copy_address(&(sai->dst_addr),&(pinfo->dst));
+ }
+ }
+
+ if (!sai)
+ return FALSE;
+
+ sai->frame_number = pinfo->num;
+
+ if (pinfo->fd->color_filter) {
+ sai->bg_color = color_t_to_rgb(&pinfo->fd->color_filter->bg_color);
+ sai->fg_color = color_t_to_rgb(&pinfo->fd->color_filter->fg_color);
+ sai->has_color_filter = TRUE;
+ }
+
+ sai->port_src=pinfo->srcport;
+ sai->port_dst=pinfo->destport;
+ sai->protocol = g_strdup(port_type_to_str(pinfo->ptype));
+
+ if (pinfo->cinfo) {
+ col_item_t *col_item;
+ int i;
+
+ if (pinfo->cinfo->col_first[COL_INFO] >= 0) {
+ for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) {
+ col_item = &pinfo->cinfo->columns[i];
+ if (col_item->fmt_matx[COL_INFO]) {
+ colinfo = g_strdup(col_item->col_data);
+ /* break; ? or g_free(colinfo); before g_strdup() */
+ }
+ }
+ }
+
+ if (pinfo->cinfo->col_first[COL_PROTOCOL] >= 0) {
+ for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) {
+ col_item = &pinfo->cinfo->columns[i];
+ if (col_item->fmt_matx[COL_PROTOCOL]) {
+ protocol = g_strdup(col_item->col_data);
+ /* break; ? or g_free(protocol); before g_strdup() */
+ }
+ }
+ }
+ }
+
+ if (colinfo != NULL) {
+ sai->frame_label = g_strdup(colinfo);
+ if (protocol != NULL) {
+ sai->comment = g_strdup_printf("%s: %s", protocol, colinfo);
+ } else {
+ sai->comment = g_strdup(colinfo);
+ }
+ } else {
+ /* This will probably never happen...*/
+ if (protocol != NULL) {
+ sai->frame_label = g_strdup(protocol);
+ sai->comment = g_strdup(protocol);
+ }
+ }
+
+ if (pinfo->ptype == PT_NONE) {
+ icmp_info_t *p_icmp_info;
+
+ if ((p_icmp_info = (icmp_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_short_name("ICMP"), 0))) {
+ g_free(sai->protocol);
+ sai->protocol = g_strdup("ICMP");
+ sai->port_src = 0;
+ sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code;
+ } else if ((p_icmp_info = (icmp_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_short_name("ICMPv6"), 0))) {
+ g_free(sai->protocol);
+ sai->protocol = g_strdup("ICMPv6");
+ sai->port_src = 0;
+ sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code;
+ }
+ }
+
+ g_free(protocol);
+ g_free(colinfo);
+
+ sai->line_style = 1;
+ sai->conv_num = 0;
+ sai->display = TRUE;
+
+ g_queue_push_tail(sainfo->items, sai);
+ }
+
+ return TRUE;
+}
+
/*
* Routine used to register frame end routine. The routine should only
* be registered when the dissector is used in the frame, not in the
@@ -952,6 +1068,8 @@ proto_register_frame(void)
tantamount to not doing any dissection whatsoever. */
proto_set_cant_toggle(proto_frame);
+ register_seq_analysis("any", "All Flows", proto_frame, NULL, TL_REQUIRES_COLUMNS, frame_seq_analysis_packet);
+
/* Our preferences */
frame_module = prefs_register_protocol(proto_frame, NULL);
prefs_register_bool_preference(frame_module, "show_file_off",
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index e7997439f5..899326f6a6 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -35,6 +35,7 @@
#include <epan/show_exception.h>
#include <epan/conversation_table.h>
#include <epan/dissector_filters.h>
+#include <epan/sequence_analysis.h>
#include <epan/reassemble.h>
#include <epan/decode_as.h>
#include <epan/exported_pdu.h>
@@ -618,6 +619,60 @@ static const int *tcp_option_mptcp_dss_flags[] = {
const unit_name_string units_64bit_version = { " (64bits version)", NULL };
+
+static const char *
+tcp_flags_to_str(wmem_allocator_t *scope, const struct tcpheader *tcph)
+{
+ static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR", "NS" };
+ const int maxlength = 64; /* upper bounds, max 53B: 8 * 3 + 2 + strlen("Reserved") + 9 * 2 + 1 */
+
+ char *pbuf;
+ const char *buf;
+
+ int i;
+
+ buf = pbuf = (char *) wmem_alloc(scope, maxlength);
+ *pbuf = '\0';
+
+ for (i = 0; i < 9; i++) {
+ if (tcph->th_flags & (1 << i)) {
+ if (buf[0])
+ pbuf = g_stpcpy(pbuf, ", ");
+ pbuf = g_stpcpy(pbuf, flags[i]);
+ }
+ }
+
+ if (tcph->th_flags & TH_RES) {
+ if (buf[0])
+ pbuf = g_stpcpy(pbuf, ", ");
+ g_stpcpy(pbuf, "Reserved");
+ }
+
+ if (buf[0] == '\0')
+ buf = "<None>";
+
+ return buf;
+}
+static const char *
+tcp_flags_to_str_first_letter(const struct tcpheader *tcph)
+{
+ wmem_strbuf_t *buf = wmem_strbuf_new(wmem_packet_scope(), "");
+ unsigned i;
+ const unsigned flags_count = 12;
+ const char first_letters[] = "RRRNCEUAPRSF";
+
+ /* upper three bytes are marked as reserved ('R'). */
+ for (i = 0; i < flags_count; i++) {
+ if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) {
+ wmem_strbuf_append_c(buf, first_letters[i]);
+ } else {
+ wmem_strbuf_append(buf, UTF8_MIDDLE_DOT);
+ }
+ }
+
+ return wmem_strbuf_finalize(buf);
+}
+
static void
tcp_src_prompt(packet_info *pinfo, gchar *result)
{
@@ -806,6 +861,59 @@ tcp_build_filter(packet_info *pinfo)
return NULL;
}
+/****************************************************************************/
+/* whenever a TCP packet is seen by the tap listener */
+/* Add a new tcp frame into the graph */
+static gboolean
+tcp_seq_analysis_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info)
+{
+ seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
+ const struct tcpheader *tcph = (const struct tcpheader *)tcp_info;
+
+ if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){
+ const char* flags;
+ seq_analysis_item_t *sai;
+
+ sai = g_new0(seq_analysis_item_t, 1);
+ sai->frame_number = pinfo->num;
+ if (sainfo->any_addr) {
+ copy_address(&(sai->src_addr),&(pinfo->net_src));
+ copy_address(&(sai->dst_addr),&(pinfo->net_dst));
+ } else {
+ copy_address(&(sai->src_addr),&(pinfo->src));
+ copy_address(&(sai->dst_addr),&(pinfo->dst));
+ }
+ sai->port_src=pinfo->srcport;
+ sai->port_dst=pinfo->destport;
+ sai->protocol=g_strdup(port_type_to_str(pinfo->ptype));
+
+ flags = tcp_flags_to_str(NULL, tcph);
+
+ if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){
+ sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen);
+ }
+ else{
+ sai->frame_label = g_strdup(flags);
+ }
+
+ wmem_free(NULL, (void*)flags);
+
+ if (tcph->th_flags & TH_ACK)
+ sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack);
+ else
+ sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq);
+
+ sai->line_style = 1;
+ sai->conv_num = (guint16) tcph->th_stream;
+ sai->display = TRUE;
+
+ g_queue_push_tail(sainfo->items, sai);
+ }
+
+ return TRUE;
+}
+
+
gchar* tcp_follow_conv_filter(packet_info* pinfo, int* stream)
{
conversation_t *conv;
@@ -5603,59 +5711,6 @@ dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 seq,
}
}
-static const char *
-tcp_flags_to_str(const struct tcpheader *tcph)
-{
- static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR", "NS" };
- const int maxlength = 64; /* upper bounds, max 53B: 8 * 3 + 2 + strlen("Reserved") + 9 * 2 + 1 */
-
- char *pbuf;
- const char *buf;
-
- int i;
-
- buf = pbuf = (char *) wmem_alloc(wmem_packet_scope(), maxlength);
- *pbuf = '\0';
-
- for (i = 0; i < 9; i++) {
- if (tcph->th_flags & (1 << i)) {
- if (buf[0])
- pbuf = g_stpcpy(pbuf, ", ");
- pbuf = g_stpcpy(pbuf, flags[i]);
- }
- }
-
- if (tcph->th_flags & TH_RES) {
- if (buf[0])
- pbuf = g_stpcpy(pbuf, ", ");
- g_stpcpy(pbuf, "Reserved");
- }
-
- if (buf[0] == '\0')
- buf = "<None>";
-
- return buf;
-}
-static const char *
-tcp_flags_to_str_first_letter(const struct tcpheader *tcph)
-{
- wmem_strbuf_t *buf = wmem_strbuf_new(wmem_packet_scope(), "");
- unsigned i;
- const unsigned flags_count = 12;
- const char first_letters[] = "RRRNCEUAPRSF";
-
- /* upper three bytes are marked as reserved ('R'). */
- for (i = 0; i < flags_count; i++) {
- if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) {
- wmem_strbuf_append_c(buf, first_letters[i]);
- } else {
- wmem_strbuf_append(buf, UTF8_MIDDLE_DOT);
- }
- }
-
- return wmem_strbuf_finalize(buf);
-}
-
static gboolean
capture_tcp(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header)
{
@@ -5950,7 +6005,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
} else
tcph->th_have_seglen = FALSE;
- flags_str = tcp_flags_to_str(tcph);
+ flags_str = tcp_flags_to_str(wmem_packet_scope(), tcph);
flags_str_first_letter = tcp_flags_to_str_first_letter(tcph);
col_append_lstr(pinfo->cinfo, COL_INFO,
@@ -7493,6 +7548,7 @@ proto_register_tcp(void)
register_conversation_table(proto_tcp, FALSE, tcpip_conversation_packet, tcpip_hostlist_packet);
register_conversation_filter("tcp", "TCP", tcp_filter_valid, tcp_build_filter);
+ register_seq_analysis("tcp", "TCP Flows", proto_tcp, NULL, 0, tcp_seq_analysis_packet);
/* considers MPTCP as a distinct protocol (even if it's a TCP option) */
proto_mptcp = proto_register_protocol("Multipath Transmission Control Protocol", "MPTCP", "mptcp");
diff --git a/epan/sequence_analysis.c b/epan/sequence_analysis.c
new file mode 100644
index 0000000000..7d8f03064f
--- /dev/null
+++ b/epan/sequence_analysis.c
@@ -0,0 +1,275 @@
+/* sequence-analysis.c
+ * Flow sequence analysis
+ *
+ * Some code from from gtk/flow_graph.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "sequence_analysis.h"
+
+#include "addr_resolv.h"
+#include "proto.h"
+#include "tap.h"
+#include "wmem/wmem.h"
+
+#define NODE_OVERFLOW MAX_NUM_NODES+1
+
+struct register_analysis {
+ const char* name; /* Name (used for lookup) */
+ const char* ui_name; /* Name used for UI */
+ int proto_id; /* protocol id (0-indexed) */
+ const char* tap_listen_str; /* string used in register_tap_listener (NULL to use protocol name) */
+ guint tap_flags;
+ tap_packet_cb analysis_func; /* function to be called for new incoming packets for sequence analysis */
+};
+
+static wmem_tree_t *registered_seq_analysis = NULL;
+
+void
+register_seq_analysis(const char* name, const char* ui_name, const int proto_id, const char* tap_listener, guint tap_flags, tap_packet_cb tap_func)
+{
+ register_analysis_t* analysis;
+
+ DISSECTOR_ASSERT(tap_func);
+
+ analysis = wmem_new0(wmem_epan_scope(), register_analysis_t);
+
+ analysis->name = name;
+ analysis->ui_name = ui_name;
+ analysis->proto_id = proto_id;
+ if (tap_listener != NULL)
+ analysis->tap_listen_str = tap_listener;
+ else
+ analysis->tap_listen_str = proto_get_protocol_filter_name(proto_id);
+ analysis->tap_flags = tap_flags;
+ analysis->analysis_func = tap_func;
+
+ if (registered_seq_analysis == NULL)
+ registered_seq_analysis = wmem_tree_new(wmem_epan_scope());
+
+ wmem_tree_insert_string(registered_seq_analysis, name, analysis, 0);
+}
+
+const char* sequence_analysis_get_name(register_analysis_t* analysis)
+{
+ return analysis->name;
+}
+
+const char* sequence_analysis_get_ui_name(register_analysis_t* analysis)
+{
+ return analysis->ui_name;
+}
+
+const char* sequence_analysis_get_tap_listener_name(register_analysis_t* analysis)
+{
+ return analysis->tap_listen_str;
+}
+
+tap_packet_cb sequence_analysis_get_packet_func(register_analysis_t* analysis)
+{
+ return analysis->analysis_func;
+}
+
+guint sequence_analysis_get_tap_flags(register_analysis_t* analysis)
+{
+ return analysis->tap_flags;
+}
+
+
+register_analysis_t* sequence_analysis_find_by_name(const char* name)
+{
+ return (register_analysis_t*)wmem_tree_lookup_string(registered_seq_analysis, name, 0);
+}
+
+void sequence_analysis_table_iterate_tables(wmem_foreach_func func, gpointer user_data)
+{
+ wmem_tree_foreach(registered_seq_analysis, func, user_data);
+}
+
+seq_analysis_info_t *
+sequence_analysis_info_new(void)
+{
+ seq_analysis_info_t *sainfo = g_new0(seq_analysis_info_t, 1);
+
+ /* SEQ_ANALYSIS_DEBUG("adding new item"); */
+ sainfo->items = g_queue_new();
+ sainfo->ht= g_hash_table_new(g_int_hash, g_int_equal);
+ return sainfo;
+}
+
+void sequence_analysis_info_free(seq_analysis_info_t *sainfo)
+{
+ if (!sainfo) return;
+
+ /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
+ sequence_analysis_list_free(sainfo);
+
+ g_queue_free(sainfo->items);
+ g_hash_table_destroy(sainfo->ht);
+
+ g_free(sainfo);
+}
+
+static void sequence_analysis_item_free(gpointer data)
+{
+ seq_analysis_item_t *seq_item = (seq_analysis_item_t *)data;
+ g_free(seq_item->frame_label);
+ g_free(seq_item->time_str);
+ g_free(seq_item->comment);
+ g_free(seq_item->protocol);
+ free_address(&seq_item->src_addr);
+ free_address(&seq_item->dst_addr);
+ g_free(data);
+}
+
+
+/* compare two list entries by packet no */
+static gint
+sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
+{
+ const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a;
+ const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b;
+
+ if(entry_a->frame_number < entry_b->frame_number)
+ return -1;
+
+ if(entry_a->frame_number > entry_b->frame_number)
+ return 1;
+
+ return 0;
+}
+
+
+void
+sequence_analysis_list_sort(seq_analysis_info_t *sainfo)
+{
+ if (!sainfo) return;
+ g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL);
+}
+
+void
+sequence_analysis_list_free(seq_analysis_info_t *sainfo)
+{
+ if (!sainfo) return;
+ /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
+
+ /* free the graph data items */
+
+#if GLIB_CHECK_VERSION (2, 32, 0)
+ g_queue_free_full(sainfo->items, sequence_analysis_item_free);
+ sainfo->items = g_queue_new();
+#else
+ {
+ GList *list = g_queue_peek_nth_link(sainfo->items, 0);
+ while (list)
+ {
+ sequence_analysis_item_free(list->data);
+ list = g_list_next(list);
+ }
+ g_queue_clear(sainfo->items);
+ }
+#endif
+
+ if (NULL != sainfo->ht) {
+ g_hash_table_remove_all(sainfo->ht);
+ }
+ sainfo->nconv = 0;
+
+ sequence_analysis_free_nodes(sainfo);
+}
+
+/* Return the index array if the node is in the array. Return -1 if there is room in the array
+ * and Return -2 if the array is full
+ */
+/****************************************************************************/
+static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
+ guint i;
+
+ if (node->type == AT_NONE) return NODE_OVERFLOW;
+
+ for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) {
+ if ( cmp_address(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */
+ }
+
+ if (i >= MAX_NUM_NODES) {
+ return NODE_OVERFLOW;
+ } else {
+ sainfo->num_nodes++;
+ copy_address(&(sainfo->nodes[i]), node);
+ return i;
+ }
+}
+
+struct sainfo_counter {
+ seq_analysis_info_t *sainfo;
+ int num_items;
+};
+
+static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_data)
+{
+ seq_analysis_item_t *gai = (seq_analysis_item_t *)data;
+ struct sainfo_counter *sc = (struct sainfo_counter *)user_data;
+ if (gai->display) {
+ (sc->num_items)++;
+ gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr));
+ gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr));
+ }
+}
+
+/* Get the nodes from the list */
+/****************************************************************************/
+int
+sequence_analysis_get_nodes(seq_analysis_info_t *sainfo)
+{
+ struct sainfo_counter sc = {sainfo, 0};
+
+ /* Fill the node array */
+ g_queue_foreach(sainfo->items, sequence_analysis_get_nodes_item_proc, &sc);
+
+ return sc.num_items;
+}
+
+/* Free the node address list */
+/****************************************************************************/
+void
+sequence_analysis_free_nodes(seq_analysis_info_t *sainfo)
+{
+ int i;
+
+ for (i=0; i<MAX_NUM_NODES; i++) {
+ free_address(&sainfo->nodes[i]);
+ }
+ sainfo->num_nodes = 0;
+}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/epan/sequence_analysis.h b/epan/sequence_analysis.h
new file mode 100644
index 0000000000..bcebdef3a5
--- /dev/null
+++ b/epan/sequence_analysis.h
@@ -0,0 +1,196 @@
+/* sequence-analysis.h
+ * Flow sequence analysis
+ *
+ * Copied from gtk/graph_analysis.h
+ *
+ * Copyright 2004, Verso Technologies Inc.
+ * By Alejandro Vaquero <alejandrovaquero@yahoo.com>
+ *
+ * based on rtp_analysis.c and io_stat
+ *
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __EPAN_SEQUENCE_ANALYSIS_H__
+#define __EPAN_SEQUENCE_ANALYSIS_H__
+
+#include "ws_symbol_export.h"
+
+#include <glib.h>
+
+#include "packet_info.h"
+#include "tap.h"
+#include "address.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define MAX_NUM_NODES 40
+
+/** defines an entry for the graph analysis */
+typedef struct _seq_analysis_item {
+ guint32 frame_number;
+ address src_addr;
+ guint16 port_src;
+ address dst_addr;
+ guint16 port_dst;
+ gchar *frame_label; /**< the label on top of the arrow */
+ gchar *time_str; /**< timestamp */
+ gchar *comment; /**< a comment that appears at the right of the graph */
+ guint16 conv_num; /**< The conversation number. Used for coloring VoIP calls. */
+ unsigned fg_color; /**< Foreground color, 0xRRGGBB. Qt only. */
+ unsigned bg_color; /**< Background color, 0xRRGGBB. Qt only. */
+ gboolean has_color_filter; /**< Set if packet has color filter. Qt only. */
+ gboolean display; /**< indicate if the packet is displayed or not in the graph */
+ guint src_node; /**< this is used by graph_analysis.c to identify the node */
+ guint dst_node; /**< a node is an IP address that will be displayed in columns */
+ guint16 line_style; /**< the arrow line width in pixels*/
+ gchar *protocol; /**< the label of the protocol defined in the IP packet */
+} seq_analysis_item_t;
+
+/** defines the graph analysis structure */
+typedef struct _seq_analysis_info {
+ const char* name; /**< Name of sequence analysis */
+ gboolean all_packets; /**< all packets vs only displayed */
+ gboolean any_addr; /**< any addr (DL+net) vs net-only */
+ int nconv; /**< number of conversations in the list */
+ GQueue* items; /**< list of seq_analysis_info_t */
+ GHashTable *ht; /**< hash table of seq_analysis_info_t */
+ address nodes[MAX_NUM_NODES]; /**< horizontal node list */
+ guint32 num_nodes; /**< actual number of nodes */
+} seq_analysis_info_t;
+
+/** Structure for information about a registered sequence analysis function */
+typedef struct register_analysis register_analysis_t;
+
+#if 0
+#define SEQ_ANALYSIS_DEBUG(...) { \
+ char *SEQ_ANALYSIS_DEBUG_MSG = g_strdup_printf(__VA_ARGS__); \
+ g_warning("sequence analysis: %s:%d %s", G_STRFUNC, __LINE__, SEQ_ANALYSIS_DEBUG_MSG); \
+ g_free(SEQ_ANALYSIS_DEBUG_MSG); \
+}
+#else
+#define SEQ_ANALYSIS_DEBUG()
+#endif
+
+WS_DLL_PUBLIC void register_seq_analysis(const char* name, const char* ui_name, const int proto_id, const char* tap_listener, guint tap_flags, tap_packet_cb tap_func);
+
+/** Helper function to get sequence analysis name
+ *
+ * @param analysis Registered sequence analysis
+ * @return sequence analysis name string
+ */
+WS_DLL_PUBLIC const char* sequence_analysis_get_name(register_analysis_t* analysis);
+
+/** Helper function to get tap listener name
+ *
+ * @param analysis Registered sequence analysis
+ * @return sequence analysis tap listener string
+ */
+WS_DLL_PUBLIC const char* sequence_analysis_get_tap_listener_name(register_analysis_t* analysis);
+
+/** Helper function to get UI name
+ *
+ * @param analysis Registered sequence analysis
+ * @return sequence analysis UI string
+ */
+WS_DLL_PUBLIC const char* sequence_analysis_get_ui_name(register_analysis_t* analysis);
+
+/** Get tap function handler from sequence analysis
+ *
+ * @param analysis Registered sequence analysis
+ * @return tap function handler of sequence analysis
+ */
+WS_DLL_PUBLIC tap_packet_cb sequence_analysis_get_packet_func(register_analysis_t* analysis);
+
+/** Helper function to get tap flags
+ *
+ * @param analysis Registered sequence analysis
+ * @return sequence analysis tap flags
+ */
+WS_DLL_PUBLIC guint sequence_analysis_get_tap_flags(register_analysis_t* analysis);
+
+/** Find a registered sequence analysis "protocol" by name
+ *
+ * @param name Registered sequence analysis to find
+ * @return registered sequence analysis, NULL if not found
+ */
+WS_DLL_PUBLIC register_analysis_t* sequence_analysis_find_by_name(const char* name);
+
+/** Interator to walk sequence_analysis tables and execute func
+ *
+ * @param func action to be performed on all sequence_analysis tables
+ * @param user_data any data needed to help perform function
+ */
+WS_DLL_PUBLIC void sequence_analysis_table_iterate_tables(wmem_foreach_func func, gpointer user_data);
+
+/** Create and initialize a seq_analysis_info_t struct
+ * @return A pointer to a newly allocated seq_analysis_info_t struct.
+ */
+WS_DLL_PUBLIC seq_analysis_info_t *sequence_analysis_info_new(void);
+
+/** Free a seq_analysis_info_t struct.
+ * @param sainfo A pointer to the seq_analysis_info_t struct to be freed.
+ */
+WS_DLL_PUBLIC void sequence_analysis_info_free(seq_analysis_info_t * sainfo);
+
+/** Sort a seq_analysis_info_t struct.
+ * @param sainfo A pointer to the seq_analysis_info_t struct to be sorted
+ */
+WS_DLL_PUBLIC void sequence_analysis_list_sort(seq_analysis_info_t *sainfo);
+
+/** Free the segment list
+ *
+ * @param sainfo Sequence analysis information.
+ */
+WS_DLL_PUBLIC void sequence_analysis_list_free(seq_analysis_info_t *sainfo);
+
+/** Fill in the node address list
+ *
+ * @param sainfo Sequence analysis information.
+ * @return The number of transaction items (not nodes) processed.
+ */
+WS_DLL_PUBLIC int sequence_analysis_get_nodes(seq_analysis_info_t *sainfo);
+
+/** Free the node address list
+ *
+ * @param sainfo Sequence analysis information.
+ */
+WS_DLL_PUBLIC void sequence_analysis_free_nodes(seq_analysis_info_t *sainfo);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __EPAN_SEQUENCE_ANALYSIS_H__ */
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/gtk/flow_graph.c b/ui/gtk/flow_graph.c
index 75680c0009..5475be457b 100644
--- a/ui/gtk/flow_graph.c
+++ b/ui/gtk/flow_graph.c
@@ -47,17 +47,16 @@ static GtkWidget *flow_graph_dlg = NULL;
static GtkWidget *select_all_rb;
static GtkWidget *select_displayed_rb;
-static GtkWidget *select_general_rb;
-static GtkWidget *select_tcp_rb;
static GtkWidget *src_dst_rb;
static GtkWidget *net_src_dst_rb;
+static GtkWidget *select_analysis_combo;
/****************************************************************************/
static void
flow_graph_data_init(void) {
graph_analysis = sequence_analysis_info_new();
- graph_analysis->type = SEQ_ANALYSIS_ANY;
+ graph_analysis->name = "any";
graph_analysis->all_packets = TRUE;
}
@@ -82,44 +81,47 @@ flow_graph_on_destroy(GObject *object _U_, gpointer user_data _U_)
flow_graph_dlg = NULL;
}
-
-/****************************************************************************/
-static void
-toggle_select_all(GtkWidget *widget _U_, gpointer user_data _U_)
+static gboolean
+find_seq_name(const void *key, void *value, void *userdata)
{
- /* is the button now active? */
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_all_rb))) {
- graph_analysis->all_packets = TRUE;
+ const char* name = (const char*)key;
+ register_analysis_t* analysis = (register_analysis_t*)value;
+ const char* ui_name = (const char*)userdata;
+
+ if (strcmp(ui_name, sequence_analysis_get_ui_name(analysis)) == 0)
+ {
+ graph_analysis->name = name;
+ return TRUE;
}
+
+ return FALSE;
}
-/****************************************************************************/
static void
-toggle_select_displayed(GtkWidget *widget _U_, gpointer user_data _U_)
+sequence_combo_box_changed_cb(GtkComboBox *combo_box, gpointer user_data _U_)
{
- /* is the button now active? */
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_displayed_rb))) {
- graph_analysis->all_packets = FALSE;
- }
+ gchar* ui_name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box));
+
+ sequence_analysis_table_iterate_tables(find_seq_name, ui_name);
}
/****************************************************************************/
static void
-toggle_select_general(GtkWidget *widget _U_, gpointer user_data _U_)
+toggle_select_all(GtkWidget *widget _U_, gpointer user_data _U_)
{
/* is the button now active? */
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_general_rb))) {
- graph_analysis->type = SEQ_ANALYSIS_ANY;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_all_rb))) {
+ graph_analysis->all_packets = TRUE;
}
}
/****************************************************************************/
static void
-toggle_select_tcp(GtkWidget *widget _U_, gpointer user_data _U_)
+toggle_select_displayed(GtkWidget *widget _U_, gpointer user_data _U_)
{
/* is the button now active? */
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_tcp_rb))) {
- graph_analysis->type = SEQ_ANALYSIS_TCP;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_displayed_rb))) {
+ graph_analysis->all_packets = FALSE;
}
}
@@ -184,6 +186,16 @@ flow_graph_on_delete(GtkButton *button _U_,
/****************************************************************************/
/* INTERFACE */
/****************************************************************************/
+static gboolean
+add_flow_sequence_item(const void *key _U_, void *value, void *userdata)
+{
+ register_analysis_t* analysis = (register_analysis_t*)value;
+ GtkWidget* combo_box = (GtkWidget*)userdata;
+
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), sequence_analysis_get_ui_name(analysis));
+ return FALSE;
+}
+
static void
flow_graph_dlg_create(void)
@@ -230,7 +242,7 @@ flow_graph_dlg_create(void)
if (graph_analysis->all_packets) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_all_rb),TRUE);
}
- gtk_widget_show(select_all_rb);
+ gtk_widget_show(select_all_rb);
/* Process displayed packets */
select_displayed_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(select_all_rb),
@@ -255,28 +267,14 @@ flow_graph_dlg_create(void)
gtk_container_set_border_width(GTK_CONTAINER(flow_type_grid), 5);
gtk_container_add(GTK_CONTAINER(flow_type_fr), flow_type_grid);
- /* General information */
- select_general_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_General flow");
- gtk_widget_set_tooltip_text (select_general_rb, ("Show all packets, with general information"));
- g_signal_connect(select_general_rb, "toggled", G_CALLBACK(toggle_select_general), NULL);
- ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_general_rb, 0, 0, 1, 1,
- (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
- if (graph_analysis->type == SEQ_ANALYSIS_ANY) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_general_rb),TRUE);
- }
- gtk_widget_show(select_general_rb);
-
- /* TCP specific information */
- select_tcp_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(select_general_rb),
- "_TCP flow");
- gtk_widget_set_tooltip_text (select_tcp_rb, ("Show only TCP packets, with TCP specific information"));
- g_signal_connect(select_tcp_rb, "toggled", G_CALLBACK(toggle_select_tcp), NULL);
- ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_tcp_rb, 0, 1, 1, 1,
- (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
- if (graph_analysis->type == SEQ_ANALYSIS_TCP) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_tcp_rb),TRUE);
- }
- gtk_widget_show(select_tcp_rb);
+ select_analysis_combo = gtk_combo_box_text_new();
+ g_signal_connect(select_analysis_combo, "changed", G_CALLBACK(sequence_combo_box_changed_cb), NULL);
+ sequence_analysis_table_iterate_tables(add_flow_sequence_item, select_analysis_combo);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(select_analysis_combo), 0);
+
+ ws_gtk_grid_attach_extended(GTK_GRID(flow_type_grid), select_analysis_combo, 0, 0, 1, 1,
+ (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
+ gtk_widget_show(select_analysis_combo);
gtk_widget_show(flow_type_grid);
gtk_widget_show(flow_type_fr);
diff --git a/ui/gtk/lbm_uimflow_dlg.c b/ui/gtk/lbm_uimflow_dlg.c
index 61ea3eb5ea..0a5f1fbd4c 100644
--- a/ui/gtk/lbm_uimflow_dlg.c
+++ b/ui/gtk/lbm_uimflow_dlg.c
@@ -58,7 +58,7 @@ static lbm_uimflow_dialog_t dialog_data = { FALSE, -1, NULL, NULL, NULL, select_
static void lbmc_uim_flow_graph_data_init(void)
{
dialog_data.graph_analysis = sequence_analysis_info_new();
- dialog_data.graph_analysis->type = SEQ_ANALYSIS_ANY;
+ dialog_data.graph_analysis->name = "any";
dialog_data.graph_analysis->all_packets = TRUE;
dialog_data.graph_analysis->any_addr = TRUE;
}
diff --git a/ui/qt/sequence_diagram.cpp b/ui/qt/sequence_diagram.cpp
index 0dd52c59b1..98071b18a6 100644
--- a/ui/qt/sequence_diagram.cpp
+++ b/ui/qt/sequence_diagram.cpp
@@ -263,7 +263,7 @@ void SequenceDiagram::draw(QCPPainter *painter)
fg_pen.setColor(sel_pal.color(QPalette::HighlightedText));
bg_color = sel_pal.color(QPalette::Highlight);
selected_key_ = cur_key;
- } else if (sainfo_->type == SEQ_ANALYSIS_ANY) {
+ } else if (strcmp(sainfo_->name, "any") == 0) {
if (sai->has_color_filter) {
fg_pen.setColor(QColor().fromRgb(sai->fg_color));
bg_color = QColor().fromRgb(sai->bg_color);
diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp
index 0d058fe556..786a73076d 100644
--- a/ui/qt/sequence_dialog.cpp
+++ b/ui/qt/sequence_dialog.cpp
@@ -33,6 +33,7 @@
#include <ui/qt/utils/qt_ui_utils.h>
#include "sequence_diagram.h"
#include "wireshark_application.h"
+#include <ui/qt/utils/variant_pointer.h>
#include <QDir>
#include <QFileDialog>
@@ -65,6 +66,12 @@
static const double min_top_ = -1.0;
static const double min_left_ = -0.5;
+typedef struct {
+ int curr_index;
+ QComboBox *flow;
+ SequenceInfo *info;
+} sequence_items_t;
+
SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *info) :
WiresharkDialog(parent, cf),
ui(new Ui::SequenceDialog),
@@ -80,7 +87,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i
if (!info_) {
info_ = new SequenceInfo(sequence_analysis_info_new());
- info_->sainfo()->type = SEQ_ANALYSIS_ANY;
+ info_->sainfo()->name = "any";
info_->sainfo()->all_packets = TRUE;
} else {
info_->ref();
@@ -153,13 +160,16 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i
ui->showComboBox->setCurrentIndex(0);
ui->addressComboBox->setCurrentIndex(0);
- QComboBox *fcb = ui->flowComboBox;
- fcb->addItem(ui->actionFlowAny->text(), SEQ_ANALYSIS_ANY);
- fcb->addItem(ui->actionFlowTcp->text(), SEQ_ANALYSIS_TCP);
+ sequence_items_t item_data;
+
+ item_data.curr_index = 0;
+ item_data.flow = ui->flowComboBox;
+ item_data.info = info_;
- ui->flowComboBox->setCurrentIndex(info_->sainfo()->type);
+ //Add all registered analysis to combo box
+ sequence_analysis_table_iterate_tables(addFlowSequenceItem, &item_data);
- if (info_->sainfo()->type == SEQ_ANALYSIS_VOIP) {
+ if (strcmp(info_->sainfo()->name, "voip") == 0) {
ui->flowComboBox->blockSignals(true);
ui->controlFrame->hide();
}
@@ -405,7 +415,7 @@ void SequenceDialog::fillDiagram()
QCustomPlot *sp = ui->sequencePlot;
- if (info_->sainfo()->type == SEQ_ANALYSIS_VOIP) {
+ if (strcmp(info_->sainfo()->name, "voip") == 0) {
seq_diagram_->setData(info_->sainfo());
} else {
seq_diagram_->clearData();
@@ -587,9 +597,12 @@ void SequenceDialog::on_showComboBox_activated(int index)
void SequenceDialog::on_flowComboBox_activated(int index)
{
- if (!info_->sainfo() || info_->sainfo()->type == SEQ_ANALYSIS_VOIP || index < 0) return;
+ if (!info_->sainfo() || (strcmp(info_->sainfo()->name, "voip") == 0) || index < 0)
+ return;
+
+ register_analysis_t* analysis = VariantPointer<register_analysis_t>::asPtr(ui->flowComboBox->itemData(index));
+ info_->sainfo()->name = sequence_analysis_get_name(analysis);
- info_->sainfo()->type = static_cast<seq_analysis_type>(ui->flowComboBox->itemData(index).toInt());
fillDiagram();
}
@@ -673,6 +686,27 @@ void SequenceDialog::zoomXAxis(bool in)
sp->replot();
}
+gboolean SequenceDialog::addFlowSequenceItem(const void* key, void *value, void *userdata)
+{
+ const char* name = (const char*)key;
+ register_analysis_t* analysis = (register_analysis_t*)value;
+ sequence_items_t* item_data = (sequence_items_t*)userdata;
+
+ /* XXX - Although "voip" isn't a registered name yet, it appears to have special
+ handling that will be done outside of registered data */
+ if (strcmp(name, "voip") == 0)
+ return FALSE;
+
+ item_data->flow->addItem(sequence_analysis_get_ui_name(analysis), VariantPointer<register_analysis_t>::asQVariant(analysis));
+
+ if (item_data->flow->itemData(item_data->curr_index).toString().compare(item_data->info->sainfo()->name) == 0)
+ item_data->flow->setCurrentIndex(item_data->curr_index);
+
+ item_data->curr_index++;
+
+ return FALSE;
+}
+
SequenceInfo::SequenceInfo(seq_analysis_info_t *sainfo) :
sainfo_(sainfo),
count_(1)
diff --git a/ui/qt/sequence_dialog.h b/ui/qt/sequence_dialog.h
index e6f0afef11..110e1f948e 100644
--- a/ui/qt/sequence_dialog.h
+++ b/ui/qt/sequence_dialog.h
@@ -117,6 +117,8 @@ private:
void panAxes(int x_pixels, int y_pixels);
void resetAxes(bool keep_lower = false);
void goToAdjacentPacket(bool next);
+
+ static gboolean addFlowSequenceItem(const void *key, void *value, void *userdata);
};
#endif // SEQUENCE_DIALOG_H
diff --git a/ui/qt/voip_calls_dialog.cpp b/ui/qt/voip_calls_dialog.cpp
index ef7ce35760..2016c01eaa 100644
--- a/ui/qt/voip_calls_dialog.cpp
+++ b/ui/qt/voip_calls_dialog.cpp
@@ -103,7 +103,7 @@ VoipCallsDialog::VoipCallsDialog(QWidget &parent, CaptureFile &cf, bool all_flow
tapinfo_.h225_cstype = H225_OTHER;
tapinfo_.fs_option = all_flows ? FLOW_ALL : FLOW_ONLY_INVITES; /* flow show option */
tapinfo_.graph_analysis = sequence_analysis_info_new();
- tapinfo_.graph_analysis->type = SEQ_ANALYSIS_VOIP;
+ tapinfo_.graph_analysis->name = "voip";
sequence_info_ = new SequenceInfo(tapinfo_.graph_analysis);
voip_calls_init_all_taps(&tapinfo_);
diff --git a/ui/tap-sequence-analysis.c b/ui/tap-sequence-analysis.c
index eda3b049f8..2ec1fc8333 100644
--- a/ui/tap-sequence-analysis.c
+++ b/ui/tap-sequence-analysis.c
@@ -29,19 +29,13 @@
#include "tap-sequence-analysis.h"
#include "epan/addr_resolv.h"
-#include "epan/color_filters.h"
#include "epan/packet.h"
#include "epan/tap.h"
-#include "epan/proto_data.h"
-#include "epan/dissectors/packet-tcp.h"
-#include "epan/dissectors/packet-icmp.h"
#include "ui/alert_box.h"
#include <wsutil/file_util.h>
-#define NODE_OVERFLOW MAX_NUM_NODES+1
-
#define NODE_CHARS_WIDTH 20
#define CONV_TIME_HEADER "Conv.| Time "
#define TIME_HEADER "|Time "
@@ -50,210 +44,6 @@
#define CONV_TIME_HEADER_LENGTH 16
#define TIME_HEADER_LENGTH 10
-seq_analysis_info_t *
-sequence_analysis_info_new(void)
-{
- seq_analysis_info_t *sainfo = g_new0(seq_analysis_info_t, 1);
-
- /* SEQ_ANALYSIS_DEBUG("adding new item"); */
- sainfo->items = g_queue_new();
- sainfo->ht= g_hash_table_new(g_int_hash, g_int_equal);
- return sainfo;
-}
-
-void sequence_analysis_info_free(seq_analysis_info_t *sainfo)
-{
- if (!sainfo) return;
-
- /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
- sequence_analysis_list_free(sainfo);
-
- g_queue_free(sainfo->items);
- g_hash_table_destroy(sainfo->ht);
-
- g_free(sainfo);
-}
-
-/****************************************************************************/
-/* whenever a frame packet is seen by the tap listener */
-/* Add a new frame into the graph */
-static gboolean
-seq_analysis_frame_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_)
-{
- seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
- col_item_t* col_item;
-
- if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){
- int i;
- gchar *protocol = NULL;
- gchar *colinfo = NULL;
- seq_analysis_item_t *sai = NULL;
- icmp_info_t *p_icmp_info;
-
- if (sainfo->any_addr) {
- if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) {
- sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
- copy_address(&(sai->src_addr),&(pinfo->net_src));
- copy_address(&(sai->dst_addr),&(pinfo->net_dst));
- }
-
- } else {
- if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) {
- sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
- copy_address(&(sai->src_addr),&(pinfo->src));
- copy_address(&(sai->dst_addr),&(pinfo->dst));
- }
- }
-
- if (!sai) return FALSE;
-
- sai->frame_number = pinfo->num;
-
- if (pinfo->fd->color_filter) {
- sai->bg_color = color_t_to_rgb(&pinfo->fd->color_filter->bg_color);
- sai->fg_color = color_t_to_rgb(&pinfo->fd->color_filter->fg_color);
- sai->has_color_filter = TRUE;
- }
-
- sai->port_src=pinfo->srcport;
- sai->port_dst=pinfo->destport;
- sai->protocol = g_strdup(port_type_to_str(pinfo->ptype));
-
- if(pinfo->cinfo) {
- if (pinfo->cinfo->col_first[COL_INFO]>=0){
-
- for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) {
- col_item = &pinfo->cinfo->columns[i];
- if (col_item->fmt_matx[COL_INFO]) {
- colinfo = g_strdup(col_item->col_data);
- /* break; ? or g_free(colinfo); before g_strdup() */
- }
- }
- }
-
- if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){
-
- for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) {
- col_item = &pinfo->cinfo->columns[i];
- if (col_item->fmt_matx[COL_PROTOCOL]) {
- protocol = g_strdup(col_item->col_data);
- /* break; ? or g_free(protocol); before g_strdup() */
- }
- }
- }
- }
-
- if (colinfo != NULL) {
- sai->frame_label = g_strdup(colinfo);
- if (protocol != NULL) {
- sai->comment = g_strdup_printf("%s: %s", protocol, colinfo);
- } else {
- sai->comment = g_strdup(colinfo);
- }
- } else {
- /* This will probably never happen...*/
- if (protocol != NULL) {
- sai->frame_label = g_strdup(protocol);
- sai->comment = g_strdup(protocol);
- }
- }
-
- if (pinfo->ptype == PT_NONE) {
- if ((p_icmp_info = (icmp_info_t *)p_get_proto_data(wmem_file_scope(),
- pinfo, proto_get_id_by_short_name("ICMP"), 0)) != NULL) {
- g_free(sai->protocol);
- sai->protocol = g_strdup("ICMP");
- sai->port_src = 0;
- sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code;
- } else if ((p_icmp_info = (icmp_info_t *)p_get_proto_data(wmem_file_scope(),
- pinfo, proto_get_id_by_short_name("ICMPv6"), 0)) != NULL) {
- g_free(sai->protocol);
- sai->protocol = g_strdup("ICMPv6");
- sai->port_src = 0;
- sai->port_dst = p_icmp_info->type * 256 + p_icmp_info->code;
- }
- }
-
- g_free(protocol);
- g_free(colinfo);
-
- sai->line_style=1;
- sai->conv_num=0;
- sai->display=TRUE;
-
- g_queue_push_tail(sainfo->items, sai);
- }
-
- return TRUE;
-}
-
-/****************************************************************************/
-/* whenever a TCP packet is seen by the tap listener */
-/* Add a new tcp frame into the graph */
-static gboolean
-seq_analysis_tcp_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info)
-{
- seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
- const struct tcpheader *tcph = (const struct tcpheader *)tcp_info;
-
- if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){
- /* copied from packet-tcp */
- static const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" };
- guint i, bpos;
- gboolean flags_found = FALSE;
- gchar flags[64];
- seq_analysis_item_t *sai;
-
- sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
- sai->frame_number = pinfo->num;
- if (sainfo->any_addr) {
- copy_address(&(sai->src_addr),&(pinfo->net_src));
- copy_address(&(sai->dst_addr),&(pinfo->net_dst));
- } else {
- copy_address(&(sai->src_addr),&(pinfo->src));
- copy_address(&(sai->dst_addr),&(pinfo->dst));
- }
- sai->port_src=pinfo->srcport;
- sai->port_dst=pinfo->destport;
- sai->protocol=g_strdup(port_type_to_str(pinfo->ptype));
-
- flags[0] = '\0';
- for (i = 0; i < 8; i++) {
- bpos = 1 << i;
- if (tcph->th_flags & bpos) {
- if (flags_found) {
- g_strlcat(flags, ", ", sizeof(flags));
- }
- g_strlcat(flags, fstr[i], sizeof(flags));
- flags_found = TRUE;
- }
- }
- if (flags[0] == '\0') {
- g_snprintf (flags, sizeof(flags), "<None>");
- }
-
- if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){
- sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen);
- }
- else{
- sai->frame_label = g_strdup(flags);
- }
-
- if (tcph->th_flags & TH_ACK)
- sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack);
- else
- sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq);
-
- sai->line_style = 1;
- sai->conv_num = (guint16) tcph->th_stream;
- sai->display = TRUE;
-
- g_queue_push_tail(sainfo->items, sai);
- }
-
- return TRUE;
-}
-
static void sequence_analysis_item_set_timestamp(gpointer data, gpointer user_data)
{
gchar time_str[COL_MAX_LEN];
@@ -267,29 +57,17 @@ static void sequence_analysis_item_set_timestamp(gpointer data, gpointer user_da
void
sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo)
{
- if (!cf || !sainfo) return;
-
- switch (sainfo->type) {
- case SEQ_ANALYSIS_ANY:
- register_tap_listener("frame", sainfo, NULL,
- TL_REQUIRES_COLUMNS,
- NULL,
- seq_analysis_frame_packet,
- NULL
- );
- break;
- case SEQ_ANALYSIS_TCP:
- register_tap_listener("tcp", sainfo, NULL,
- 0,
- NULL,
- seq_analysis_tcp_packet,
- NULL
- );
- break;
- case SEQ_ANALYSIS_VOIP:
- default:
+ register_analysis_t* analysis = NULL;
+
+ if (!cf || !sainfo)
return;
- }
+
+ analysis = sequence_analysis_find_by_name(sainfo->name);
+ if (analysis == NULL)
+ return;
+
+ register_tap_listener(sequence_analysis_get_tap_listener_name(analysis), sainfo, NULL, sequence_analysis_get_tap_flags(analysis),
+ NULL, sequence_analysis_get_packet_func(analysis), NULL);
cf_retap_packets(cf);
remove_tap_listener(sainfo);
@@ -299,74 +77,6 @@ sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo)
g_queue_foreach(sainfo->items, sequence_analysis_item_set_timestamp, cf);
}
-static void sequence_analysis_item_free(gpointer data)
-{
- seq_analysis_item_t *seq_item = (seq_analysis_item_t *)data;
- g_free(seq_item->frame_label);
- g_free(seq_item->time_str);
- g_free(seq_item->comment);
- g_free(seq_item->protocol);
- free_address(&seq_item->src_addr);
- free_address(&seq_item->dst_addr);
- g_free(data);
-}
-
-
-/* compare two list entries by packet no */
-static gint
-sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
-{
- const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a;
- const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b;
-
- if(entry_a->frame_number < entry_b->frame_number)
- return -1;
-
- if(entry_a->frame_number > entry_b->frame_number)
- return 1;
-
- return 0;
-}
-
-
-void
-sequence_analysis_list_sort(seq_analysis_info_t *sainfo)
-{
- if (!sainfo) return;
- g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL);
-}
-
-void
-sequence_analysis_list_free(seq_analysis_info_t *sainfo)
-{
- if (!sainfo) return;
- /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
-
- /* free the graph data items */
-
-#if GLIB_CHECK_VERSION (2, 32, 0)
- g_queue_free_full(sainfo->items, sequence_analysis_item_free);
- sainfo->items = g_queue_new();
-#else
- {
- GList *list = g_queue_peek_nth_link(sainfo->items, 0);
- while (list)
- {
- sequence_analysis_item_free(list->data);
- list = g_list_next(list);
- }
- g_queue_clear(sainfo->items);
- }
-#endif
-
- if (NULL != sainfo->ht) {
- g_hash_table_remove_all(sainfo->ht);
- }
- sainfo->nconv = 0;
-
- sequence_analysis_free_nodes(sainfo);
-}
-
/****************************************************************************/
/* Adds trailing characters to complete the requested length. */
/****************************************************************************/
@@ -427,70 +137,6 @@ static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32
g_free(ins_str);
}
-/* Return the index array if the node is in the array. Return -1 if there is room in the array
- * and Return -2 if the array is full
- */
-/****************************************************************************/
-static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
- guint i;
-
- if (node->type == AT_NONE) return NODE_OVERFLOW;
-
- for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) {
- if ( cmp_address(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */
- }
-
- if (i >= MAX_NUM_NODES) {
- return NODE_OVERFLOW;
- } else {
- sainfo->num_nodes++;
- copy_address(&(sainfo->nodes[i]), node);
- return i;
- }
-}
-
-struct sainfo_counter {
- seq_analysis_info_t *sainfo;
- int num_items;
-};
-
-static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_data)
-{
- seq_analysis_item_t *gai = (seq_analysis_item_t *)data;
- struct sainfo_counter *sc = (struct sainfo_counter *)user_data;
- if (gai->display) {
- (sc->num_items)++;
- gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr));
- gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr));
- }
-}
-
-/* Get the nodes from the list */
-/****************************************************************************/
-int
-sequence_analysis_get_nodes(seq_analysis_info_t *sainfo)
-{
- struct sainfo_counter sc = {sainfo, 0};
-
- /* Fill the node array */
- g_queue_foreach(sainfo->items, sequence_analysis_get_nodes_item_proc, &sc);
-
- return sc.num_items;
-}
-
-/* Free the node address list */
-/****************************************************************************/
-void
-sequence_analysis_free_nodes(seq_analysis_info_t *sainfo)
-{
- int i;
-
- for (i=0; i<MAX_NUM_NODES; i++) {
- free_address(&sainfo->nodes[i]);
- }
- sainfo->num_nodes = 0;
-}
-
/****************************************************************************/
gboolean
sequence_analysis_dump_to_file(const char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node)
diff --git a/ui/tap-sequence-analysis.h b/ui/tap-sequence-analysis.h
index 39b09839f2..f6d6d3267a 100644
--- a/ui/tap-sequence-analysis.h
+++ b/ui/tap-sequence-analysis.h
@@ -36,71 +36,12 @@
#include "cfile.h"
#include "epan/address.h"
+#include <epan/sequence_analysis.h>
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-#define MAX_NUM_NODES 40
-
-typedef enum seq_analysis_type_ {
- SEQ_ANALYSIS_ANY,
- SEQ_ANALYSIS_TCP,
- SEQ_ANALYSIS_VOIP
-} seq_analysis_type;
-
-/** defines an entry for the graph analysis */
-typedef struct _seq_analysis_item {
- guint32 frame_number;
- address src_addr;
- guint16 port_src;
- address dst_addr;
- guint16 port_dst;
- gchar *frame_label; /**< the label on top of the arrow */
- gchar *time_str; /**< timestamp */
- gchar *comment; /**< a comment that appears at the right of the graph */
- guint16 conv_num; /**< The conversation number. Used for coloring VoIP calls. */
- unsigned fg_color; /**< Foreground color, 0xRRGGBB. Qt only. */
- unsigned bg_color; /**< Background color, 0xRRGGBB. Qt only. */
- gboolean has_color_filter; /**< Set if packet has color filter. Qt only. */
- gboolean display; /**< indicate if the packet is displayed or not in the graph */
- guint src_node; /**< this is used by graph_analysis.c to identify the node */
- guint dst_node; /**< a node is an IP address that will be displayed in columns */
- guint16 line_style; /**< the arrow line width in pixels*/
- gchar *protocol; /**< the label of the protocol defined in the IP packet */
-} seq_analysis_item_t;
-
-/** defines the graph analysis structure */
-typedef struct _seq_analysis_info {
- seq_analysis_type type; /**< sequence type */
- gboolean all_packets; /**< all packets vs only displayed */
- gboolean any_addr; /**< any addr (DL+net) vs net-only */
- int nconv; /**< number of conversations in the list */
- GQueue* items; /**< list of seq_analysis_info_t */
- GHashTable *ht; /**< hash table of seq_analysis_info_t */
- address nodes[MAX_NUM_NODES]; /**< horizontal node list */
- guint32 num_nodes; /**< actual number of nodes */
-} seq_analysis_info_t;
-
-#if 0
-#define SEQ_ANALYSIS_DEBUG(...) { \
- char *SEQ_ANALYSIS_DEBUG_MSG = g_strdup_printf(__VA_ARGS__); \
- g_warning("sequence analysis: %s:%d %s", G_STRFUNC, __LINE__, SEQ_ANALYSIS_DEBUG_MSG); \
- g_free(SEQ_ANALYSIS_DEBUG_MSG); \
-}
-#else
-#define SEQ_ANALYSIS_DEBUG()
-#endif
-
-/** Create and initialize a seq_analysis_info_t struct
- * @return A pointer to a newly allocated seq_analysis_info_t struct.
- */
-seq_analysis_info_t *sequence_analysis_info_new(void);
-
-/** Free a seq_analysis_info_t struct.
- * @param sainfo A pointer to the seq_analysis_info_t struct to be freed.
- */
-void sequence_analysis_info_free(seq_analysis_info_t * sainfo);
-
/** Fill in the segment list for sequence analysis
*
* @param cf Capture file to scan
@@ -108,27 +49,6 @@ void sequence_analysis_info_free(seq_analysis_info_t * sainfo);
*/
void sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo);
-void sequence_analysis_list_sort(seq_analysis_info_t *sainfo);
-
-/** Free the segment list
- *
- * @param sainfo Sequence analysis information.
- */
-void sequence_analysis_list_free(seq_analysis_info_t *sainfo);
-
-/** Fill in the node address list
- *
- * @param sainfo Sequence analysis information.
- * @return The number of transaction items (not nodes) processed.
- */
-int sequence_analysis_get_nodes(seq_analysis_info_t *sainfo);
-
-/** Free the node address list
- *
- * @param sainfo Sequence analysis information.
- */
-void sequence_analysis_free_nodes(seq_analysis_info_t *sainfo);
-
/** Write an ASCII version of the sequence diagram to a file.
*
* @param pathname Pathname of the file to write.