Ethereal-dev: Re: [Ethereal-dev] Expert Analysis API

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Lars Roland <lars.roland@xxxxxxx>
Date: Wed, 26 May 2004 12:38:44 +0200
Hello list,

here is what I have done so far. Not much, but may be someone can use this as a starting point.

stat_table_interface.h : helper functions used in a gui independent tap
tethereal_stat_table.c : tethereal's implementation of helper functions
gtk_stat_table.c :       ethereal's implementation of helper functions
tap-h225counter.c :      tap implementation example

Note that this source is a little out of date and may need to be patched to work with current ethereal.

My intention was to create both an ethereal tap and an tethereal tap using the same tap code for both. I created some helper functions as some kind of an api. Ethereal and Tethereal have seperate implementations of those helper functions.

I decided to create a data structure for tethereal that can be accessed in a similar way as the GTKClist (see tethereal_stat_table.c) . Thus the GTK implementation of the helper functions is not very interesting. Just some sort of renaming of GTK functions. :)

The data structure I have created for tethereal may be used as a basis for a generic tabel structure used by both ethereal and tethereal.

The printing function in tethereal_stat_table may be useful, too.

Feel free to use anything what you find useful.

I wish I had a group of students working on this. :(

Regards,
Lars
/* gtk_stat_table.c
 * table functions for ethereal with gtk
 * Lars Roland
 *
 * $Id:  $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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_info.h>
#include <epan/epan.h>
#include "tap_menu.h"
#include "../tap.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"

#include "../stat_table_interface.h"

void protect_thread_critical_region(void);
void unprotect_thread_critical_region(void);
static void
win_destroy_cb(GtkWindow *win _U_, gpointer data)
{
	tap_register_data *tap_data=(tap_register_data *)data;

	protect_thread_critical_region();
	remove_tap_listener(tap_data->container);
	unprotect_thread_critical_region();

	if(tap_data->filter){
		g_free(tap_data->filter);
		tap_data->filter=NULL;
	}
	g_free(tap_data->container);
	g_free(tap_data);
}

gpointer create_table(char *title, tap_register_data *tap_data, char *col_titles[] , gint columns, gint width, gint height)
{
	GtkCList *table;
	GtkWidget *scrolled_window;
	GtkWidget *vbox;
	GtkWidget *win;
	GtkWidget *main_label;
	GtkWidget *filter_label;
	char filter_string[256];
	
	win=window_new(GTK_WINDOW_TOPLEVEL, NULL);
	SIGNAL_CONNECT(win, "destroy", win_destroy_cb, tap_data);

	vbox=gtk_vbox_new(FALSE, 0);
	
	gtk_window_set_title(GTK_WINDOW(win), title);

	gtk_container_add(GTK_CONTAINER(win), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
	gtk_widget_show(vbox);

	main_label=gtk_label_new(title);
	gtk_box_pack_start(GTK_BOX(vbox), main_label, FALSE, FALSE, 0);
	gtk_widget_show(main_label);

	snprintf(filter_string,255,"Filter: %s",tap_data->filter?tap_data->filter:"");
	filter_label=gtk_label_new(filter_string);
	gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
	gtk_widget_show(filter_label);

        /* init a scrolled window*/
	scrolled_window = scrolled_window_new(NULL, NULL);
	WIDGET_SET_SIZE(scrolled_window, width, height);
	
	table = create_stat_table(scrolled_window, vbox, columns, col_titles);
	gtk_widget_show_all(win);
	
	return (gpointer)table;
}

void append_row2table(gpointer table_pointer, char *row_items[])
{
	GtkCList *table;
	
	table = (GtkCList *)table_pointer;
	gtk_clist_append(table, row_items);
}

void show_table(gpointer table_pointer)
{
	GtkCList *table;
	
	table = (GtkCList *)table_pointer;
	gtk_widget_show(GTK_WIDGET(table));
}

void clear_table(gpointer table_pointer)
{
	GtkCList *table;
	
	table = (GtkCList *)table_pointer;
	gtk_clist_clear(table);
}

