diff options
author | Michael Tüxen <tuexen@fh-muenster.de> | 2005-03-20 12:02:00 +0000 |
---|---|---|
committer | Michael Tüxen <tuexen@fh-muenster.de> | 2005-03-20 12:02:00 +0000 |
commit | 3aa6383210e3a6d25cb8b8402825d4e4a268a923 (patch) | |
tree | e7333c8f8868841516f821f9dcf3af8e6570e8e1 | |
parent | 612b5f4fc690ba9c78491d5f40a19b053275127f (diff) | |
download | wireshark-3aa6383210e3a6d25cb8b8402825d4e4a268a923.tar.gz |
From Oleg Terletsky: Support for SCTP chunk counters. Modified to handle bundling correctly.
svn path=/trunk/; revision=13823
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-sctp.c | 6 | ||||
-rw-r--r-- | gtk/Makefile.common | 3 | ||||
-rw-r--r-- | gtk/conversations_sctp.c | 96 | ||||
-rw-r--r-- | gtk/sctp_chunk_stat.c | 351 | ||||
-rw-r--r-- | tap-iousers.c | 70 | ||||
-rw-r--r-- | tap-sctpchunkstat.c | 265 |
8 files changed, 788 insertions, 5 deletions
@@ -1862,6 +1862,7 @@ Thierry Martin <thierry.martin [AT] accellent-group.com> { Oleg Terletsky <oleg.terletsky [AT] comverse.com> { LWRES support AgentX support + SCTP chunk statistic } Michael Lum <mlum [AT] telostech.com> { diff --git a/Makefile.common b/Makefile.common index aca585176e..a105566ac4 100644 --- a/Makefile.common +++ b/Makefile.common @@ -125,6 +125,7 @@ TETHEREAL_TAP_SRC = \ tap-protohierstat.c \ tap-rpcstat.c \ tap-rpcprogs.c \ + tap-sctpchunkstat.c \ tap-sipstat.c \ tap-smbsids.c \ tap-smbstat.c \ diff --git a/epan/dissectors/packet-sctp.c b/epan/dissectors/packet-sctp.c index 4332142fdd..095eb04f3a 100644 --- a/epan/dissectors/packet-sctp.c +++ b/epan/dissectors/packet-sctp.c @@ -1902,9 +1902,6 @@ dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, pr flags_item = NULL; }; - /* FIXME - sctp_info.msg_type = type; - */ /* now dissect the chunk value */ switch(type) { case SCTP_DATA_CHUNK_ID: @@ -2174,12 +2171,11 @@ dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) memset(&sctp_info, 0, sizeof(struct _sctp_info)); sctp_info.verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET); - /* FIXME + /* FIXME: Do we need to put this into _sctp_info? */ sctp_info.sport = pinfo->srcport; sctp_info.dport = pinfo->destport; SET_ADDRESS(&sctp_info.ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data); SET_ADDRESS(&sctp_info.ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data); - */ dissect_sctp_packet(tvb, pinfo, tree, FALSE); if (!pinfo->in_error_pkt) diff --git a/gtk/Makefile.common b/gtk/Makefile.common index ec6c35d7d0..4dce286c70 100644 --- a/gtk/Makefile.common +++ b/gtk/Makefile.common @@ -106,11 +106,13 @@ ETHEREAL_TAP_SRC = \ ansi_a_stat.c \ ansi_map_stat.c \ bootp_stat.c \ + sctp_chunk_stat.c \ conversations_eth.c \ conversations_fc.c \ conversations_fddi.c \ conversations_ip.c \ conversations_ipx.c \ + conversations_sctp.c \ conversations_tcpip.c \ conversations_tr.c \ conversations_udpip.c \ @@ -145,6 +147,7 @@ ETHEREAL_TAP_SRC = \ stats_tree_stat.c \ sctp_assoc_analyse.c \ sctp_stat_dlg.c \ +# sctp_chunk_stat_dlg.c \ sip_stat.c \ smb_stat.c \ tcp_graph.c \ diff --git a/gtk/conversations_sctp.c b/gtk/conversations_sctp.c new file mode 100644 index 0000000000..1b9a94bbe0 --- /dev/null +++ b/gtk/conversations_sctp.c @@ -0,0 +1,96 @@ +/* conversations_sctp.c + * conversations_sctp 2005 Oleg Terletsky <oleg.terletsky@comverse.com> + * + * $Id:$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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 <gtk/gtk.h> +#include <string.h> +#include "epan/packet.h" +#include "tap_menu.h" +#include <epan/tap.h> +#include "../register.h" +#include "conversations_table.h" +#include <epan/dissectors/packet-sctp.h> + + +static int +sctp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip) +{ + const struct _sctp_info *sctphdr=vip; + + add_conversation_table_data((conversations_table *)pct, + &sctphdr->ip_src, + &sctphdr->ip_dst, + sctphdr->sport, + sctphdr->dport, + 1, + pinfo->fd->pkt_len, + SAT_NONE, + PT_SCTP); + + + return 1; +} + + + +static void +sctp_conversation_init(char *optarg) +{ + char *filter=NULL; + + if(!strncmp(optarg,"conv,sctp,",10)){ + filter=optarg+10; + } else { + filter=NULL; + } + + init_conversation_table(FALSE, "SCTP", "sctp", filter, sctp_conversation_packet); + +} + + +static void +sctp_conversation_cb(GtkWidget *w _U_, gpointer d _U_) +{ + sctp_conversation_init("conv,sctp"); +} + + +void +register_tap_listener_sctp_conversation(void) +{ + register_ethereal_tap("conv,sctp", sctp_conversation_init); + + register_tap_menu_item("SCTP", REGISTER_TAP_GROUP_CONVERSATION_LIST, + sctp_conversation_cb, NULL, NULL, NULL); + + register_conversation_table(FALSE, "SCTP", "sctp", NULL /*filter*/, sctp_conversation_packet); +} diff --git a/gtk/sctp_chunk_stat.c b/gtk/sctp_chunk_stat.c new file mode 100644 index 0000000000..8d8eee08ea --- /dev/null +++ b/gtk/sctp_chunk_stat.c @@ -0,0 +1,351 @@ +/* sctp_chunk_stat.c + * SCTP chunk counter for ethereal + * Copyright 2005 Oleg Terletsky oleg.terletsky@comverse.com + * + * $Id:$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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 "tap_menu.h" +#include <epan/tap.h> +#include "../register.h" +#include <epan/dissectors/packet-sctp.h> +#include "gtk_stat_util.h" +#include "compat_macros.h" +#include "../simple_dialog.h" +#include "dlg_utils.h" +#include "../file.h" +#include "../globals.h" +#include "../tap_dfilter_dlg.h" +#include "tap_dfilter_dlg.h" +#include "ui_util.h" + + +static void sctpstat_init(char *optarg); + +static tap_dfilter_dlg sctp_stat_dlg = { + "SCTP Statisctics", + "sctp,stat", + sctpstat_init, + -1 +}; + +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; + GtkCList *table; + guint32 number_of_packets; + sctp_ep_t* ep_list; +} sctpstat_t; + +typedef struct _sctp_info sctp_into_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; +} + +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; + 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=0; + char *str[14]; + int i=0; + + for(i=0;i<14;i++) { + str[i]=g_malloc(sizeof(char[256])); + } + /* Now print Message and Reason Counter Table */ + /* clear list before printing */ + gtk_clist_clear(hs->table); + + + for(tmp = list ; tmp ; tmp=tmp->next) { + + g_snprintf(str[0], sizeof(char[256]),"%s", address_to_str(&tmp->src)); + g_snprintf(str[1], sizeof(char[256]),"%u", tmp->sport); + g_snprintf(str[2], sizeof(char[256]),"%s", address_to_str(&tmp->dst)); + g_snprintf(str[3], sizeof(char[256]),"%u", tmp->dport); + g_snprintf(str[4], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_DATA_CHUNK_ID]); + g_snprintf(str[5], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_SACK_CHUNK_ID]); + g_snprintf(str[6], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_HEARTBEAT_CHUNK_ID]); + g_snprintf(str[7], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_HEARTBEAT_ACK_CHUNK_ID]); + g_snprintf(str[8], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_INIT_CHUNK_ID]); + g_snprintf(str[9], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_INIT_ACK_CHUNK_ID]); + g_snprintf(str[10], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_COOKIE_ECHO_CHUNK_ID]); + g_snprintf(str[11], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_COOKIE_ACK_CHUNK_ID]); + g_snprintf(str[12], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_ABORT_CHUNK_ID]); + g_snprintf(str[13], sizeof(char[256]),"%u", tmp->chunk_count[SCTP_ERROR_CHUNK_ID]); + + gtk_clist_append(hs->table, str); + } + + gtk_widget_show(GTK_WIDGET(hs->table)); + +} + +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); +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 gchar *titles[]={"Source IP", + "Sourse port", + "Dest IP", + "Dest port", + "DATA", + "SACK", + "HBEAT", + "HBEAT_ACK", + "INIT", + "INIT_ACK", + "COOKIE", + "COOKIE_ACK", + "ABORT", + "ERROR" }; + +static void +sctpstat_init(char *optarg) +{ + sctpstat_t *hs; + char *filter=NULL; + GString *error_string; + GtkWidget *bbox; + GtkWidget *close_bt; + + if(strncmp(optarg,"sctp,stat,",11) == 0){ + filter=optarg+11; + } else { + filter=g_malloc(1); + *filter='\0'; + } + + hs=g_malloc(sizeof(sctpstat_t)); + hs->filter=g_strdup(filter); + hs->ep_list = NULL; + hs->number_of_packets = 0; + sctpstat_reset(hs); + + hs->win=window_new(GTK_WINDOW_TOPLEVEL, "Ethereal: SCTP chunk statistics"); + gtk_window_set_default_size(GTK_WINDOW(hs->win), 400, 200); + + 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", filter); + + /* init a scrolled window*/ + hs->scrolled_window = scrolled_window_new(NULL, NULL); + + hs->table = create_stat_table(hs->scrolled_window, hs->vbox, 14, titles); + + error_string=register_tap_listener("sctp", hs, filter, + sctpstat_reset, + sctpstat_packet, + sctpstat_draw); + if(error_string){ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, 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 = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE); + window_set_cancel_button(hs->win, close_bt, window_cancel_button_cb); + + SIGNAL_CONNECT(hs->win, "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(hs->win, "destroy", 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_ethereal_tap("sctp,stat", sctpstat_init); + + register_tap_menu_item("SCTP Chunk", REGISTER_TAP_GROUP_NONE, + gtk_tap_dfilter_dlg_cb, NULL, NULL, &(sctp_stat_dlg)); +} diff --git a/tap-iousers.c b/tap-iousers.c index e1a93d07df..4d0ed164fc 100644 --- a/tap-iousers.c +++ b/tap-iousers.c @@ -43,6 +43,7 @@ #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-fc.h> #include <epan/dissectors/packet-fddi.h> @@ -128,6 +129,65 @@ iousers_udpip_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, con 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; + + sprintf(s_sport,"%d",sctph->sport); + sprintf(s_dport,"%d",sctph->dport); + + if(sctph->sport > sctph->dport) { + direction=0; + snprintf(name1,256,"%s:%s",address_to_str(&sctph->ip_src),s_sport); + snprintf(name2,256,"%s:%s",address_to_str(&sctph->ip_dst),s_dport); + } else if(sctph->sport < sctph->dport) { + direction=1; + snprintf(name1,256,"%s:%s",address_to_str(&sctph->ip_src),s_sport); + snprintf(name2,256,"%s:%s",address_to_str(&sctph->ip_dst),s_dport); + } else { + direction=0; + snprintf(name1,256,"%s:%s",address_to_str(&sctph->ip_src),s_sport); + snprintf(name2,256,"%s:%s",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=strdup(name1); +/* iui->addr2=NULL;*/ + iui->name2=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; @@ -599,6 +659,15 @@ iousers_init(char *optarg) 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, "tethereal: invalid \"-z conv,<type>[,<filter>]\" argument\n"); fprintf(stderr," <type> must be one of\n"); @@ -607,6 +676,7 @@ iousers_init(char *optarg) 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"); diff --git a/tap-sctpchunkstat.c b/tap-sctpchunkstat.c new file mode 100644 index 0000000000..8cdf8e5bdc --- /dev/null +++ b/tap-sctpchunkstat.c @@ -0,0 +1,265 @@ +/* tap_sctpchunkstat.c + * SCTP chunk counter for ethereal + * Copyright 2005 Oleg Terletsky <oleg.terletsky@comverse.com> + * + * $Id:$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + */ + +/* With MSVC and a libethereal.dll this file needs to import some variables + in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */ +#define _NEED_VAR_IMPORT_ + +#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/value_string.h" +#include "register.h" +#include <epan/dissectors/packet-sctp.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)) + + +extern gchar* address_to_str(const address *); + + +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; +} + + +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; + 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", + address_to_str(&tmp->src),tmp->sport, + 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(char *optarg) +{ + sctpstat_t *hs; + char *filter=NULL; + GString *error_string; + + if(!strncmp(optarg,"sctp,stat,",11)){ + filter=optarg+11; + } else { + filter=g_malloc(1); + *filter='\0'; + } + + hs = g_malloc(sizeof(sctpstat_t)); + hs->filter=g_malloc(strlen(filter)+1); + hs->ep_list = NULL; + hs->number_of_packets = 0; + strcpy(hs->filter, filter); + + sctpstat_reset(hs); + + error_string=register_tap_listener("sctp", hs, filter, 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, "tethereal: 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_ethereal_tap("sctp,stat", sctpstat_init); +} |