![Guy Harris](/assets/img/avatar_default.png)
the ui directory. (Perhaps some other files that would be used by all flavors of Wireshark, for any GUI toolkit or for someting such as ncurses, and not for any command-line tool such as TShark, should be moved there as well.) Shuffle some #includes to put the "ui/XXX.h" includes together. svn path=/trunk/; revision=40529
340 lines
8.6 KiB
C
340 lines
8.6 KiB
C
/* sctp_chunk_stat.c
|
|
* SCTP chunk counter for Wireshark
|
|
* Copyright 2005 Oleg Terletsky <oleg.terletsky [AT] comverse.com>
|
|
* Copyright 2009 Varun Notibala <nbvarun [AT] gmail.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
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <epan/packet_info.h>
|
|
#include <epan/epan.h>
|
|
#include <epan/value_string.h>
|
|
#include <epan/tap.h>
|
|
#include <epan/dissectors/packet-sctp.h>
|
|
|
|
#include "ui/simple_dialog.h"
|
|
#include "../file.h"
|
|
#include "../globals.h"
|
|
#include "../stat_menu.h"
|
|
|
|
#include "ui/gtk/gui_stat_util.h"
|
|
#include "ui/gtk/dlg_utils.h"
|
|
#include "ui/gtk/tap_param_dlg.h"
|
|
#include "ui/gtk/gui_utils.h"
|
|
#include "ui/gtk/main.h"
|
|
#include "ui/gtk/sctp_stat.h"
|
|
|
|
|
|
static void sctpstat_init(const char *optarg, void *userdata);
|
|
|
|
static tap_param sctp_stat_params[] = {
|
|
{ PARAM_FILTER, "Filter", NULL }
|
|
};
|
|
|
|
static tap_param_dlg sctp_stat_dlg = {
|
|
"SCTP Statistics",
|
|
"sctp,stat",
|
|
sctpstat_init,
|
|
-1,
|
|
G_N_ELEMENTS(sctp_stat_params),
|
|
sctp_stat_params
|
|
};
|
|
|
|
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 _sctp_stat_t {
|
|
GtkWidget *win;
|
|
GtkWidget *vbox;
|
|
char *filter;
|
|
GtkWidget *scrolled_window;
|
|
GtkTreeView *table;
|
|
guint32 number_of_packets;
|
|
sctp_ep_t* ep_list;
|
|
} sctpstat_t;
|
|
|
|
typedef struct _sctp_info sctp_into_t;
|
|
|
|
#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(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;
|
|
struct _sctp_info *si = (struct _sctp_info *) phi;
|
|
guint32 tvb_number;
|
|
|
|
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) {
|
|
for(tvb_number = 0; tvb_number < si->number_of_tvbs; tvb_number++) {
|
|
if (IS_SCTP_CHUNK_TYPE(CHUNK_TYPE(si->tvb[tvb_number])))
|
|
(te->chunk_count[CHUNK_TYPE(si->tvb[tvb_number])])++;
|
|
else
|
|
(te->chunk_count[OTHER_CHUNKS_INDEX])++;
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
|
|
static void
|
|
sctpstat_draw(void *phs)
|
|
{
|
|
sctpstat_t *hs=(sctpstat_t *)phs;
|
|
sctp_ep_t* list = hs->ep_list, *tmp;
|
|
GtkListStore *store;
|
|
GtkTreeIter iter;
|
|
|
|
/* Now print Message and Reason Counter Table */
|
|
/* clear list before printing */
|
|
/* XXX use an iter for new/modified ? */
|
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->table));
|
|
gtk_list_store_clear(store);
|
|
|
|
for(tmp = list ; tmp ; tmp=tmp->next) {
|
|
gtk_list_store_append(store, &iter);
|
|
gtk_list_store_set(store, &iter,
|
|
0, ep_address_to_str(&tmp->src),
|
|
1, tmp->sport,
|
|
2, ep_address_to_str(&tmp->dst),
|
|
3, tmp->dport,
|
|
4, tmp->chunk_count[SCTP_DATA_CHUNK_ID],
|
|
5, tmp->chunk_count[SCTP_SACK_CHUNK_ID],
|
|
6, tmp->chunk_count[SCTP_HEARTBEAT_CHUNK_ID],
|
|
7, tmp->chunk_count[SCTP_HEARTBEAT_ACK_CHUNK_ID],
|
|
8, tmp->chunk_count[SCTP_INIT_CHUNK_ID],
|
|
9, tmp->chunk_count[SCTP_INIT_ACK_CHUNK_ID],
|
|
10, tmp->chunk_count[SCTP_COOKIE_ECHO_CHUNK_ID],
|
|
11, tmp->chunk_count[SCTP_COOKIE_ACK_CHUNK_ID],
|
|
12, tmp->chunk_count[SCTP_ABORT_CHUNK_ID],
|
|
13, tmp->chunk_count[SCTP_ERROR_CHUNK_ID],
|
|
14, tmp->chunk_count[SCTP_NR_SACK_CHUNK_ID],
|
|
15, tmp->chunk_count[SCTP_ASCONF_ACK_CHUNK_ID],
|
|
16, tmp->chunk_count[SCTP_PKTDROP_CHUNK_ID],
|
|
17, tmp->chunk_count[SCTP_FORWARD_TSN_CHUNK_ID],
|
|
18, tmp->chunk_count[SCTP_ASCONF_CHUNK_ID],
|
|
19, tmp->chunk_count[OTHER_CHUNKS_INDEX],
|
|
-1
|
|
);
|
|
}
|
|
}
|
|
|
|
static void
|
|
win_destroy_cb(GtkWindow *win _U_, gpointer data)
|
|
{
|
|
sctpstat_t *hs=(sctpstat_t *)data;
|
|
|
|
protect_thread_critical_region();
|
|
remove_tap_listener(hs);
|
|
unprotect_thread_critical_region();
|
|
|
|
if(hs->filter){
|
|
g_free(hs->filter);
|
|
hs->filter=NULL;
|
|
}
|
|
g_free(hs);
|
|
}
|
|
|
|
|
|
static const stat_column titles[]={
|
|
{G_TYPE_STRING, LEFT, "Source IP" },
|
|
{G_TYPE_UINT, RIGHT, "Source Port" },
|
|
{G_TYPE_STRING, LEFT, "Dest IP" },
|
|
{G_TYPE_UINT, RIGHT, "Dest Port" },
|
|
{G_TYPE_UINT, RIGHT, "DATA" },
|
|
{G_TYPE_UINT, RIGHT, "SACK" },
|
|
{G_TYPE_UINT, RIGHT, "HBEAT" },
|
|
{G_TYPE_UINT, RIGHT, "HBEAT-ACK" },
|
|
{G_TYPE_UINT, RIGHT, "INIT" },
|
|
{G_TYPE_UINT, RIGHT, "INIT-ACK" },
|
|
{G_TYPE_UINT, RIGHT, "COOKIE" },
|
|
{G_TYPE_UINT, RIGHT, "COOKIE-ACK" },
|
|
{G_TYPE_UINT, RIGHT, "ABORT" },
|
|
{G_TYPE_UINT, RIGHT, "ERROR" },
|
|
{G_TYPE_UINT, RIGHT, "NR-SACK" },
|
|
{G_TYPE_UINT, RIGHT, "ASCONF-ACK" },
|
|
{G_TYPE_UINT, RIGHT, "PKTDROP" },
|
|
{G_TYPE_UINT, RIGHT, "FORWARD-TSN" },
|
|
{G_TYPE_UINT, RIGHT, "ASCONF" },
|
|
{G_TYPE_UINT, RIGHT, "Others" }
|
|
};
|
|
|
|
static void
|
|
sctpstat_init(const char *optarg, void *userdata _U_)
|
|
{
|
|
sctpstat_t *hs;
|
|
GString *error_string;
|
|
GtkWidget *bbox;
|
|
GtkWidget *close_bt;
|
|
|
|
hs=g_malloc(sizeof(sctpstat_t));
|
|
if(strncmp(optarg,"sctp,stat,",10) == 0){
|
|
hs->filter=g_strdup(optarg+10);
|
|
} else {
|
|
hs->filter=NULL;
|
|
}
|
|
hs->ep_list = NULL;
|
|
hs->number_of_packets = 0;
|
|
sctpstat_reset(hs);
|
|
|
|
hs->win = dlg_window_new("Wireshark: SCTP Chunk Statistics"); /* transient_for top_level */
|
|
gtk_window_set_destroy_with_parent (GTK_WINDOW(hs->win), TRUE);
|
|
gtk_window_set_default_size(GTK_WINDOW(hs->win), 700, 250);
|
|
|
|
hs->vbox=gtk_vbox_new(FALSE, 3);
|
|
gtk_container_set_border_width(GTK_CONTAINER(hs->vbox), 12);
|
|
|
|
init_main_stat_window(hs->win, hs->vbox, "SCTP Chunk Counter", hs->filter);
|
|
|
|
/* init a scrolled window*/
|
|
hs->scrolled_window = scrolled_window_new(NULL, NULL);
|
|
|
|
hs->table = create_stat_table(hs->scrolled_window, hs->vbox, 20, titles);
|
|
|
|
error_string=register_tap_listener("sctp", hs, hs->filter, 0,
|
|
sctpstat_reset,
|
|
sctpstat_packet,
|
|
sctpstat_draw);
|
|
if(error_string){
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
|
|
g_string_free(error_string, TRUE);
|
|
g_free(hs->filter);
|
|
g_free(hs);
|
|
return;
|
|
}
|
|
|
|
/* Button row. */
|
|
bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
|
|
gtk_box_pack_end(GTK_BOX(hs->vbox), bbox, FALSE, FALSE, 0);
|
|
|
|
close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
|
|
window_set_cancel_button(hs->win, close_bt, window_cancel_button_cb);
|
|
|
|
g_signal_connect(hs->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
|
|
g_signal_connect(hs->win, "destroy", G_CALLBACK(win_destroy_cb), hs);
|
|
|
|
gtk_widget_show_all(hs->win);
|
|
window_present(hs->win);
|
|
|
|
cf_retap_packets(&cfile);
|
|
}
|
|
|
|
void
|
|
register_tap_listener_sctpstat(void)
|
|
{
|
|
register_dfilter_stat(&sctp_stat_dlg, "S_CTP/Chunk Counter",
|
|
REGISTER_STAT_GROUP_TELEPHONY);
|
|
}
|
|
|
|
void sctp_chunk_counter_cb(GtkAction *action _U_, gpointer user_data _U_)
|
|
{
|
|
tap_param_dlg_cb(action, &sctp_stat_dlg);
|
|
}
|
|
|