wireshark/epan/camel-persistentdata.c

799 lines
26 KiB
C

/*
* 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
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <epan/emem.h>
#include <epan/packet.h>
#include <epan/tap.h>
#include <epan/asn1.h>
#include <epan/camel-persistentdata.h>
#include <epan/dissectors/packet-tcap.h>
#include <epan/dissectors/packet-mtp3.h>
const value_string camelSRTtype_naming[]= {
{ CAMELSRT_SESSION, "TCAP_Session" },
{ CAMELSRT_VOICE_INITIALDP, "InialDP/Continue" },
{ CAMELSRT_VOICE_ACR1, "Slice1_ACR/ACH" },
{ CAMELSRT_VOICE_ACR2, "Slice2_ACR/ACH" },
{ CAMELSRT_VOICE_ACR3, "Slice3_ACR/ACH" },
{ CAMELSRT_VOICE_DISC, "EvtRepBSCM/Release" },
{ CAMELSRT_SMS_INITIALDP, "InitialDP/ContinueSMS" },
{ CAMELSRT_GPRS_INITIALDP, "InitialDP/ContinueGPRS" },
{ CAMELSRT_GPRS_REPORT, "EvtRepGPRS/ContinueGPRS" },
{ 0,NULL}
};
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);
static struct camelsrt_call_t *new_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key);
static void update_camelsrt_call(struct camelsrt_call_t *p_camelsrt_call,
packet_info *pinfo, guint msg_category);
static void camelsrt_begin_call_matching(packet_info *pinfo,
struct camelsrt_info_t *p_camelsrt_info);
static void camelsrt_request_call_matching(tvbuff_t *tvb, packet_info *pinfo,
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,
proto_tree *tree,
struct camelsrt_info_t *p_camelsrt_info,
guint srt_type);
static void camelsrt_close_call_matching(packet_info *pinfo,
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, 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)
{
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);
#ifdef DEBUG_CAMELSRT
if(p_camelsrt_call) {
dbg(10,"D%d ", p_camelsrt_call->session_id);
} else {
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)
{
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)
{
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-table for SRT */
if (srt_calls != NULL) {
#ifdef DEBUG_CAMELSRT
dbg(16,"Destroy hash ");
#endif
g_hash_table_destroy(srt_calls);
}
/* create new hash-table 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, 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(pinfo, p_camelsrt_info);
camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
CAMELSRT_VOICE_INITIALDP);
break;
case 60: /*InitialDPSMS*/
camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
CAMELSRT_SMS_INITIALDP);
break;
case 78: /*InitialDPGPRS*/
camelsrt_begin_call_matching(pinfo, 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(pinfo, p_camelsrt_info);
tcapsrt_close(p_camelsrt_info->tcap_context, pinfo);
break;
case 80: /*EventReportGPRS*/
camelsrt_begin_call_matching(pinfo, 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(pinfo, p_camelsrt_info);
break;
case 66: /*ReleaseSMS*/
/* Session has been closed by Network */
camelsrt_close_call_matching(pinfo, 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(pinfo, 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 _U_, packet_info *pinfo,
proto_tree *tree _U_,
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(pinfo, 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(packet_info *pinfo,
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 #%u\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);
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,
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, *hidden_item;
#ifdef DEBUG_CAMELSRT
dbg(10,"\n %s #%u\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);
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 #%u ", 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){
hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
PROTO_ITEM_SET_HIDDEN(hidden_item);
}
} 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 #%u ", 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,
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, *hidden_item;
#ifdef DEBUG_CAMELSRT
dbg(10,"\n %s #%u\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);
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 %u ",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 #%u 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 ){
hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
PROTO_ITEM_SET_HIDDEN(hidden_item);
}
}
} /* 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(packet_info *pinfo,
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 #%u\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);
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));
}