void print_error_string(GString *error_string)
{
	simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
	g_string_free(error_string, TRUE);	
}

void call_redissection(void){
	retap_packets(&cfile);
}

void register_generic_tap_menu_item(char *name,  gint group, gpointer callback_data)
{
	register_tap_menu_item(name, group, gtk_tap_dfilter_dlg_cb, NULL, NULL, callback_data);
}
/* stat_table_interface.h
 * interface for statistic tables used in taps
 * Lars Roland
 *
 * $Id:  $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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.
 */

/* 
 * tap_register_data contains pointers to dynamically allocated memory.
 * and it is dynamically allocated, too.
 * We have to free them in a callback when the tap's window is destroyed.
 * We have to remove the tap listener in this callback, too.
 *
 * We need this only for GTK, but it is used in common code for ethereal and tethereal.
 */
 
typedef struct _tap_register_data {
	void *container;
	char *filter;
} tap_register_data;

/*
 * Following functions are used in generic taps. 
 * Tethereal and Ethereal have different implementations of them.
 * You will find Tethereal's implementation in tethereal_stat_table.c ,
 * and Ethereal's implementation in gtk/gtk_stat_table.c
 */
gpointer create_table(char *title, tap_register_data *tap_data, char *col_titles[] , gint columns, gint width, gint height);

void append_row2table(gpointer table, char *row_items[]);

void show_table(gpointer table);

void clear_table(gpointer table);

void print_error_string(GString *error_string);

void call_redissection(void);

void register_generic_tap_menu_item(char *name, gint group, gpointer callback_data);
/* tethereal_stat_table.c
 * table functions for tethereal
 * Lars Roland
 *
 * $Id:  $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <glib.h>

#include "stat_table_interface.h"

typedef struct _row_item {
 	char *item;
 	struct _row_item *next;
} row_item;
 	

typedef struct _generic_row {
	row_item *first_item;
	struct _generic_row *next;
} generic_row;

typedef struct _generic_column {
	char *title;
	guint width;
	struct _generic_column *next;
} generic_column;

typedef struct _generic_table {
	char *title;
	char *filter; 
	gint columns;
	gint rows;
	generic_column *first_column;
	generic_row *first_row;
	generic_row *last_row;
} generic_table;

gpointer create_table(char *title, tap_register_data *tap_data, char *col_titles[] , gint columns, gint width , gint height )
{
	generic_table *table;
	generic_column *current_col;
	gint i;
	
	table = (generic_table *) g_malloc(sizeof(generic_table));
	table->title = title;
	table->filter = tap_data->filter;
	table->columns = columns;
	table->rows = 0;
	table->first_row = NULL;
	table->last_row = NULL;
	
	table->first_column = (generic_column *) g_malloc(sizeof(generic_column));
	current_col = table->first_column;
	current_col->title = col_titles[0];
	current_col->width = strlen(col_titles[0]);
	
	for(i=1;i<columns;i++) {
		current_col->next = (generic_column *) g_malloc(sizeof(generic_column));
		current_col = current_col->next;
		current_col->title = col_titles[i];
		current_col->width = strlen(col_titles[i]);
	}
	current_col->next=NULL; /* last column */
	
	return (gpointer)table;
}

void append_row2table(gpointer table_pointer, char *row_items[])
{
	generic_row *current_row;
	generic_column *current_col;
	row_item *current_item;
	gint i;
	generic_table *table;
	
	table = (generic_table *)table_pointer;
		
	current_row = (generic_row *) g_malloc(sizeof(generic_row));
	
	if(table->first_row == NULL) {
		table->first_row = current_row;
		table->last_row = current_row;
	} else {
		table->last_row->next = current_row;
		table->last_row = current_row;
	}
	
	table->rows++;
	
	current_row->next = NULL;
	current_row->first_item = (row_item *) g_malloc(sizeof(row_item));	
	current_col = table->first_column;
	
	current_item = current_row->first_item;
	current_item->item = g_strdup(row_items[0]);
	current_col->width = (current_col->width > strlen(current_item->item)) ? current_col->width : strlen(current_item->item);
	
	for(i=1;i<table->columns;i++) {	
		current_item->next = (row_item *) g_malloc(sizeof(row_item));
		current_item = current_item->next;
		current_item->item = g_strdup(row_items[i]);
		current_col = current_col->next;
		current_col->width = (current_col->width > strlen(current_item->item)) ? current_col->width : strlen(current_item->item);		
	}
	current_item->next = NULL;
	
}

