Fix [-Wmissing-prototypes]
[metze/wireshark/wip.git] / ui / gtk / sctp_chunk_stat.c
1 /* sctp_chunk_stat.c
2  * SCTP chunk counter for Wireshark
3  * Copyright 2005 Oleg Terletsky <oleg.terletsky [AT] comverse.com>
4  * Copyright 2009 Varun Notibala <nbvarun [AT] gmail.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27
28 #include "config.h"
29
30 #include <string.h>
31
32 #include <gtk/gtk.h>
33
34 #include <epan/packet_info.h>
35 #include <epan/epan.h>
36 #include <epan/to_str.h>
37 #include <epan/value_string.h>
38 #include <epan/tap.h>
39 #include <epan/dissectors/packet-sctp.h>
40
41 #include "ui/simple_dialog.h"
42 #include "../file.h"
43 #include "../globals.h"
44 #include "../stat_menu.h"
45
46 #include "ui/gtk/gui_stat_util.h"
47 #include "ui/gtk/dlg_utils.h"
48 #include "ui/gtk/tap_param_dlg.h"
49 #include "ui/gtk/gui_utils.h"
50 #include "ui/gtk/main.h"
51 #include "ui/tap-sctp-analysis.h"
52 #include "ui/gtk/sctp_stat_gtk.h"
53
54 void register_tap_listener_sctpstat(void);
55 static void sctpstat_init(const char *opt_arg, void *userdata);
56
57 static tap_param sctp_stat_params[] = {
58         { PARAM_FILTER, "Filter", NULL }
59 };
60
61 static tap_param_dlg sctp_stat_dlg = {
62         "SCTP Statistics",
63         "sctp,stat",
64         sctpstat_init,
65         -1,
66         G_N_ELEMENTS(sctp_stat_params),
67         sctp_stat_params
68 };
69
70 typedef struct sctp_ep {
71         struct sctp_ep* next;
72         address src;
73         address dst;
74         guint16 sport;
75         guint16 dport;
76         guint32 chunk_count[256];
77 } sctp_ep_t;
78
79 /* used to keep track of the statistics for an entire program interface */
80 typedef struct _sctp_stat_t {
81         GtkWidget  *win;
82         GtkWidget  *vbox;
83         char       *filter;
84         GtkWidget  *scrolled_window;
85         GtkTreeView *table;
86         guint32    number_of_packets;
87         sctp_ep_t* ep_list;
88 } sctpstat_t;
89
90 typedef struct _sctp_info sctp_into_t;
91
92 #define CHUNK_TYPE(x)(tvb_get_guint8((x), CHUNK_TYPE_OFFSET))
93
94 static void
95 sctpstat_reset(void *phs)
96 {
97         sctpstat_t* sctp_stat = (sctpstat_t *)phs;
98         sctp_ep_t* list = (sctp_ep_t*)sctp_stat->ep_list;
99         sctp_ep_t* tmp = NULL;
100         guint16 chunk_type;
101
102         if(!list)
103                 return;
104
105         for(tmp = list; tmp ; tmp=tmp->next)
106                 for(chunk_type = 0; chunk_type < 256; chunk_type++)
107                         tmp->chunk_count[chunk_type] = 0;
108
109         sctp_stat->number_of_packets = 0;
110 }
111
112 static sctp_ep_t* alloc_sctp_ep(struct _sctp_info *si)
113 {
114         sctp_ep_t* ep;
115         guint16 chunk_type;
116
117         if(!si)
118                 return NULL;
119
120         if (!(ep = (sctp_ep_t *)g_malloc(sizeof(sctp_ep_t))))
121                 return NULL;
122
123         COPY_ADDRESS(&ep->src,&si->ip_src);
124         COPY_ADDRESS(&ep->dst,&si->ip_dst);
125         ep->sport = si->sport;
126         ep->dport = si->dport;
127         ep->next = NULL;
128         for(chunk_type = 0; chunk_type < 256; chunk_type++)
129                 ep->chunk_count[chunk_type] = 0;
130         return ep;
131 }
132
133 static int
134 sctpstat_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi)
135 {
136
137         sctpstat_t *hs=(sctpstat_t *)phs;
138         sctp_ep_t *tmp = NULL, *te = NULL;
139         struct _sctp_info *si = (struct _sctp_info *) phi;
140         guint32 tvb_number;
141
142         if (!hs)
143                 return (0);
144
145         hs->number_of_packets++;
146         if(!hs->ep_list) {
147                 hs->ep_list = alloc_sctp_ep(si);
148                 te = hs->ep_list;
149         } else {
150                 for(tmp=hs->ep_list ; tmp ; tmp=tmp->next) {
151                         if((!CMP_ADDRESS(&tmp->src,&si->ip_src)) &&
152                            (!CMP_ADDRESS(&tmp->dst,&si->ip_dst)) &&
153                            (tmp->sport == si->sport) &&
154                            (tmp->dport == si->dport)) {
155                                 te = tmp;
156                                 break;
157                         }
158                 }
159                 if(!te) {
160                         if ((te = alloc_sctp_ep(si))) {
161                                 te->next = hs->ep_list;
162                                 hs->ep_list = te;
163                         }
164                 }
165         }
166
167         if(!te)
168                 return (0);
169
170
171         if (si->number_of_tvbs > 0) {
172                 for(tvb_number = 0; tvb_number < si->number_of_tvbs; tvb_number++) {
173                         if (IS_SCTP_CHUNK_TYPE(CHUNK_TYPE(si->tvb[tvb_number])))
174                                 (te->chunk_count[CHUNK_TYPE(si->tvb[tvb_number])])++;
175                         else
176                                 (te->chunk_count[OTHER_CHUNKS_INDEX])++;
177                 }
178         }
179         return (1);
180 }
181
182
183 static void
184 sctpstat_draw(void *phs)
185 {
186         sctpstat_t *hs=(sctpstat_t *)phs;
187         sctp_ep_t* list = hs->ep_list, *tmp;
188         GtkListStore *store;
189         GtkTreeIter iter;
190
191         /* Now print Message and Reason Counter Table */
192         /* clear list before printing */
193         /* XXX use an iter for new/modified ? */
194         store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->table));
195         gtk_list_store_clear(store);
196
197         for(tmp = list ; tmp ; tmp=tmp->next) {
198                 gtk_list_store_append(store, &iter);
199                 gtk_list_store_set(store, &iter,
200                 0,  ep_address_to_str(&tmp->src),
201                 1,  tmp->sport,
202                 2,  ep_address_to_str(&tmp->dst),
203                 3,  tmp->dport,
204                 4,  tmp->chunk_count[SCTP_DATA_CHUNK_ID],
205                 5,  tmp->chunk_count[SCTP_SACK_CHUNK_ID],
206                 6,  tmp->chunk_count[SCTP_HEARTBEAT_CHUNK_ID],
207                 7,  tmp->chunk_count[SCTP_HEARTBEAT_ACK_CHUNK_ID],
208                 8,  tmp->chunk_count[SCTP_INIT_CHUNK_ID],
209                 9,  tmp->chunk_count[SCTP_INIT_ACK_CHUNK_ID],
210                 10, tmp->chunk_count[SCTP_COOKIE_ECHO_CHUNK_ID],
211                 11, tmp->chunk_count[SCTP_COOKIE_ACK_CHUNK_ID],
212                 12, tmp->chunk_count[SCTP_ABORT_CHUNK_ID],
213                 13, tmp->chunk_count[SCTP_ERROR_CHUNK_ID],
214                 14, tmp->chunk_count[SCTP_NR_SACK_CHUNK_ID],
215                 15, tmp->chunk_count[SCTP_ASCONF_ACK_CHUNK_ID],
216                 16, tmp->chunk_count[SCTP_PKTDROP_CHUNK_ID],
217                 17, tmp->chunk_count[SCTP_FORWARD_TSN_CHUNK_ID],
218                 18, tmp->chunk_count[SCTP_ASCONF_CHUNK_ID],
219                 19, tmp->chunk_count[OTHER_CHUNKS_INDEX],
220                 -1
221                 );
222         }
223 }
224
225 static void
226 win_destroy_cb(GtkWindow *win _U_, gpointer data)
227 {
228         sctpstat_t *hs=(sctpstat_t *)data;
229
230         remove_tap_listener(hs);
231
232         if(hs->filter){
233                 g_free(hs->filter);
234                 hs->filter=NULL;
235         }
236         g_free(hs);
237 }
238
239
240 static const stat_column titles[]={
241         {G_TYPE_STRING, LEFT, "Source IP" },
242         {G_TYPE_UINT, RIGHT,  "Source Port" },
243         {G_TYPE_STRING, LEFT, "Dest IP" },
244         {G_TYPE_UINT, RIGHT,  "Dest Port" },
245         {G_TYPE_UINT, RIGHT,  "DATA" },
246         {G_TYPE_UINT, RIGHT,  "SACK" },
247         {G_TYPE_UINT, RIGHT,  "HBEAT" },
248         {G_TYPE_UINT, RIGHT,  "HBEAT-ACK" },
249         {G_TYPE_UINT, RIGHT,  "INIT" },
250         {G_TYPE_UINT, RIGHT,  "INIT-ACK" },
251         {G_TYPE_UINT, RIGHT,  "COOKIE" },
252         {G_TYPE_UINT, RIGHT,  "COOKIE-ACK" },
253         {G_TYPE_UINT, RIGHT,  "ABORT" },
254         {G_TYPE_UINT, RIGHT,  "ERROR" },
255         {G_TYPE_UINT, RIGHT,  "NR-SACK" },
256         {G_TYPE_UINT, RIGHT,  "ASCONF-ACK" },
257         {G_TYPE_UINT, RIGHT,  "PKTDROP" },
258         {G_TYPE_UINT, RIGHT,  "FORWARD-TSN" },
259         {G_TYPE_UINT, RIGHT,  "ASCONF" },
260         {G_TYPE_UINT, RIGHT,  "Others" }
261 };
262
263 static void
264 sctpstat_init(const char *opt_arg, void *userdata _U_)
265 {
266         sctpstat_t *hs;
267         GString *error_string;
268         GtkWidget *bbox;
269         GtkWidget *close_bt;
270
271         hs=(sctpstat_t *)g_malloc(sizeof(sctpstat_t));
272         if(strncmp(opt_arg,"sctp,stat,",10) == 0){
273                 hs->filter=g_strdup(opt_arg+10);
274         } else {
275                 hs->filter=NULL;
276         }
277         hs->ep_list = NULL;
278         hs->number_of_packets = 0;
279         sctpstat_reset(hs);
280
281         hs->win = dlg_window_new("Wireshark: SCTP Chunk Statistics");  /* transient_for top_level */
282         gtk_window_set_destroy_with_parent (GTK_WINDOW(hs->win), TRUE);
283         gtk_window_set_default_size(GTK_WINDOW(hs->win), 700, 250);
284
285         hs->vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
286         gtk_container_set_border_width(GTK_CONTAINER(hs->vbox), 12);
287
288         init_main_stat_window(hs->win, hs->vbox, "SCTP Chunk Counter", hs->filter);
289
290         /* init a scrolled window*/
291         hs->scrolled_window = scrolled_window_new(NULL, NULL);
292
293         hs->table = create_stat_table(hs->scrolled_window, hs->vbox, 20, titles);
294
295         error_string=register_tap_listener("sctp", hs, hs->filter, 0,
296                                            sctpstat_reset,
297                                            sctpstat_packet,
298                                            sctpstat_draw);
299         if(error_string){
300                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
301                 g_string_free(error_string, TRUE);
302                 g_free(hs->filter);
303                 g_free(hs);
304                 return;
305         }
306
307         /* Button row. */
308         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
309         gtk_box_pack_end(GTK_BOX(hs->vbox), bbox, FALSE, FALSE, 0);
310
311         close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
312         window_set_cancel_button(hs->win, close_bt, window_cancel_button_cb);
313
314         g_signal_connect(hs->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
315         g_signal_connect(hs->win, "destroy", G_CALLBACK(win_destroy_cb), hs);
316
317         gtk_widget_show_all(hs->win);
318         window_present(hs->win);
319
320         cf_retap_packets(&cfile);
321 }
322
323 void
324 register_tap_listener_sctpstat(void)
325 {
326         register_param_stat(&sctp_stat_dlg, "Chunk Counter",
327             REGISTER_STAT_GROUP_TELEPHONY_SCTP);
328 }