From Florent.Drouin@alcatel.fr:
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 3 Oct 2006 22:12:47 +0000 (22:12 +0000)
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 3 Oct 2006 22:12:47 +0000 (22:12 +0000)
Please find two new TAP for Camel Statistics.
The first one updates  counters related to camel operations. It is located in the GSM submenu. The second one , named Camel Service Response Time, gives the time ellapsed between a couple of camel specifics operations. (For example InitialDP/Continue or InitialDP GPRS/Continue GPRS). With Wireshark, you can have the Min/Max/Mean delay time for your traces files, and with Tshark, you have the additional information for percentile (1%,95% 99% etc )

To enable the use of the Camel statistics, you have 2 new parameters in the preferences,
- SRT, enable the service Response Time calculation.
- persistentSRT, keep the data in a context, even after the  camel session has been closed. This is mandatory with Wireshark, to have a clean display of the stats.

Only the new files checked in for now because of include problems.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@19420 f5534014-38df-0310-8fa8-9805f1628bb7

epan/camel-persistentdata.c [new file with mode: 0644]
epan/camel-persistentdata.h [new file with mode: 0644]
gtk/camel_counter.c [new file with mode: 0644]
gtk/camel_srt.c [new file with mode: 0644]
tap-camelcounter.c [new file with mode: 0644]
tap-camelsrt.c [new file with mode: 0644]