static void print_table_line(generic_table *table)
{
	generic_column *current_col;
	gint i;
	char *tmp;
	
	printf("+");
	
	current_col = table->first_column;
	for(i=0;i<table->columns;i++) {
		tmp = g_strnfill(current_col->width, '-');
		printf("-%s-+",tmp);
		g_free(tmp);
		current_col = current_col->next;
	}
	printf("\n");
}

void show_table(gpointer table_pointer)
{
	gint i, j, title_lenght, filter_length;
	generic_column *current_col;
	generic_row *current_row;
	row_item *current_row_item;
	generic_table *table;
	char *tmp;
	
	table = (generic_table *)table_pointer;	
	title_lenght = strlen(table->title);
	filter_length = strlen(table->filter);
	
	/* print title and filter */
	printf("\n+++ %s +++\n", table->title);
	printf("Filter: %s\n\n", table->filter);
	print_table_line(table);
	
	/* print column titles */
	current_col = table->first_column;
	for(i=0;i<table->columns;i++) {
		tmp = g_strnfill(current_col->width - strlen(current_col->title), ' ');
		/* make first column left aligned, everything else is right aligned */
		if(i==0) {
			printf("| %s%s ", current_col->title, tmp);
		} else {
			printf("| %s%s ", tmp, current_col->title);
		}
		current_col = current_col->next;
		g_free(tmp);
	}
	printf("|\n"); 
	
	print_table_line(table);
	
	/* print table values */
	current_row = table->first_row;
	for(j=0;j<table->rows;j++) {
		current_row_item = current_row->first_item;
		current_col = table->first_column;
		for(i=0;i<table->columns;i++) {
			tmp = g_strnfill(current_col->width - strlen(current_row_item->item), ' ');
			/* make first column left aligned, everything else right aligned */
			if(i==0) {
				printf("| %s%s ", current_row_item->item, tmp);
			} else {
				printf("| %s%s ", tmp, current_row_item->item);
			}
			current_row_item = current_row_item->next;
			current_col = current_col->next;
			g_free(tmp);
		}
		printf("|\n"); 
		current_row = current_row->next;
	}
	
	print_table_line(table);
}

/* Dummy function, necessary only in GTK version */
void clear_table(gpointer table)
{
	return;
}


void print_error_string(GString *error_string)
{
	fprintf(stderr, "tethereal: Couldn't register tap: %s\n",
		    error_string->str);
	g_string_free(error_string, TRUE);
	exit(1);
}

/* Dummy function, necessary only in GTK version */
void call_redissection(void){
	return;
}

/* Dummy function, necessary only in GTK version */
void register_generic_tap_menu_item(char *name,  gint group, gpointer callback_data)
{
	return;
}

/* tap_h225counter.c
 * h225 message counter for ethereal
 * Copyright 2003 Lars Roland
 *
 * $Id: tap-h225counter.c,v 1.2 2003/12/15 04:23:54 guy Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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

#include <stdio.h>

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <string.h>
#include <epan/packet_info.h>
#include "tap.h"
#include <epan/value_string.h>
#include "register.h"
#include "packet-h225.h"
#include "tap_dfilter_dlg.h"
#include "stat_table_interface.h"

/* following values represent the size of their valuestring arrays */

#define RAS_MSG_TYPES 33
#define CS_MSG_TYPES 13

#define GRJ_REASONS 8
#define RRJ_REASONS 18
#define URQ_REASONS 6
#define URJ_REASONS 6
#define ARJ_REASONS 22
#define BRJ_REASONS 8
#define DRQ_REASONS 3
#define DRJ_REASONS 4
#define LRJ_REASONS 16
#define IRQNAK_REASONS 4
#define REL_CMP_REASONS 26
#define FACILITY_REASONS 11


/* used to keep track of the statistics for an entire program interface */
typedef struct _h225counter_t {
	gpointer table;
	guint32 ras_msg[RAS_MSG_TYPES + 1];
        guint32 cs_msg[CS_MSG_TYPES + 1];
        guint32 grj_reason[GRJ_REASONS + 1];
        guint32 rrj_reason[RRJ_REASONS + 1];
        guint32 urq_reason[URQ_REASONS + 1];
        guint32 urj_reason[URJ_REASONS + 1];
        guint32 arj_reason[ARJ_REASONS + 1];
        guint32 brj_reason[BRJ_REASONS + 1];
        guint32 drq_reason[DRQ_REASONS + 1];
        guint32 drj_reason[DRJ_REASONS + 1];
        guint32 lrj_reason[LRJ_REASONS + 1];
        guint32 irqnak_reason[IRQNAK_REASONS + 1];
        guint32 rel_cmp_reason[REL_CMP_REASONS + 1];
        guint32 facility_reason[FACILITY_REASONS + 1];
} h225counter_t;


static void
h225counter_reset(void *phs)
{
	h225counter_t *hs=(h225counter_t *)phs;
	int i;

	for(i=0;i<=RAS_MSG_TYPES;i++) {
		hs->ras_msg[i] = 0;
	}
	for(i=0;i<=CS_MSG_TYPES;i++) {
		hs->cs_msg[i] = 0;
	}
	for(i=0;i<=GRJ_REASONS;i++) {
		hs->grj_reason[i] = 0;
	}
	for(i=0;i<=RRJ_REASONS;i++) {
		hs->rrj_reason[i] = 0;
	}
	for(i=0;i<=URQ_REASONS;i++) {
		hs->urq_reason[i] = 0;
	}
	for(i=0;i<=URJ_REASONS;i++) {
		hs->urj_reason[i] = 0;
	}
	for(i=0;i<=ARJ_REASONS;i++) {
		hs->arj_reason[i] = 0;
	}
	for(i=0;i<=BRJ_REASONS;i++) {
		hs->brj_reason[i] = 0;
	}
	for(i=0;i<=DRQ_REASONS;i++) {
		hs->drq_reason[i] = 0;
	}
	for(i=0;i<=DRJ_REASONS;i++) {
		hs->drj_reason[i] = 0;
	}
	for(i=0;i<=LRJ_REASONS;i++) {
		hs->lrj_reason[i] = 0;
	}
	for(i=0;i<=IRQNAK_REASONS;i++) {
		hs->irqnak_reason[i] = 0;
	}
	for(i=0;i<=REL_CMP_REASONS;i++) {
		hs->rel_cmp_reason[i] = 0;
	}
	for(i=0;i<=FACILITY_REASONS;i++) {
		hs->facility_reason[i] = 0;
	}
}