diff --git a/epan/camel-persistentdata.c b/epan/camel-persistentdata.c
new file mode 100644 (file)
index 0000000..ff3c06b
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+ * camel-persistentdata.c
+ * Source for lists and hash tables used in wireshark's camel dissector
+ * for calculation of delays in camel calls
+ * Copyright 2006 Florent Drouin
+ *
+ * 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
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <epan/emem.h>
+#include "epan/packet.h"
+#include "epan/conversation.h"
+#include "epan/camel-persistentdata.h"
+#include "epan/dissectors/packet-tcap.h"
+#include "epan/dissectors/packet-mtp3.h"
+
+static gint camelsrt_call_equal(gconstpointer k1, gconstpointer k2);
+static guint camelsrt_call_hash(gconstpointer k);
+static struct camelsrt_call_t * find_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key,
+                                                  packet_info *pinfo);
+static struct camelsrt_call_t * new_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key,
+                                                 packet_info *pinfo);
+
+static void update_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call,
+                                packet_info *pinfo,
+                                guint msg_category _U_);
+
+static struct camelsrt_call_t * append_camelsrt_call(struct camelsrt_call_t * prev_call,
+                                                    packet_info *pinfo);
+
+static void camelsrt_begin_call_matching(tvbuff_t *tvb,
+                                        packet_info * pinfo _U_,
+                                        proto_tree *tree,
+                                        struct camelsrt_info_t * p_camelsrt_info);
+
+static void camelsrt_request_call_matching(tvbuff_t *tvb,
+                                          packet_info * pinfo _U_,
+                                          proto_tree *tree,
+                                          struct camelsrt_info_t * p_camelsrt_info,
+                                          guint srt_type);
+
+static void camelsrt_report_call_matching(tvbuff_t *tvb,
+                                         packet_info * pinfo _U_,
+                                         proto_tree *tree,
+                                         struct camelsrt_info_t * p_camelsrt_info,
+                                         guint srt_type);
+
+static void camelsrt_close_call_matching(tvbuff_t *tvb,
+                                        packet_info * pinfo _U_,
+                                        proto_tree *tree,
+                                        struct camelsrt_info_t * p_camelsrt_info);
+
+static void camelsrt_display_DeltaTime(proto_tree *tree,
+                                      tvbuff_t *tvb,
+                                      nstime_t* value_ptr,
+                                      guint category);
+
+static void raz_camelsrt_call (struct camelsrt_call_t * p_camelsrt_call);
+
+void camelsrt_tcap_matching(tvbuff_t *tvb,
+                           packet_info * pinfo _U_,
+                           proto_tree *tree,
+                           struct tcaphash_context_t * tcap_context);
+
+/* When several Camel components are received in a single TCAP message,
+   we have to use several buffers for the stored parameters
+   because else this data are erased during TAP dissector call */
+#define MAX_CAMEL_INSTANCE 10
+int camelsrt_global_current=0;
+struct camelsrt_info_t camelsrt_global_info[MAX_CAMEL_INSTANCE];
+
+/* Configuration parameters to enable or disable the Service Response Time */
+extern gboolean gcamel_HandleSRT;
+gboolean gcamel_PersistentSRT=FALSE;
+gboolean gcamel_DisplaySRT=FALSE;
+gboolean gcamel_StatSRT=FALSE;
+
+extern int camel_tap;
+
+extern int hf_camelsrt_SessionId;
+extern int hf_camelsrt_RequestNumber;
+extern int hf_camelsrt_Duplicate;
+extern int hf_camelsrt_RequestFrame;
+extern int hf_camelsrt_ResponseFrame;
+extern int hf_camelsrt_DeltaTime;
+extern int hf_camelsrt_SessionTime;
+extern int hf_camelsrt_DeltaTime31;
+extern int hf_camelsrt_DeltaTime75;
+extern int hf_camelsrt_DeltaTime65;
+extern int hf_camelsrt_DeltaTime22;
+extern int hf_camelsrt_DeltaTime35;
+extern int hf_camelsrt_DeltaTime80;
+
+/* Global hash tables*/
+static GHashTable *srt_calls = NULL;
+guint32 camelsrt_global_SessionId=1;
+
+/*
+ * DEBUG fonctions
+ */
+
+#undef DEBUG_CAMELSRT
+/* #define DEBUG_CAMELSRT */
+
+#ifdef DEBUG_CAMELSRT
+#include <stdio.h>
+#include <stdarg.h>
+static unsigned debug_level = 99;
+
+static void dbg(unsigned  level, char* fmt, ...) {
+  va_list ap;
+  
+  if (level > debug_level) return;
+  va_start(ap,fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+}
+#endif
+
+/*
+ * Functions needed for Hash-Table
+ */
+
+/* compare 2 keys */
+static gint camelsrt_call_equal(gconstpointer k1, gconstpointer k2)
+{
+  const struct camelsrt_call_info_key_t * key1 = (const struct camelsrt_call_info_key_t *) k1;
+  const struct camelsrt_call_info_key_t * key2 = (const struct camelsrt_call_info_key_t *) k2;
+  
+  return (key1->SessionIdKey == key2->SessionIdKey) ;
+}
+
+/* calculate a hash key */
+static guint camelsrt_call_hash(gconstpointer k)
+{
+  const struct camelsrt_call_info_key_t * key = (const struct camelsrt_call_info_key_t *) k;
+  return key->SessionIdKey;
+}
+
+/* 
+ * Find the dialog by Key and Time 
+ */
+static struct camelsrt_call_t * find_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key,
+                                                  packet_info *pinfo)
+{
+  struct camelsrt_call_t * p_camelsrt_call = NULL;
+  p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, p_camelsrt_call_key);
+
+  if(p_camelsrt_call) {
+#ifdef DEBUG_CAMELSRT
+    dbg(10,"D%d ", p_camelsrt_call->session_id);
+#endif
+  } else {
+#ifdef DEBUG_CAMELSRT
+    dbg(23,"Not in hash ");
+#endif  
+  }
+
+  return p_camelsrt_call;
+}
+
+/*
+ * New record to create, to identify a new transaction 
+ */
+static struct camelsrt_call_t * new_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key,
+                                                 packet_info *pinfo)
+  
+{
+  struct camelsrt_call_info_key_t * p_new_camelsrt_call_key;
+  struct camelsrt_call_t * p_new_camelsrt_call = NULL;
+  
+  /* Register the transaction in the hash table 
+     with the tcap transaction Id as main Key
+     Once created, this entry will be updated later */
+
+  p_new_camelsrt_call_key = se_alloc(sizeof(struct camelsrt_call_info_key_t));
+  p_new_camelsrt_call_key->SessionIdKey = p_camelsrt_call_key->SessionIdKey;
+  p_new_camelsrt_call = se_alloc(sizeof(struct camelsrt_call_t));
+  raz_camelsrt_call(p_new_camelsrt_call);
+  p_new_camelsrt_call->session_id = camelsrt_global_SessionId++;
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"D%d ", p_new_camelsrt_call->session_id);
+#endif
+  /* store it */
+  g_hash_table_insert(srt_calls, p_new_camelsrt_call_key, p_new_camelsrt_call);
+  return p_new_camelsrt_call;
+}
+
+/* 
+ * Update a record with the data of the Request 
+ */
+static void update_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call,
+                                packet_info *pinfo,
+                                guint msg_category _U_)
+{
+  p_camelsrt_call->category[msg_category].req_num = pinfo->fd->num;
+  p_camelsrt_call->category[msg_category].rsp_num = 0;
+  p_camelsrt_call->category[msg_category].responded = FALSE;
+  p_camelsrt_call->category[msg_category].req_time = pinfo->fd->abs_ts;
+}
+
+
+/*
+ * Routine called when the TAP is initialized.
+ * so hash table are (re)created
+ */
+void camelsrt_init_routine(void)
+{
+
+  /* free hash-tables and mem_chunks for SRT */
+  if (srt_calls != NULL) {
+#ifdef DEBUG_CAMELSRT
+    dbg(16,"Destroy hash ");
+#endif
+    g_hash_table_destroy(srt_calls);
+  }
+  
+  /* create new hash-tables and mem_chunks for SRT */
+  srt_calls = g_hash_table_new(camelsrt_call_hash, camelsrt_call_equal);
+#ifdef DEBUG_CAMELSRT
+  dbg(16,"Create hash ");
+#endif
+  /* Reset the session counter */
+  camelsrt_global_SessionId=1;
+
+  /* The Display of SRT is enable 
+   * 1) For wireshark only if Persistent Stat is enable
+   * 2) For Tshark, if the SRT handling is enable
+   */
+  gcamel_DisplaySRT=gcamel_PersistentSRT || gcamel_HandleSRT&gcamel_StatSRT;
+}
+
+/*
+ * Service Response Time analyze, called just after the camel dissector
+ * According to the camel operation, we 
+ * - open/close a context for the camel session
+ * - look for a request, or look for the corresponding response 
+ */
+void camelsrt_call_matching(tvbuff_t *tvb,
+                           packet_info * pinfo _U_,
+                           proto_tree *tree,
+                           struct camelsrt_info_t * p_camelsrt_info)
+{ 
+
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"tcap_session #%d ", p_camelsrt_info->tcap_session_id);
+#endif
+  
+  switch (p_camelsrt_info->opcode) {
+
+  case 0:  /*InitialDP*/
+    camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_VOICE_INITIALDP);
+    break;
+  case 60: /*InitialDPSMS*/
+    camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_SMS_INITIALDP); 
+    break;
+  case 78: /*InitialDPGPRS*/
+    camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_GPRS_INITIALDP); 
+    break;
+
+  case 23: /*RequestReportBCSMEvent*/
+    break;
+
+  case 63: /*RequestReportSMSEvent*/
+    break;
+
+  case 81: /*RequestReportGPRSEvent*/
+    break;
+
+  case 24: /*EventReportBCSMEvent*/
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_VOICE_DISC );
+    break;
+    
+  case 64: /*EventReportSMS*/
+    /* Session has been explicity closed without TC_END */
+    camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    tcapsrt_close(p_camelsrt_info->tcap_context, pinfo);
+    break;
+    
+  case 80: /*EventReportGPRS*/
+    camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_GPRS_REPORT);
+    break;
+    
+  case 35: /*ApplyCharging*/
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_VOICE_ACR1 ); 
+    break;
+    
+  case 71: /*ApplyChargingGPRS*/
+    break;
+    
+  case 36: /*ApplyChargingReport*/
+    camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                  CAMELSRT_VOICE_ACR1 );
+    break;
+    
+  case 72: /*ApplyChargingReportGPRS*/
+    break;
+    
+  case 31: /*Continue*/
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_VOICE_INITIALDP);
+    break;
+  case 65: /*ContinueSMS*/
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_SMS_INITIALDP);
+    break;
+  case 75: /*ContinueGPRS*/
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_GPRS_INITIALDP);
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_GPRS_REPORT);
+    break;
+
+  case 22: /*ReleaseCall*/
+    camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
+                                 CAMELSRT_VOICE_DISC);
+    /* Session has been closed by Network */
+    camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    break;
+
+  case 66: /*ReleaseSMS*/
+    /* Session has been closed by Network */
+    camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); 
+    tcapsrt_close(p_camelsrt_info->tcap_context,pinfo);
+    break;
+
+  case 79: /*ReleaseGPRS*/
+    /* Session has been closed by Network */
+    camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    break;
+  } /* switch opcode */
+}
+
+/*
+ * Callback function for the TCAP dissector
+ * This callback function is used to inform the camel layer, that the session 
+ * has been Closed or Aborted by a TCAP message without Camel component
+ * So, we can close the context for camel session, and update the stats.
+ */
+void camelsrt_tcap_matching(tvbuff_t *tvb,
+                           packet_info * pinfo _U_,
+                           proto_tree *tree,
+                           struct tcaphash_context_t * p_tcap_context)
+{  
+  struct camelsrt_info_t * p_camelsrt_info;
+  
+#ifdef DEBUG_CAMELSRT
+  dbg(11,"Camel_CallBack ");
+#endif
+  p_camelsrt_info=camelsrt_razinfo();
+  
+  p_camelsrt_info->tcap_context=p_tcap_context; 
+  if (p_tcap_context) {
+#ifdef DEBUG_CAMELSRT
+    dbg(11,"Close TCAP ");
+#endif
+    p_camelsrt_info->tcap_session_id = p_tcap_context->session_id;
+    camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info);
+    tap_queue_packet(camel_tap, pinfo, p_camelsrt_info);
+  }
+}
+
+
+/* 
+ * Create the record identifiying the Camel session
+ * As the Tcap session id given by the TCAP dissector is uniq, it will be
+ * used as main key.
+ */
+static void camelsrt_begin_call_matching(tvbuff_t *tvb,
+                                        packet_info * pinfo _U_,
+                                        proto_tree *tree,
+                                        struct camelsrt_info_t * p_camelsrt_info)
+{
+  struct camelsrt_call_t * p_camelsrt_call;
+  struct camelsrt_call_info_key_t camelsrt_call_key;
+
+  p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
+  
+  /* prepare the key data */  
+  camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
+
+  /* look up the request */
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"\n Session begin #%d\n", pinfo->fd->num);
+  dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
+#endif
+  p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, &camelsrt_call_key);
+  if (p_camelsrt_call) {
+    /* We have seen this request before -> do nothing */
+#ifdef DEBUG_CAMELSRT
+    dbg(22,"Already seen ");
+#endif
+  } else { /* p_camelsrt_call has not been found */
+#ifdef DEBUG_CAMELSRT
+    dbg(10,"New key %lu ",camelsrt_call_key.SessionIdKey);
+#endif
+    p_camelsrt_call = new_camelsrt_call(&camelsrt_call_key, pinfo); 
+    p_camelsrt_call->tcap_context=p_camelsrt_info->tcap_context;
+    update_camelsrt_call(p_camelsrt_call, pinfo,CAMELSRT_SESSION);
+
+#ifdef DEBUG_CAMELSRT
+    dbg(11,"Update Callback ");
+#endif
+    p_camelsrt_call->tcap_context->callback=camelsrt_tcap_matching;
+  }
+}
+  
+/*
+ * Register the request, and try to find the response
+ *
+ */
+static void camelsrt_request_call_matching(tvbuff_t *tvb,
+                                          packet_info * pinfo _U_,
+                                          proto_tree *tree,
+                                          struct camelsrt_info_t * p_camelsrt_info,
+                                          guint srt_type )
+{
+  struct camelsrt_call_t * p_camelsrt_call;
+  struct camelsrt_call_info_key_t camelsrt_call_key;
+  proto_item *ti;
+  
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"\n %s #%d\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num);
+#endif 
+
+  /* look only for matching request, if matching conversation is available. */
+  camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
+
+#ifdef DEBUG_CAMELSRT
+  dbg(11,"Search key %lu ", camelsrt_call_key.SessionIdKey);
+#endif
+  p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo);
+  if(p_camelsrt_call) {
+#ifdef DEBUG_CAMELSRT
+    dbg(12,"Found ");
+#endif 
+    if (gcamel_DisplaySRT)
+      proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
+
+
+    /* Hmm.. As there are several slices ApplyChargingReport/ApplyCharging
+     * we will prepare the measurement for 3 slices with 3 categories */
+    if (srt_type==CAMELSRT_VOICE_ACR1) { 
+      if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num == 0) {
+       srt_type=CAMELSRT_VOICE_ACR1;
+      } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num == 0) 
+                  && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0)
+                  && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num < pinfo->fd->num) ) {
+       srt_type=CAMELSRT_VOICE_ACR2;
+      } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num == 0)
+                  && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0)
+                  && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num < pinfo->fd->num) ) {
+       srt_type=CAMELSRT_VOICE_ACR3;
+      } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
+                && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num > pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR1;
+      } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0
+                  && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num > pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR2;
+      } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
+                 && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num > pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR3;
+      }
+#ifdef DEBUG_CAMELSRT
+      dbg(70,"Request ACR %u ",srt_type); 
+      dbg(70,"ACR1 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num);
+      dbg(70,"ACR2 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num);
+      dbg(70,"ACR3 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num);
+#endif
+    } /* not ACR */
+    p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
+
+    
+    if (p_camelsrt_call->category[srt_type].req_num == 0) { 
+      /* We have not yet seen a request to that call, so this must be the first request
+        remember its frame number. */ 
+#ifdef DEBUG_CAMELSRT
+      dbg(5,"Set reqlink #%d ", pinfo->fd->num);
+#endif
+      update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
+    } else {
+      /* We have seen a request to this call - but was it *this* request? */
+      if (p_camelsrt_call->category[srt_type].req_num != pinfo->fd->num) {
+       
+       if (srt_type!=CAMELSRT_VOICE_DISC) { 
+         /* No, so it's a duplicate resquest. Mark it as such. */ 
+#ifdef DEBUG_CAMELSRT
+         dbg(21,"Display_duplicate with req %d ", p_camelsrt_call->category[srt_type].req_num);
+#endif
+         p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE;
+         if (gcamel_DisplaySRT) 
+           proto_tree_add_uint_hidden(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
+
+       } else {
+         /* Ignore duplicate frame */
+         if (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) {
+           p_camelsrt_call->category[srt_type].req_num = pinfo->fd->num;
+#ifdef DEBUG_CAMELSRT
+           dbg(5,"DISC Set reqlink #%d ", pinfo->fd->num);
+#endif
+           update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
+         } /* greater frame */
+       } /* DISC */
+      } /* req_num already seen */
+    } /* req_num != 0 */
+    
+      /* add link to response frame, if available */
+    if ( gcamel_DisplaySRT &&
+        (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
+        (p_camelsrt_call->category[srt_type].req_num != 0) &&
+        (p_camelsrt_call->category[srt_type].req_num == pinfo->fd->num) ) {
+#ifdef DEBUG_CAMELSRT
+      dbg(20,"Display_framersplink %d ",p_camelsrt_call->category[srt_type].rsp_num);
+#endif
+      ti = proto_tree_add_uint_format(tree, hf_camelsrt_RequestFrame, tvb, 0, 0, 
+                                     p_camelsrt_call->category[srt_type].rsp_num,
+                                     "Linked response %s in frame %u", 
+                                     val_to_str(srt_type, camelSRTtype_naming, "Unk"),
+                                     p_camelsrt_call->category[srt_type].rsp_num);
+      PROTO_ITEM_SET_GENERATED(ti);
+    } /* frame valid */
+  }/* call reference */
+}
+
+
+/*
+ * Check if the received message is a response to a previous request
+ * registered is the camel session context.
+ */
+static void camelsrt_report_call_matching(tvbuff_t *tvb,
+                                         packet_info * pinfo _U_,
+                                         proto_tree *tree,
+                                         struct camelsrt_info_t * p_camelsrt_info,
+                                         guint srt_type )
+{
+  struct camelsrt_call_t * p_camelsrt_call;
+  struct camelsrt_call_info_key_t camelsrt_call_key;
+  nstime_t delta;
+  proto_item *ti;
+
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"\n %s #%d\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num);
+#endif  
+  camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
+  /* look only for matching request, if matching conversation is available. */
+
+#ifdef DEBUG_CAMELSRT
+  dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
+#endif
+  p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo);
+  if(p_camelsrt_call) {
+#ifdef DEBUG_CAMELSRT
+    dbg(12,"Found, req=%d ",p_camelsrt_call->category[srt_type].req_num);
+#endif
+    if ( gcamel_DisplaySRT )
+      proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
+
+    if (srt_type==CAMELSRT_VOICE_ACR1) { 
+      if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num != 0
+         && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num < pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR1;
+      } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num != 0
+                  && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num < pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR2;
+      } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num != 0
+                 && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num < pinfo->fd->num) {
+       srt_type=CAMELSRT_VOICE_ACR1;
+      }
+#ifdef DEBUG_CAMELSRT
+      dbg(70,"Report ACR %u ",srt_type);
+#endif
+    } /* not ACR */
+    p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
+
+    if (p_camelsrt_call->category[srt_type].rsp_num == 0) {
+      if  ( (p_camelsrt_call->category[srt_type].req_num != 0)
+           && (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) ){
+       /* We have not yet seen a response to that call, so this must be the first response;
+          remember its frame number only if response comes after request */ 
+#ifdef DEBUG_CAMELSRT
+       dbg(14,"Set reslink #%d req %d ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num);
+#endif
+       p_camelsrt_call->category[srt_type].rsp_num = pinfo->fd->num;
+
+      } else {
+#ifdef DEBUG_CAMELSRT
+       dbg(2,"badreslink #%d req %u ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num);
+#endif
+      } /* req_num != 0 */
+    } else { /* rsp_num != 0 */
+      /* We have seen a response to this call - but was it *this* response? */
+      if (p_camelsrt_call->category[srt_type].rsp_num != pinfo->fd->num) {
+       /* No, so it's a duplicate response. Mark it as such. */
+#ifdef DEBUG_CAMELSRT
+       dbg(21,"Display_duplicate rsp=%d ", p_camelsrt_call->category[srt_type].rsp_num);
+#endif
+       p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE; 
+       if ( gcamel_DisplaySRT )
+         proto_tree_add_uint_hidden(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
+      }
+    } /* rsp_num != 0 */
+    
+    if ( (p_camelsrt_call->category[srt_type].req_num != 0) &&
+        (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
+        (p_camelsrt_call->category[srt_type].rsp_num == pinfo->fd->num) ) {
+      
+      p_camelsrt_call->category[srt_type].responded = TRUE;
+      p_camelsrt_info->msginfo[srt_type].request_available = TRUE;
+#ifdef DEBUG_CAMELSRT
+      dbg(20,"Display_frameReqlink %d ",p_camelsrt_call->category[srt_type].req_num);
+#endif
+      /* Indicate the frame to which this is a reply. */
+      if ( gcamel_DisplaySRT ) {
+       ti = proto_tree_add_uint_format(tree, hf_camelsrt_ResponseFrame, tvb, 0, 0,
+                                       p_camelsrt_call->category[srt_type].req_num,
+                                       "Linked request %s in frame %u",
+                                       val_to_str(srt_type, camelSRTtype_naming, "Unk"),
+                                       p_camelsrt_call->category[srt_type].req_num);
+       PROTO_ITEM_SET_GENERATED(ti);
+      }
+      /* Calculate Service Response Time */
+      nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[srt_type].req_time);
+      
+      p_camelsrt_info->msginfo[srt_type].is_delta_time = TRUE;
+      p_camelsrt_info->msginfo[srt_type].delta_time = delta; /* give it to tap */
+      p_camelsrt_info->msginfo[srt_type].req_time = p_camelsrt_call->category[srt_type].req_time;
+      
+      /* display Service Response Time and make it filterable */
+      camelsrt_display_DeltaTime(tree, tvb, &delta, srt_type);
+      
+    } /*req_num != 0 && not duplicate */
+  } /* call reference found */
+}
+
+/*
+ * Update the Camel session info, and close the session.
+ * Then remove the associated context, if we do not have persistentSRT enable
+ */
+static void camelsrt_close_call_matching(tvbuff_t *tvb,
+                                        packet_info * pinfo _U_,
+                                        proto_tree *tree,
+                                        struct camelsrt_info_t * p_camelsrt_info)
+{
+  struct camelsrt_call_t * p_camelsrt_call;
+  struct camelsrt_call_info_key_t camelsrt_call_key;
+  nstime_t delta;
+
+  p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
+#ifdef DEBUG_CAMELSRT
+  dbg(10,"\n Session end #%d\n", pinfo->fd->num);
+#endif
+  /* look only for matching request, if matching conversation is available. */
+  camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
+
+#ifdef DEBUG_CAMELSRT
+  dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
+#endif
+  p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo);
+  if(p_camelsrt_call) {
+#ifdef DEBUG_CAMELSRT
+    dbg(12,"Found ");
+#endif 
+    /* Calculate Service Response Time */
+    nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[CAMELSRT_SESSION].req_time);
+    p_camelsrt_call->category[CAMELSRT_SESSION].responded = TRUE;
+    p_camelsrt_info->msginfo[CAMELSRT_SESSION].request_available = TRUE;      
+    p_camelsrt_info->msginfo[CAMELSRT_SESSION].is_delta_time = TRUE;
+    p_camelsrt_info->msginfo[CAMELSRT_SESSION].delta_time = delta; /* give it to tap */
+    p_camelsrt_info->msginfo[CAMELSRT_SESSION].req_time = p_camelsrt_call->category[CAMELSRT_SESSION].req_time;
+      
+    if ( !gcamel_PersistentSRT ) {
+      g_hash_table_remove(srt_calls, &camelsrt_call_key);
+#ifdef DEBUG_CAMELSRT
+      dbg(20,"remove hash ");
+#endif
+    } else {
+#ifdef DEBUG_CAMELSRT
+      dbg(20,"keep hash ");
+#endif
+    }
+  } /* call reference found */
+}
+
+/*
+ * Display the delta time between two messages in a field corresponding 
+ * to the category (hf_camelsrt_DeltaTimexx).
+ */
+static void camelsrt_display_DeltaTime(proto_tree *tree,
+                                      tvbuff_t *tvb,
+                                      nstime_t* value_ptr,
+                                      guint category)
+{ 
+  proto_item *ti;
+  
+  if ( gcamel_DisplaySRT ) {
+    switch(category) {
+    case CAMELSRT_VOICE_INITIALDP:
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime31, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+      
+    case CAMELSRT_VOICE_ACR1:
+    case CAMELSRT_VOICE_ACR2:
+    case CAMELSRT_VOICE_ACR3: 
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime22, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+   
+    case CAMELSRT_VOICE_DISC:
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime35, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+    
+    case CAMELSRT_GPRS_INITIALDP:
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime75, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+   
+    case CAMELSRT_GPRS_REPORT:
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime80, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+    
+    case CAMELSRT_SMS_INITIALDP: 
+      ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime65, tvb, 0, 0, value_ptr);
+      PROTO_ITEM_SET_GENERATED(ti);
+      break;
+
+    default:
+      break;
+    }
+  }
+}
+
+/*
+ * Initialize the Message Info used by the main dissector
+ * Data are linked to a TCAP transaction 
+ */
+struct camelsrt_info_t * camelsrt_razinfo(void)
+{
+  struct camelsrt_info_t * p_camelsrt_info ;
+
+  /* Global buffer for packet extraction */
+  camelsrt_global_current++;
+  if(camelsrt_global_current==MAX_CAMEL_INSTANCE){
+    camelsrt_global_current=0;
+  }
+  
+  p_camelsrt_info=&camelsrt_global_info[camelsrt_global_current];
+  memset(p_camelsrt_info,0,sizeof(struct camelsrt_info_t));  
+  
+  p_camelsrt_info->opcode=255; 
+  
+  return p_camelsrt_info;
+}
+
+/*
+ * Initialize the data per call for the Service Response Time Statistics
+ * Data are linked to a Camel operation in a TCAP transaction
+ */
+static void raz_camelsrt_call (struct camelsrt_call_t * p_camelsrt_call)
+{  
+  memset(p_camelsrt_call,0,sizeof(struct camelsrt_call_t));
+}
diff --git a/epan/camel-persistentdata.h b/epan/camel-persistentdata.h
new file mode 100644 (file)
index 0000000..4414788
--- /dev/null
@@ -0,0 +1,126 @@
+/*\r
+ * camel-persistentdata.h\r
+ * Definitions for lists and hash tables used in wireshark's camel dissector\r
+ * for calculation of delays in camel-transactions\r
+ * Copyright 2006 Florent Drouin\r
+ *\r
+ * Wireshark - Network traffic analyzer\r
+ * By Gerald Combs <gerald@wireshark.org>\r
+ * Copyright 1998 Gerald Combs\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ */\r
+\r
+#ifndef __camelsrt_HASH__\r
+#define __camelsrt_HASH__\r
+\r
+#include "epan/packet.h"\r
+#include "epan/conversation.h"\r
+#include "epan/dissectors/packet-camel.h"\r
+#include "epan/tcap-persistentdata.h"\r
+\r
+#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */\r
+/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent\r
+   is a category, we want to measure the delay between the two messages */ \r
+\r
+#define CAMELSRT_SESSION 1\r
+\r
+#define CAMELSRT_VOICE_INITIALDP 2\r
+#define CAMELSRT_VOICE_ACR1 3\r
+#define CAMELSRT_VOICE_ACR2 4\r
+#define CAMELSRT_VOICE_ACR3 5\r
+#define CAMELSRT_VOICE_DISC 6\r
+\r
+#define CAMELSRT_GPRS_INITIALDP 7\r
+#define CAMELSRT_GPRS_REPORT 8\r
+\r
+#define CAMELSRT_SMS_INITIALDP 9\r
+\r
+static const value_string  camelSRTtype_naming[]= {\r
+  { CAMELSRT_SESSION,         "TCAP_Session" },\r
+  { CAMELSRT_VOICE_INITIALDP, "InialDP/Continue" },\r
+  { CAMELSRT_VOICE_ACR1,      "Slice1_ACR/ACH" }, \r
+  { CAMELSRT_VOICE_ACR2,      "Slice2_ACR/ACH" },\r
+  { CAMELSRT_VOICE_ACR3,      "Slice3_ACR/ACH" },\r
+  { CAMELSRT_VOICE_DISC,      "EvtRepBSCM/Release" },\r
+  { CAMELSRT_SMS_INITIALDP,   "InitialDP/ContinueSMS" },\r
+  { CAMELSRT_GPRS_INITIALDP,  "InitialDP/ContinueGPRS" },\r
+  { CAMELSRT_GPRS_REPORT,     "EvtRepGPRS/ContinueGPRS" },\r
+  { 0,NULL}\r
+};\r
+\r
+/* If we have a request message and its response,\r
+   (eg: ApplyCharging, ApplyChargingReport)\r
+   the frames numbers are stored in this structure */ \r
+\r
+struct camelsrt_category_t {\r
+  guint32 req_num;     /* frame number request seen */\r
+  guint32 rsp_num;     /* frame number response seen */\r
+  nstime_t req_time;   /* arrival time of request */\r
+  gboolean responded;  /* true, if request has been responded */\r
+};\r
+\r
+/* List of stored parameters for a Camel dialogue\r
+   All this parameters are linked to the hash table key below (use of Tid)\r
+   In case of same Tid reused, the Camel parameters are chained.\r
+   The right dialogue will be identified with the arrival time of the InitialDP */\r
+\r
+struct camelsrt_call_t {\r
+  guint32 session_id;    /* Identify the session, with an internal number */\r
+  struct tcaphash_context_t * tcap_context;\r
+  struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY];\r
+};\r
+\r
+\r
+/* The Key for the hash table is the TCAP origine transaction identifier \r
+   of the TC_BEGIN containing the InitialDP */\r
+\r
+struct camelsrt_call_info_key_t {\r
+  guint32 SessionIdKey;\r
+};\r
+\r
+/* Info for a couple of messages (or category)\r
+   The request must be available, not duplicated, \r
+   and once the corresponding response received, \r
+   we can deduce the Delta Time between Request/response */\r
+\r
+struct camelsrt_msginfo_t {\r
+  gboolean request_available;\r
+  gboolean is_duplicate;\r
+  gboolean is_delta_time;\r
+  nstime_t req_time;\r
+  nstime_t delta_time;\r
+};\r
+\r
+/* List of infos to store for the analyse */\r
+\r
+struct camelsrt_info_t { \r
+  guint32 tcap_session_id;\r
+  void * tcap_context;\r
+  guint8 opcode; /* operation code of message received */\r
+  guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */\r
+  struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY];\r
+};\r
+\r
+void camelsrt_init_routine(void);\r
+\r
+struct camelsrt_info_t * camelsrt_razinfo(void);\r
+\r
+void camelsrt_call_matching(tvbuff_t *tvb,\r
+                           packet_info * pinfo _U_,\r
+                           proto_tree *tree,\r
+                           struct camelsrt_info_t * p_camel_info);\r
+\r
+#endif /* __camelsrt_HASH__*/\r
diff --git a/gtk/camel_counter.c b/gtk/camel_counter.c
new file mode 100644 (file)
index 0000000..600eac0
--- /dev/null
@@ -0,0 +1,233 @@
+/* camel_counter.c
+ * camel message counter for Wireshark
+ * Copyright 2006 Florent Drouin (based on h225_counter.c from Lars Roland)
+ *
+ * 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 "register.h"
+#include "timestats.h"
+#include "simple_dialog.h"
+#include "file.h"
+#include "globals.h"
+#include "stat_menu.h"
+#include "tap_dfilter_dlg.h"
+
+#include "gtk/main.h"
+#include "gtk/dlg_utils.h"
+#include "gtk/gui_utils.h"
+#include "gtk/gui_stat_util.h"
+#include "gtk/compat_macros.h"
+#include "epan/camel-persistentdata.h"
+
+static void gtk_camelcounter_reset(void *phs);
+static int gtk_camelcounter_packet(void *phs,
+                                  packet_info *pinfo _U_,
+                                  epan_dissect_t *edt _U_, 
+                                  const void *phi);
+static void gtk_camelcounter_draw(void *phs);
+static void win_destroy_cb(GtkWindow *win _U_, gpointer data);
+static void gtk_camelcounter_init(const char *optarg, void *userdata _U_);
+void register_tap_listener_gtk_camelcounter(void);
+
+/* following values represent the size of their valuestring arrays */
+
+struct camelcounter_t {
+  GtkWidget *win;
+  GtkWidget *vbox;
+  char *filter;
+  GtkWidget *scrolled_window;
+  GtkCList *table;
+  guint32 camel_msg[camel_MAX_NUM_OPR_CODES];
+};
+
+static void gtk_camelcounter_reset(void *phs)
+{
+  struct camelcounter_t * p_counter= ( struct camelcounter_t *) phs;
+  int i;
+  
+  /* Erase Message Type count */
+  for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) {
+    p_counter->camel_msg[i]=0; 
+  }
+}
+
+
+/*
+ * If there is a valid camel operation, increase the value in the array of counter
+ */
+static int gtk_camelcounter_packet(void *phs,
+                                  packet_info *pinfo _U_,
+                                  epan_dissect_t *edt _U_, 
+                                  const void *phi)
+{
+  struct camelcounter_t * p_counter =(struct camelcounter_t *)phs;
+  const struct camelsrt_info_t * pi=phi;
+  if (pi->opcode != 255)
+    p_counter->camel_msg[pi->opcode]++;
+  
+  return 1;
+}
+
+static void gtk_camelcounter_draw(void *phs)
+{
+  struct camelcounter_t *p_counter=(struct camelcounter_t *)phs;
+  int i;
+  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 */
+  gtk_clist_clear(p_counter->table);
+  
+  for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) {
+    /* Message counter */
+    if(p_counter->camel_msg[i]!=0) {
+      g_snprintf(str[0], sizeof(char[256]), 
+                "Request %s", val_to_str(i,camel_opr_code_strings,"Unknown message "));
+      g_snprintf(str[1], sizeof(char[256]),
+                "%d", p_counter->camel_msg[i]);
+      gtk_clist_append(p_counter->table, str);
+    } 
+  } /* Message Type */
+  gtk_widget_show(GTK_WIDGET(p_counter->table));
+}
+
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
+{
+  struct camelcounter_t *hs=(struct camelcounter_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 gchar *titles[]={
+  "Message Type or Reason",
+  "Count" };
+
+static void gtk_camelcounter_init(const char *optarg, void *userdata _U_)
+{
+  struct camelcounter_t *p_camelcounter;
+  const char *filter=NULL; 
+  const char *emptyfilter=""; 
+  GString *error_string;
+  GtkWidget *bbox;
+  GtkWidget *close_bt;
+  
+  if(strncmp(optarg,"camel,counter,",14) == 0){
+    filter=optarg+14;
+  } else {
+    filter=NULL;
+  }
+  
+  p_camelcounter=g_malloc(sizeof(struct camelcounter_t));
+  p_camelcounter->filter=g_strdup(filter);
+  
+  gtk_camelcounter_reset(p_camelcounter);
+  
+  p_camelcounter->win=window_new(GTK_WINDOW_TOPLEVEL, "Ethereal: CAMEL counters");
+  gtk_window_set_default_size(GTK_WINDOW(p_camelcounter->win), 500, 300);
+  
+  p_camelcounter->vbox=gtk_vbox_new(FALSE, 3);
+  gtk_container_set_border_width(GTK_CONTAINER(p_camelcounter->vbox), 12);
+  
+  init_main_stat_window(p_camelcounter->win, p_camelcounter->vbox, "CAMEL Messages Counters", filter);
+  
+  /* init a scrolled window*/
+  p_camelcounter->scrolled_window = scrolled_window_new(NULL, NULL);
+
+  p_camelcounter->table = create_stat_table(p_camelcounter->scrolled_window, p_camelcounter->vbox, 2, titles);
+  
+  if (filter) {
+    error_string=register_tap_listener("CAMEL", p_camelcounter, filter,
+                                      gtk_camelcounter_reset,
+                                      gtk_camelcounter_packet,
+                                      gtk_camelcounter_draw);
+  } else {
+    error_string=register_tap_listener("CAMEL", p_camelcounter, emptyfilter,
+                                      gtk_camelcounter_reset,
+                                      gtk_camelcounter_packet,
+                                      gtk_camelcounter_draw);
+  }
+
+  if(error_string){
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
+    g_string_free(error_string, TRUE);
+    g_free(p_camelcounter);
+    return;
+  }
+
+  /* Button row. */
+  bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
+  gtk_box_pack_end(GTK_BOX(p_camelcounter->vbox), bbox, FALSE, FALSE, 0);
+
+  close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
+  window_set_cancel_button(p_camelcounter->win, close_bt, window_cancel_button_cb);
+
+  SIGNAL_CONNECT(p_camelcounter->win, "delete_event", window_delete_event_cb, NULL);
+  SIGNAL_CONNECT(p_camelcounter->win, "destroy", win_destroy_cb, p_camelcounter);
+
+  gtk_widget_show_all(p_camelcounter->win);
+  window_present(p_camelcounter->win);
+
+  cf_retap_packets(&cfile, FALSE);
+}
+
+static tap_dfilter_dlg camel_counter_dlg = {
+  "CAMEL Messages and Response Status",
+  "camel,counter",
+  gtk_camelcounter_init,
+  -1
+};
+
+void  /* Next line mandatory */
+register_tap_listener_gtk_camelcounter(void)
+{
+  register_dfilter_stat(&camel_counter_dlg, "GSM/CAMEL",
+                       REGISTER_STAT_GROUP_TELEPHONY);
+
+}
diff --git a/gtk/camel_srt.c b/gtk/camel_srt.c
new file mode 100644 (file)
index 0000000..fed4a8b
--- /dev/null
@@ -0,0 +1,248 @@
+/* camel_srt.c
+ * camel Service Response Time statistics for Wireshark
+ * Copyright 2006 Florent Drouin (based on h225_ras_srt.c from Lars Roland)
+ *
+ * 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 "register.h"
+#include "timestats.h"
+#include "simple_dialog.h"
+#include "file.h"
+#include "globals.h"
+#include "stat_menu.h"
+#include "tap_dfilter_dlg.h"
+
+#include "gtk/main.h"
+#include "gtk/dlg_utils.h"
+#include "gtk/gui_utils.h"
+#include "gtk/gui_stat_util.h"
+#include "gtk/compat_macros.h"
+#include "gtk/service_response_time_table.h"
+
+#include "epan/camel-persistentdata.h"
+
+/* used to keep track of the statistics for an entire program interface */
+struct camelsrt_t {
+  GtkWidget *win;
+  srt_stat_table camel_srt_table;
+};
+
+static void camelsrt_set_title(struct camelsrt_t * p_camelsrt);
+static void camelsrt_reset(void *phs);
+static int camelsrt_packet(void *phs, 
+                          packet_info *pinfo _U_, 
+                          epan_dissect_t *edt _U_,
+                          const void *phi);
+
+static void camelsrt_draw(void *phs);
+static void win_destroy_cb(GtkWindow *win _U_, gpointer data);
+static void gtk_camelsrt_init(const char *optarg, void *userdata _U_);
+void register_tap_listener_gtk_camelsrt(void);
+
+/*
+ *
+ */
+static void camelsrt_set_title(struct camelsrt_t * p_camelsrt)
+{
+  char * title;
+  title = g_strdup_printf("CAMEL Service Response Time statistics: %s",
+                         cf_get_display_name(&cfile));
+  gtk_window_set_title(GTK_WINDOW(p_camelsrt->win), title);
+  g_free(title);
+}
+
+static void camelsrt_reset(void *phs)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  reset_srt_table_data(&hs->camel_srt_table);
+  camelsrt_set_title(hs); 
+}
+
+/*
+ * Count the delta time between Request and Response
+ * As we can make several measurement per message, we use a boolean array for the category
+ * Then, if the measurement is provided, check if it is valid, and update the table 
+ */
+static int camelsrt_packet(void *phs, 
+                          packet_info *pinfo _U_, 
+                          epan_dissect_t *edt _U_,
+                          const void *phi)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  const struct camelsrt_info_t * pi=phi;
+  int i;
+
+  for (i=1; i<NB_CAMELSRT_CATEGORY; i++) {
+    if ( pi->bool_msginfo[i] &&
+        pi->msginfo[i].is_delta_time 
+        && pi->msginfo[i].request_available
+        && !pi->msginfo[i].is_duplicate ) {
+      
+      add_srt_table_data(&hs->camel_srt_table, i, &pi->msginfo[i].req_time, pinfo);
+      
+    }
+  } /* category */
+  return 1;
+}
+
+
+static void camelsrt_draw(void *phs)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  draw_srt_table_data(&hs->camel_srt_table);
+}
+
+/*
+ * Routine for Display
+ */
+static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)data;
+  
+  protect_thread_critical_region();
+  remove_tap_listener(hs);
+  unprotect_thread_critical_region();
+   
+  free_srt_table_data(&hs->camel_srt_table);
+  g_free(hs);
+}
+
+static void gtk_camelsrt_init(const char *optarg, void *userdata _U_)
+{
+  struct camelsrt_t * p_camelsrt;
+  const char *filter=NULL; 
+  const char *emptyfilter="";
+
+  GtkWidget *cmd_label;
+  GtkWidget *main_label;
+  GtkWidget *filter_label;
+  char filter_string[256];
+  GString *error_string;
+  GtkWidget *vbox;
+  GtkWidget *bbox;
+  GtkWidget *close_bt;
+  int i;
+
+  if(strncmp(optarg,"camel,srt,",10) == 0){
+    filter=optarg+10;
+  } else {
+    filter=NULL;
+  }
+  
+  p_camelsrt=g_malloc(sizeof(struct camelsrt_t)); 
+
+  p_camelsrt->win=window_new(GTK_WINDOW_TOPLEVEL, "camel-srt");
+  gtk_window_set_default_size(GTK_WINDOW(p_camelsrt->win), 550, 400);
+  camelsrt_set_title(p_camelsrt);
+
+  vbox=gtk_vbox_new(FALSE, 3);
+  gtk_container_add(GTK_CONTAINER(p_camelsrt->win), vbox);
+  gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+  
+  main_label=gtk_label_new("CAMEL Service Response Time statistics");
+  gtk_box_pack_start(GTK_BOX(vbox), main_label, FALSE, FALSE, 0);
+  gtk_widget_show(main_label);
+
+  g_snprintf(filter_string,255,"Filter:%s",filter?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);
+
+  cmd_label=gtk_label_new("CAMEL Commands");
+  gtk_box_pack_start(GTK_BOX(vbox), cmd_label, FALSE, FALSE, 0);
+  gtk_widget_show(cmd_label);
+
+  /* We must display TOP LEVEL Widget before calling init_srt_table() */
+  gtk_widget_show_all(p_camelsrt->win);
+  
+  init_srt_table(&p_camelsrt->camel_srt_table, NB_CAMELSRT_CATEGORY, vbox, NULL); 
+  for(i=0 ;i<NB_CAMELSRT_CATEGORY; i++) {
+    init_srt_table_row(&p_camelsrt->camel_srt_table, i,
+                      val_to_str(i,camelSRTtype_naming,"Unknown"));
+  }
+
+  if (filter) {
+    error_string=register_tap_listener("CAMEL", 
+                                      p_camelsrt,
+                                      filter,
+                                      camelsrt_reset,
+                                      camelsrt_packet, 
+                                      camelsrt_draw);
+  } else {
+    error_string=register_tap_listener("CAMEL", 
+                                      p_camelsrt,
+                                      emptyfilter,
+                                      camelsrt_reset,
+                                      camelsrt_packet, 
+                                      camelsrt_draw);
+  }
+  
+    if(error_string){
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
+      g_string_free(error_string, TRUE);
+    g_free(p_camelsrt);
+    return;
+  }
+  
+  /* Button row. */
+  bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
+  gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+  
+  close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
+  window_set_cancel_button(p_camelsrt->win, close_bt, window_cancel_button_cb);
+  
+  SIGNAL_CONNECT(p_camelsrt->win, "delete_event", window_delete_event_cb, NULL);
+  SIGNAL_CONNECT(p_camelsrt->win, "destroy", win_destroy_cb, p_camelsrt);
+
+  gtk_widget_show_all(p_camelsrt->win);
+  window_present(p_camelsrt->win);
+  cf_retap_packets(&cfile, FALSE); 
+
+}
+
+static tap_dfilter_dlg camel_srt_dlg = {
+  "CAMEL Service Response Time",
+  "camel,srt",
+  gtk_camelsrt_init,
+  -1
+};
+
+void /* Next line mandatory */
+register_tap_listener_gtk_camelsrt(void)
+{
+  register_dfilter_stat(&camel_srt_dlg, "CAMEL",
+                       REGISTER_STAT_GROUP_RESPONSE_TIME);
+}
diff --git a/tap-camelcounter.c b/tap-camelcounter.c
new file mode 100644 (file)
index 0000000..b5ab177
--- /dev/null
@@ -0,0 +1,146 @@
+/* tap_camelcounter.c
+ * camel message counter for tshark
+ * Copyright 2006 Florent DROUIN
+ * This part of code is extracted from tap-h225counter.c from Lars Roland
+ *
+ * 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
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include "epan/tap.h"
+#include "epan/value_string.h"
+#include "register.h"
+#include "epan/stat_cmd_args.h"
+#include "epan/camel-persistentdata.h"
+
+void register_tap_listener_camelcounter(void);
+
+/* used to keep track of the statistics for an entire program interface */
+struct camelcounter_t {
+  char *filter; 
+  guint32 camel_msg[camel_MAX_NUM_OPR_CODES];
+};
+
+
+static void camelcounter_reset(void *phs)
+{
+  struct camelcounter_t * p_counter= ( struct camelcounter_t *) phs;
+  memset(p_counter,0,sizeof(struct camelcounter_t));
+}
+
+static int camelcounter_packet(void *phs,
+                              packet_info *pinfo _U_,
+                              epan_dissect_t *edt _U_, 
+                              const void *phi)
+{
+  struct camelcounter_t * p_counter =(struct camelcounter_t *)phs;
+  const struct camelsrt_info_t * pi=phi;
+  if (pi->opcode != 255)
+    p_counter->camel_msg[pi->opcode]++;
+  
+  return 1;
+}
+
+
+static void camelcounter_draw(void *phs)
+{
+  struct camelcounter_t * p_counter= (struct camelcounter_t *)phs;
+  int i;
+  printf("\n");
+  printf("CAMEL Message and Response Status Counter:\n");
+  printf("------------------------------------------\n");
+
+  for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) {
+    /* Message counter */
+    if(p_counter->camel_msg[i]!=0) {
+      printf("%30s ", val_to_str(i,camel_opr_code_strings,"Unknown message "));
+      printf("%6d\n", p_counter->camel_msg[i]);
+    } 
+  } /* Message Type */
+  printf("------------------------------------------\n");
+}
+
+static void camelcounter_init(const char *optarg, void* userdata _U_)
+{
+  struct camelcounter_t *p_camelcounter;
+  const char *filter=NULL;
+  const char *emptyfilter=""; 
+  GString *error_string;
+
+  if(!strncmp(optarg,"camel,counter,",13)){
+    filter=optarg+13;
+  } else {
+    filter=NULL;
+  }
+
+  p_camelcounter = g_malloc(sizeof(struct camelcounter_t));
+  if(filter){
+    p_camelcounter->filter=g_malloc(strlen(filter)+1);
+    strcpy(p_camelcounter->filter,filter);
+  } else {
+    p_camelcounter->filter=NULL;
+  }
+  
+  camelcounter_reset(p_camelcounter);
+
+  if (filter) {
+    error_string=register_tap_listener("CAMEL",
+                                      p_camelcounter,
+                                      filter,
+                                      NULL,
+                                      camelcounter_packet,
+                                      camelcounter_draw);
+  } else {
+    error_string=register_tap_listener("CAMEL",
+                                      p_camelcounter,
+                                      emptyfilter,
+                                      NULL,
+                                      camelcounter_packet,
+                                      camelcounter_draw);
+  }
+
+  if(error_string){
+    /* error, we failed to attach to the tap. clean up */
+    g_free(p_camelcounter->filter);
+    g_free(p_camelcounter);
+
+    fprintf(stderr, "tshark: Couldn't register camel,counter tap: %s\n",
+           error_string->str);
+    g_string_free(error_string, TRUE);
+    exit(1);
+  }
+}
+
+
+void  /* Next line mandatory */
+register_tap_listener_camelcounter(void)
+{
+  register_stat_cmd_arg("camel,counter", camelcounter_init, NULL);
+}
diff --git a/tap-camelsrt.c b/tap-camelsrt.c
new file mode 100644 (file)
index 0000000..2538702
--- /dev/null
@@ -0,0 +1,276 @@
+/* tap_camelsrt.c
+ * CAMEL Service Response Time statistics for tshark
+ * Copyright 2006 Florent Drouin (based on tap_h225rassrt.c from Lars Roland)
+ *
+ * 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
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "epan/packet_info.h"
+#include <epan/tap.h>
+#include "epan/value_string.h"
+#include "register.h"
+#include "epan/dissectors/packet-camel.h"
+#include "epan/camel-persistentdata.h"
+#include "timestats.h"
+#include "epan/stat_cmd_args.h"
+
+#undef  MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+void register_tap_listener_camelsrt(void);
+
+/* Save the the first NUM_RAS_STATS stats in the array to calculate percentile */
+#define NUM_RAS_STATS 500000
+
+/* Number of couple message Request/Response to analyze*/
+#define NB_CRITERIA 7
+
+/* used to keep track of the statistics for an entire program interface */
+struct camelsrt_t {
+  char *filter;
+  guint32 count[NB_CAMELSRT_CATEGORY];
+  timestat_t stats[NB_CAMELSRT_CATEGORY];
+  nstime_t delta_time[NB_CAMELSRT_CATEGORY][NUM_RAS_STATS];
+};
+
+/* Check if we have to inhibit the display or not */
+extern gboolean gcamel_StatSRT;
+extern gboolean gtcap_StatSRT;
+
+/* Reset the counter */
+static void camelsrt_reset(void *phs)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  memset(hs,0,sizeof(struct camelsrt_t));
+}
+
+
+static int camelsrt_packet(void *phs, 
+                          packet_info *pinfo _U_, 
+                          epan_dissect_t *edt _U_,
+                          const void *phi)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  const struct camelsrt_info_t * pi=phi;
+  int i;
+
+  for (i=0; i<NB_CAMELSRT_CATEGORY; i++) {
+    if (pi->bool_msginfo[i] &&
+       pi->msginfo[i].is_delta_time 
+       && pi->msginfo[i].request_available
+       && !pi->msginfo[i].is_duplicate ) {
+      
+      time_stat_update(&(hs->stats[i]),
+                      &(pi->msginfo[i].delta_time),
+                      pinfo);
+       
+      if (hs->count[i] < NUM_RAS_STATS) {
+       hs->delta_time[i][hs->count[i]++] 
+         = pi->msginfo[i].delta_time;
+      }
+    }
+  }
+  return 1;
+}
+
+
+static void camelsrt_draw(void *phs)
+{
+  struct camelsrt_t *hs=(struct camelsrt_t *)phs;
+  guint j,z;
+  guint32 li;
+  int somme,iteration=0;
+  timestat_t *rtd_temp;
+  double x,delay,delay_max,delay_min,delta;
+  double criteria[NB_CRITERIA]={ 5.0, 10.0, 75.0, 90.0, 95.0,99.0,99.90 };
+  double delay_criteria[NB_CRITERIA];
+
+  printf("\n");
+  printf("Camel Service Response Time (SRT) Statistics:\n");
+  printf("=================================================================================================\n");
+  printf("|        Category         | Measure |  Min SRT  |  Max SRT  |  Avg SRT  | Min frame | Max frame |\n");
+  printf("|-------------------------|---------|-----------|-----------|-----------|-----------|-----------|\n");
+  j=1;
+  printf("|%24s |%8u |%8.2f s |%8.2f s |%8.2f s |%10u |%10u |\n",
+        val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+        hs->stats[j].num,
+        nstime_to_sec(&(hs->stats[j].min)),
+        nstime_to_sec(&(hs->stats[j].max)),
+        get_average(&(hs->stats[j].tot),hs->stats[j].num)/1000.0,
+        hs->stats[j].min_num, 
+        hs->stats[j].max_num
+        );
+  for(j=2; j<NB_CAMELSRT_CATEGORY; j++) { 
+    if(hs->stats[j].num==0){ 
+      printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n",
+            val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+            0, 0.0, 0.0, 0.0, 0, 0);
+      continue;
+    }
+    
+    printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n",
+          val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"),
+          hs->stats[j].num,
+          MIN(9999,nstime_to_msec(&(hs->stats[j].min))),
+          MIN(9999,nstime_to_msec(&(hs->stats[j].max))),
+          MIN(9999,get_average(&(hs->stats[j].tot),hs->stats[j].num)),
+          hs->stats[j].min_num, 
+          hs->stats[j].max_num
+          );
+  } /* j category */ 
+
+  printf("=================================================================================================\n");
+  /*
+   * Display 95%
+   */
+
+  printf("|   Category/Criteria     |");
+  for(z=0; z<NB_CRITERIA; z++) printf("%7.2f%% |", criteria[z]);
+  printf("\n");
+
+  printf("|-------------------------|");
+  for(z=0; z<NB_CRITERIA; z++) printf("---------|");
+  printf("\n");
+  /* calculate the delay max to have a given number of messages (in percentage) */
+  for(j=2;j<NB_CAMELSRT_CATEGORY;j++) {
+    
+    rtd_temp = &(hs->stats[j]);
+    
+    if (hs->count[j]>0) { 
+      /* Calculate the delay to answer to p% of the MS */
+      for(z=0; z<NB_CRITERIA; z++) {
+       iteration=0;
+       delay_max=(double)rtd_temp->max.secs*1000 +(double)rtd_temp->max.nsecs/1000000;
+       delay_min=(double)rtd_temp->min.secs*1000 +(double)rtd_temp->min.nsecs/1000000;
+       delay=delay_min;
+       delta=delay_max-delay_min;
+       while( (delta > 0.001) && (iteration < 10000) ) {
+         somme=0;
+         iteration++;
+         
+         for(li=0;li<hs->count[j];li++) {
+           x=hs->delta_time[j][li].secs*1000 
+             + (double)hs->delta_time[j][li].nsecs/1000000;
+           if (x <= delay) somme++;
+         }
+         if ( somme*100 > hs->count[j]*criteria[z] ) { /* trop grand */
+           delay_max=delay;
+           delay=(delay_max+delay_min)/2;
+           delta=delay_max-delay_min;
+         } else { /* trop petit */
+           delay_min=delay;
+           delay=(delay_max+delay_min)/2;
+           delta=delay_max-delay_min;
+         }
+       } /* while */
+       delay_criteria[z]=delay;
+      } /* z criteria */
+      /* Append the result to the table */
+      printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") );
+      for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", MIN(9999,delay_criteria[z]));
+      printf("\n");
+    } else { /* count */ 
+      printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") );
+      for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", 0.0);
+      printf("\n");
+    } /* count */ 
+  }/* j category */ 
+  printf("===========================");
+  for(z=0; z<NB_CRITERIA; z++) printf("==========");
+  printf("\n");
+}
+
+static void camelsrt_init(const char *optarg, void* userdata _U_)
+{
+  struct camelsrt_t *p_camelsrt;
+  const char *filter=NULL;
+  const char *emptyfilter=""; 
+
+  GString *error_string;
+
+  if(!strncmp(optarg,"camel,srt,",9)){
+    filter=optarg+9;
+  } else {
+    filter=NULL;
+  }
+
+  p_camelsrt = g_malloc(sizeof(struct camelsrt_t));
+  if(filter){
+    p_camelsrt->filter=g_malloc(strlen(filter)+1);
+    strcpy(p_camelsrt->filter,filter);
+  } else {
+    p_camelsrt->filter=NULL;
+  }
+  camelsrt_reset(p_camelsrt);
+  
+  if (filter) {
+    error_string=register_tap_listener("CAMEL",
+                                      p_camelsrt,
+                                      filter,
+                                      NULL,
+                                      camelsrt_packet,
+                                      camelsrt_draw);
+  } else { 
+    error_string=register_tap_listener("CAMEL",
+                                      p_camelsrt,
+                                      emptyfilter,
+                                      NULL,
+                                      camelsrt_packet,
+                                      camelsrt_draw);
+  }
+  
+  if(error_string){
+    /* error, we failed to attach to the tap. clean up */
+    g_free(p_camelsrt->filter);
+    g_free(p_camelsrt);
+    
+    fprintf(stderr, "tshark: Couldn't register camel,srt tap: %s\n",
+           error_string->str);
+    g_string_free(error_string, TRUE);
+    exit(1);
+  }
+
+  /*
+   * If we are using tshark, we have to display the stats, even if the stats are not persistent
+   * As the frame are proceeded in the chronological order, we do not need persistent stats
+   * Whereas, with wireshark, it is not possible to have the correct display, if the stats are
+   * not saved along the analyze
+   */ 
+  gtcap_StatSRT=TRUE;
+  gcamel_StatSRT=TRUE;
+}
+
+
+void /* Next line mandatory */
+register_tap_listener_camelsrt(void)
+{
+  register_stat_cmd_arg("camel,srt", camelsrt_init, NULL);
+}