static int
h225counter_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *phi)
{
	h225counter_t *hs=(h225counter_t *)phs;
	h225_packet_info *pi=phi;

	switch (pi->msg_type) {

	case H225_RAS:
		if(pi->msg_tag==-1) { /* uninitialized */
			return 0;
		}
		else if (pi->msg_tag >= RAS_MSG_TYPES) { /* unknown */
			hs->ras_msg[RAS_MSG_TYPES]++;
		}
		else {
			hs->ras_msg[pi->msg_tag]++;
		}

		/* Look for reason tag */
		if(pi->reason==-1) { /* uninitialized */
			break;
		}

		switch(pi->msg_tag) {

		case 2:	/* GRJ */
			if(pi->reason < GRJ_REASONS)
				hs->grj_reason[pi->reason]++;
			else
				hs->grj_reason[GRJ_REASONS]++;
			break;
		case 5:	/* RRJ */
			if(pi->reason < RRJ_REASONS)
				hs->rrj_reason[pi->reason]++;
			else
				hs->rrj_reason[RRJ_REASONS]++;
			break;
		case 6:	/* URQ */
			if(pi->reason < URQ_REASONS)
				hs->urq_reason[pi->reason]++;
			else
				hs->urq_reason[URQ_REASONS]++;
			break;
		case 8:	/* URJ */
			if(pi->reason < URJ_REASONS)
				hs->urj_reason[pi->reason]++;
			else
				hs->urj_reason[URJ_REASONS]++;
			break;
		case 11: /* ARJ */
			if(pi->reason < ARJ_REASONS)
				hs->arj_reason[pi->reason]++;
			else
				hs->arj_reason[ARJ_REASONS]++;
			break;
		case 14: /* BRJ */
			if(pi->reason < BRJ_REASONS)
				hs->brj_reason[pi->reason]++;
			else
				hs->brj_reason[BRJ_REASONS]++;
			break;
		case 15: /* DRQ */
			if(pi->reason < DRQ_REASONS)
				hs->drq_reason[pi->reason]++;
			else
				hs->drq_reason[DRQ_REASONS]++;
			break;
		case 17: /* DRJ */
			if(pi->reason < DRJ_REASONS)
				hs->drj_reason[pi->reason]++;
			else
				hs->drj_reason[DRJ_REASONS]++;
			break;
		case 20: /* LRJ */
			if(pi->reason < LRJ_REASONS)
				hs->lrj_reason[pi->reason]++;
			else
				hs->lrj_reason[LRJ_REASONS]++;
			break;
		case 29: /* IRQ Nak */
			if(pi->reason < IRQNAK_REASONS)
				hs->irqnak_reason[pi->reason]++;
			else
				hs->irqnak_reason[IRQNAK_REASONS]++;
			break;

		default:
			/* do nothing */
			break;
		}

		break;

	case H225_CS:
		if(pi->msg_tag==-1) { /* uninitialized */
			return 0;
		}
		else if (pi->msg_tag >= CS_MSG_TYPES) { /* unknown */
			hs->cs_msg[CS_MSG_TYPES]++;
		}
		else {
			hs->cs_msg[pi->msg_tag]++;
		}

		/* Look for reason tag */
		if(pi->reason==-1) { /* uninitialized */
			break;
		}

		switch(pi->msg_tag) {

		case 5:	/* ReleaseComplete */
			if(pi->reason < REL_CMP_REASONS)
				hs->rel_cmp_reason[pi->reason]++;
			else
				hs->rel_cmp_reason[REL_CMP_REASONS]++;
			break;
		case 6:	/* Facility */
			if(pi->reason < FACILITY_REASONS)
				hs->facility_reason[pi->reason]++;
			else
				hs->facility_reason[FACILITY_REASONS]++;
			break;
		default:
			/* do nothing */
			break;
		}

		break;

	default:
		return 0;
		break;
	}

	return 1;
}


static void
h225counter_draw(void *phs)
{
	h225counter_t *hs=(h225counter_t *)phs;
	int i,j;
	char *str[2];

	for(i=0;i<2;i++) {
		str[i]=g_malloc(sizeof(char[256]));
	}
	/* Now print Message and Reason Counter Table */
	/* clear list before printing */
	clear_table(hs->table);

	for(i=0;i<=RAS_MSG_TYPES;i++) {
		if(hs->ras_msg[i]!=0) {
			g_snprintf(str[0], sizeof(char[256]), "%s", val_to_str(i,RasMessage_vals,"unknown ras-messages  "));
			g_snprintf(str[1], sizeof(char[256]), "%d", hs->ras_msg[i]);
			append_row2table(hs->table, str);

			/* reason counter */
			switch(i) {
			case 2: /* GRJ */
				for(j=0;j<=GRJ_REASONS;j++) {
					if(hs->grj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,GatekeeperRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->grj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 5: /* RRJ */
				for(j=0;j<=RRJ_REASONS;j++) {
					if(hs->rrj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,RegistrationRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->rrj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 6: /* URQ */
				for(j=0;j<=URQ_REASONS;j++) {
					if(hs->urq_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,UnregRequestReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->urq_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 8: /* URJ */
				for(j=0;j<=URJ_REASONS;j++) {
					if(hs->urj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,UnregRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->urj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 11: /* ARJ */
				for(j=0;j<=ARJ_REASONS;j++) {
					if(hs->arj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,AdmissionRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->arj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 14: /* BRJ */
				for(j=0;j<=BRJ_REASONS;j++) {
					if(hs->brj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,BandRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->brj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 15: /* DRQ */
				for(j=0;j<=DRQ_REASONS;j++) {
					if(hs->drq_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,DisengageReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->drq_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 17: /* DRJ */
				for(j=0;j<=DRJ_REASONS;j++) {
					if(hs->drj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,DisengageRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->drj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 20: /* LRJ */
				for(j=0;j<=LRJ_REASONS;j++) {
					if(hs->lrj_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,LocationRejectReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->lrj_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 29: /* IRQNak */
				for(j=0;j<=IRQNAK_REASONS;j++) {
					if(hs->irqnak_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,InfoRequestNakReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->irqnak_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			default:
				break;
			}
			/* end of reason counter*/
		}
	}

	for(i=0;i<=CS_MSG_TYPES;i++) {
		if(hs->cs_msg[i]!=0) {
			g_snprintf(str[0], sizeof(char[256]), "%s", val_to_str(i,h323_message_body_vals,"unknown cs-messages   "));
			g_snprintf(str[1], sizeof(char[256]), "%d", hs->cs_msg[i]);
			append_row2table(hs->table, str);

			/* reason counter */
			switch(i) {
			case 5: /* ReleaseComplete */
				for(j=0;j<=REL_CMP_REASONS;j++) {
					if(hs->rel_cmp_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,ReleaseCompleteReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->rel_cmp_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			case 6: /* Facility */
				for(j=0;j<=FACILITY_REASONS;j++) {
					if(hs->facility_reason[j]!=0) {
						g_snprintf(str[0], sizeof(char[256]), "    %s", val_to_str(j,FacilityReason_vals,"unknown reason   "));
						g_snprintf(str[1], sizeof(char[256]), "%d", hs->facility_reason[j]);
						append_row2table(hs->table, str);
					}
				}
				break;
			default:
				break;
			}
		}
	}

	show_table(hs->table);
}

static gchar *titles[]={"Message Type or Reason",
			"Count" };

static void
h225counter_init(char *optarg)
{
	h225counter_t *hs;
	char *filter=NULL;
	GString *error_string;
	tap_register_data *h225_tap_data;

	if(strncmp(optarg,"h225,counter,",13) == 0){
		filter=optarg+13;
	} else {
		filter=g_malloc(1);
		*filter='\0';
	}

	/* put all pointers which refer to dynamically allocated memory
	 * into the tap_register_data structure and pass it to create table 
	 */

	h225_tap_data = g_malloc(sizeof(tap_register_data));
	h225_tap_data->container = g_malloc(sizeof(h225counter_t));
	h225_tap_data->filter=g_strdup(filter);

	hs = (h225counter_t *) h225_tap_data->container;

	h225counter_reset(hs);
		
	hs->table = create_table("ITU-T H.225 Message and Message Reason Counter", h225_tap_data, titles, 2, 400, 200);

    	error_string=register_tap_listener("h225", hs, filter, h225counter_reset, h225counter_packet, h225counter_draw);
    	if(error_string){
		/* error, we failed to attach to the tap. clean up */
		g_free(h225_tap_data->filter);
		g_free(h225_tap_data->container);
		g_free(h225_tap_data);
		print_error_string(error_string);
		return;
	}

	call_redissection();
}

tap_dfilter_dlg h225_counter_dlg = {"H.225 Messages and Message Reasons", "h225,counter", h225counter_init, -1};

void
register_tap_listener_h225counter(void)
{
	register_ethereal_tap("h225,counter", h225counter_init);
	register_generic_tap_menu_item("ITU-T H.225...", 10,
	    &(h225_counter_dlg));
}