1 /* packet-camel-template.c
2  * Routines for Camel
3  * Copyright 2004, Tim Endean <endeant@hotmail.com>
4  * Copyright 2005, Olivier Jacques <olivier.jacques@hp.com>
5  * Copyright 2005, Javier Acuna <javier.acuna@sixbell.com>
6  * Updated to ETSI TS 129 078 V6.4.0 (2004-3GPP TS 29.078 version 6.4.0 Release 6 1 12)
7  * Copyright 2005-2010, Anders Broman <anders.broman@ericsson.com>
8  * Updated to 3GPP TS 29.078 version 7.3.0 Release 7 (2006-06)
9  * Built from the gsm-map dissector Copyright 2004, Anders Broman <anders.broman@ericsson.com>
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * SPDX-License-Identifier: GPL-2.0-or-later
16  * References: ETSI 300 374
17  */
18 /*
19  * Indentation logic: this file is indented with 2 spaces indentation.
20  *                    there are no tabs.
21  */
22 #include "config.h"
23 
24 #include <stdlib.h>
25 
26 #include <epan/packet.h>
27 #include <epan/prefs.h>
28 #include <epan/oids.h>
29 #include <epan/tap.h>
30 #include <epan/srt_table.h>
31 #include <epan/stat_tap_ui.h>
32 #include <epan/asn1.h>
33 #include <epan/expert.h>
34 #include <wsutil/strtoi.h>
35 
36 #include "packet-ber.h"
37 #include "packet-camel.h"
38 #include "packet-q931.h"
39 #include "packet-e164.h"
40 #include "packet-isup.h"
41 #include "packet-gsm_map.h"
42 #include "packet-gsm_a_common.h"
43 #include "packet-inap.h"
44 #include "packet-tcap.h"
45 
46 #define PNAME  "Camel"
47 #define PSNAME "CAMEL"
48 #define PFNAME "camel"
49 
50 /* Initialize the protocol and registered fields */
51 static int proto_camel = -1;
52 int date_format = 1; /*assume european date format */
53 int camel_tap = -1;
54 /* Global variables */
55 static guint32 opcode=0;
56 static guint32 errorCode=0;
57 static guint32 camel_ver = 0;
58 
59 /* When several Camel components are received in a single TCAP message,
60    we have to use several buffers for the stored parameters
61    because else this data are erased during TAP dissector call */
62 #define MAX_CAMEL_INSTANCE 10
63 static int camelsrt_global_current=0;
64 static struct camelsrt_info_t camelsrt_global_info[MAX_CAMEL_INSTANCE];
65 
66 /* ROSE context */
67 static rose_ctx_t camel_rose_ctx;
68 
69 static int hf_digit = -1;
70 static int hf_camel_extension_code_local = -1;
71 static int hf_camel_error_code_local = -1;
72 static int hf_camel_cause_indicator = -1;
73 static int hf_camel_PDPTypeNumber_etsi = -1;
74 static int hf_camel_PDPTypeNumber_ietf = -1;
75 static int hf_camel_PDPAddress_IPv4 = -1;
76 static int hf_camel_PDPAddress_IPv6 = -1;
77 static int hf_camel_cellGlobalIdOrServiceAreaIdFixedLength = -1;
78 static int hf_camel_RP_Cause = -1;
79 static int hf_camel_CAMEL_AChBillingChargingCharacteristics = -1;
80 static int hf_camel_CAMEL_FCIBillingChargingCharacteristics = -1;
81 static int hf_camel_CAMEL_FCIGPRSBillingChargingCharacteristics = -1;
82 static int hf_camel_CAMEL_FCISMSBillingChargingCharacteristics = -1;
83 static int hf_camel_CAMEL_SCIBillingChargingCharacteristics = -1;
84 static int hf_camel_CAMEL_SCIGPRSBillingChargingCharacteristics = -1;
85 static int hf_camel_CAMEL_CallResult = -1;
86 
87 /* Used by persistent data */
88 static int hf_camelsrt_SessionId=-1;
89 static int hf_camelsrt_RequestNumber=-1;
90 static int hf_camelsrt_Duplicate=-1;
91 static int hf_camelsrt_RequestFrame=-1;
92 static int hf_camelsrt_ResponseFrame=-1;
93 static int hf_camelsrt_DeltaTime=-1;
94 static int hf_camelsrt_SessionTime=-1;
95 static int hf_camelsrt_DeltaTime31=-1;
96 static int hf_camelsrt_DeltaTime75=-1;
97 static int hf_camelsrt_DeltaTime65=-1;
98 static int hf_camelsrt_DeltaTime22=-1;
99 static int hf_camelsrt_DeltaTime35=-1;
100 static int hf_camelsrt_DeltaTime80=-1;
101 
102 #include "packet-camel-hf.c"
103 
104 static struct camelsrt_info_t * gp_camelsrt_info;
105 
106 /* Forward declarations */
107 static int dissect_invokeData(proto_tree *tree, tvbuff_t *tvb, int offset,asn1_ctx_t *actx);
108 static int dissect_returnResultData(proto_tree *tree, tvbuff_t *tvb, int offset,asn1_ctx_t *actx);
109 static int dissect_returnErrorData(proto_tree *tree, tvbuff_t *tvb, int offset,asn1_ctx_t *actx);
110 static int dissect_camel_CAMEL_AChBillingChargingCharacteristics(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
111 static int dissect_camel_CAMEL_AChBillingChargingCharacteristicsV2(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
112 static int dissect_camel_CAMEL_CallResult(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
113 static int dissect_camel_EstablishTemporaryConnectionArgV2(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
114 static int dissect_camel_SpecializedResourceReportArgV23(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
115 
116 /* XXX - can we get rid of these and always do the SRT work? */
117 static gboolean gcamel_HandleSRT=FALSE;
118 static gboolean gcamel_PersistentSRT=FALSE;
119 static gboolean gcamel_DisplaySRT=FALSE;
120 gboolean gcamel_StatSRT=FALSE;
121 
122 /* Initialize the subtree pointers */
123 static gint ett_camel = -1;
124 static gint ett_camelisup_parameter = -1;
125 static gint ett_camel_AccessPointName = -1;
126 static gint ett_camel_pdptypenumber = -1;
127 static gint ett_camel_cause = -1;
128 static gint ett_camel_RPcause = -1;
129 static gint ett_camel_stat = -1;
130 static gint ett_camel_calledpartybcdnumber = -1;
131 static gint ett_camel_callingpartynumber = -1;
132 static gint ett_camel_originalcalledpartyid = -1;
133 static gint ett_camel_redirectingpartyid = -1;
134 static gint ett_camel_locationnumber = -1;
135 static gint ett_camel_additionalcallingpartynumber = -1;
136 static gint ett_camel_calledAddressValue = -1;
137 static gint ett_camel_callingAddressValue = -1;
138 static gint ett_camel_assistingSSPIPRoutingAddress = -1;
139 static gint ett_camel_correlationID = -1;
140 static gint ett_camel_dTMFDigitsCompleted = -1;
141 static gint ett_camel_dTMFDigitsTimeOut = -1;
142 static gint ett_camel_number = -1;
143 static gint ett_camel_digitsResponse = -1;
144 
145 #include "packet-camel-ett.c"
146 
147 static expert_field ei_camel_unknown_invokeData = EI_INIT;
148 static expert_field ei_camel_unknown_returnResultData = EI_INIT;
149 static expert_field ei_camel_unknown_returnErrorData = EI_INIT;
150 
151 /* Preference settings default */
152 #define MAX_SSN 254
153 static range_t *global_ssn_range;
154 static dissector_handle_t  camel_handle;
155 static dissector_handle_t  camel_v1_handle;
156 static dissector_handle_t  camel_v2_handle;
157 static dissector_handle_t  camel_v3_handle;
158 static dissector_handle_t  camel_v4_handle;
159 
160 /* Global variables */
161 
162 static guint8 PDPTypeOrganization;
163 static guint8 PDPTypeNumber;
164 const char *camel_obj_id = NULL;
165 gboolean is_ExtensionField =FALSE;
166 
167 /* Global hash tables*/
168 static wmem_map_t *srt_calls = NULL;
169 static guint32 camelsrt_global_SessionId=1;
170 
171 static int camel_opcode_type;
172 #define CAMEL_OPCODE_INVOKE        1
173 #define CAMEL_OPCODE_RETURN_RESULT 2
174 #define CAMEL_OPCODE_RETURN_ERROR  3
175 #define CAMEL_OPCODE_REJECT        4
176 
177 static const value_string camel_Component_vals[] = {
178   {   1, "invoke" },
179   {   2, "returnResultLast" },
180   {   3, "returnError" },
181   {   4, "reject" },
182   { 0, NULL }
183 };
184 
185 const value_string  camelSRTtype_naming[]= {
186   { CAMELSRT_SESSION,         "TCAP_Session" },
187   { CAMELSRT_VOICE_INITIALDP, "InialDP/Continue" },
188   { CAMELSRT_VOICE_ACR1,      "Slice1_ACR/ACH" },
189   { CAMELSRT_VOICE_ACR2,      "Slice2_ACR/ACH" },
190   { CAMELSRT_VOICE_ACR3,      "Slice3_ACR/ACH" },
191   { CAMELSRT_VOICE_DISC,      "EvtRepBSCM/Release" },
192   { CAMELSRT_SMS_INITIALDP,   "InitialDP/ContinueSMS" },
193   { CAMELSRT_GPRS_INITIALDP,  "InitialDP/ContinueGPRS" },
194   { CAMELSRT_GPRS_REPORT,     "EvtRepGPRS/ContinueGPRS" },
195   { 0,NULL}
196 };
197 
198 #define EUROPEAN_DATE 1
199 #define AMERICAN_DATE 2
200 #define CAMEL_DATE_AND_TIME_LEN 20 /* 2*5 + 4 + 5 + 1 (HH:MM:SS;mm/dd/yyyy) */
201 
202 static const enum_val_t date_options[] = {
203   { "european",         "DD/MM/YYYY",       EUROPEAN_DATE },
204   { "american",        "MM/DD/YYYY",        AMERICAN_DATE },
205   { NULL, NULL, 0 }
206 };
207 
208 static const value_string digit_value[] = {
209   { 0,  "0"},
210   { 1,  "1"},
211   { 2,  "2"},
212   { 3,  "3"},
213   { 4,  "4"},
214   { 5,  "5"},
215   { 6,  "6"},
216   { 7,  "7"},
217   { 8,  "8"},
218   { 9,  "9"},
219   { 10, "spare"},
220   { 11, "spare"},
221   { 12, "spare"},
222   { 13, "spare"},
223   { 0,  NULL}
224 
225 };
226 
227 
228 #if 0
229 static const value_string camel_nature_of_addr_indicator_values[] = {
230   {   0x00,  "unknown" },
231   {   0x01,  "International Number" },
232   {   0x02,  "National Significant Number" },
233   {   0x03,  "Network Specific Number" },
234   {   0x04,  "Subscriber Number" },
235   {   0x05,  "Reserved" },
236   {   0x06,  "Abbreviated Number" },
237   {   0x07,  "Reserved for extension" },
238   { 0, NULL }
239 };
240 static const value_string camel_number_plan_values[] = {
241   {   0x00,  "unknown" },
242   {   0x01,  "ISDN/Telephony Numbering (Rec ITU-T E.164)" },
243   {   0x02,  "spare" },
244   {   0x03,  "Data Numbering (ITU-T Rec. X.121)" },
245   {   0x04,  "Telex Numbering (ITU-T Rec. F.69)" },
246   {   0x05,  "spare" },
247   {   0x06,  "Land Mobile Numbering (ITU-T Rec. E.212)" },
248   {   0x07,  "spare" },
249   {   0x08,  "National Numbering" },
250   {   0x09,  "Private Numbering" },
251   {   0x0f,  "Reserved for extension" },
252   { 0, NULL }
253 };
254 #endif
255 
256 /* End includes from old" packet-camel.c */
257 
258 static const value_string camel_RP_Cause_values[] = {
259   { 1, "Unassigned (unallocated) number" },
260   { 8, "Operator determined barring" },
261   { 10, "Call barred" },
262   { 11, "Reserved" },
263   { 21, "Short message transfer rejected" },
264   { 27, "Destination out of order" },
265   { 28, "Unidentified subscriber" },
266   { 29, "Facility Rejected" },
267   { 30, "Unknown subscriber" },
268   { 38, "Network out of order" },
269   { 41, "Temporary failure" },
270   { 42, "Congestion" },
271   { 47, "Resources unavailable, unspecified" },
272   { 50, "Requested facility not subscribed" },
273   { 69, "Requested facility not implemented" },
274   { 81, "Invalid short message transfer reference value" },
275   { 95, "Semantically incorrect message" },
276   { 96, "Invalid mandatory information" },
277   { 97, " Message Type non-existent or not implemented" },
278   { 98, "Message not compatible with short message protocol state" },
279   { 99, "Information element non existent or not implemented" },
280   { 111, "Protocol error, unspecified" },
281   { 127, "Interworking, unspecified" },
282   { 22,"Memory capacity exceeded" },
283   { 0, NULL }
284 };
285 
286 static const value_string camel_holdTreatmentIndicator_values[] = {
287   {   0x01,  "acceptHoldRequest" },
288   {   0x02,  "rejectHoldRequest" },
289   { 0, NULL }
290 };
291 static const value_string camel_cwTreatmentIndicator_values[] = {
292   {   0x01,  "acceptCw" },
293   {   0x02,  "rejectCw" },
294   { 0, NULL }
295 };
296 static const value_string camel_ectTreatmentIndicator_values[] = {
297   {   0x01,  "acceptEctRequest" },
298   {   0x02,  "rejectEctRequest" },
299   { 0, NULL }
300 };
301 
302 #include "packet-camel-val.h"
303 
304 #include "packet-camel-table.c"
305 
306 /*
307  * DEBUG fonctions
308  */
309 
310 #undef DEBUG_CAMELSRT
311 /* #define DEBUG_CAMELSRT */
312 
313 #ifdef DEBUG_CAMELSRT
314 #include <stdio.h>
315 #include <stdarg.h>
316 static guint debug_level = 99;
317 
dbg(guint level,char * fmt,...)318 static void dbg(guint level, char *fmt, ...) {
319   va_list ap;
320 
321   if (level > debug_level) return;
322   va_start(ap,fmt);
323   vfprintf(stderr, fmt, ap);
324   va_end(ap);
325 }
326 #endif
327 
328 static void
camelstat_init(struct register_srt * srt _U_,GArray * srt_array)329 camelstat_init(struct register_srt* srt _U_, GArray* srt_array)
330 {
331   srt_stat_table *camel_srt_table;
332   gchar* tmp_str;
333   guint32 i;
334 
335   camel_srt_table = init_srt_table("CAMEL Commands", NULL, srt_array, NB_CAMELSRT_CATEGORY, NULL, NULL, NULL);
336   for (i = 0; i < NB_CAMELSRT_CATEGORY; i++)
337   {
338     tmp_str = val_to_str_wmem(NULL,i,camelSRTtype_naming,"Unknown (%d)");
339     init_srt_table_row(camel_srt_table, i, tmp_str);
340     wmem_free(NULL, tmp_str);
341   }
342 }
343 
344 static tap_packet_status
camelstat_packet(void * pcamel,packet_info * pinfo,epan_dissect_t * edt _U_,const void * psi)345 camelstat_packet(void *pcamel, packet_info *pinfo, epan_dissect_t *edt _U_, const void *psi)
346 {
347   guint idx = 0;
348   srt_stat_table *camel_srt_table;
349   const struct camelsrt_info_t * pi=(const struct camelsrt_info_t *)psi;
350   srt_data_t *data = (srt_data_t *)pcamel;
351   int i;
352 
353   for (i=1; i<NB_CAMELSRT_CATEGORY; i++) {
354     if ( pi->bool_msginfo[i] &&
355          pi->msginfo[i].is_delta_time
356          && pi->msginfo[i].request_available
357          && !pi->msginfo[i].is_duplicate )
358     {
359       camel_srt_table = g_array_index(data->srt_array, srt_stat_table*, idx);
360       add_srt_table_data(camel_srt_table, i, &pi->msginfo[i].req_time, pinfo);
361     }
362   } /* category */
363   return TAP_PACKET_REDRAW;
364 }
365 
366 
camel_number_to_char(int number)367 static char camel_number_to_char(int number)
368 {
369   if (number < 10)
370     return (char) (number + 48 ); /* this is ASCII specific */
371   else
372     return (char) (number + 55 );
373 }
374 
375 /*
376  * 24.011 8.2.5.4
377  */
378 static guint8
dissect_RP_cause_ie(tvbuff_t * tvb,guint32 offset,_U_ guint len,proto_tree * tree,int hf_cause_value,guint8 * cause_value)379 dissect_RP_cause_ie(tvbuff_t *tvb, guint32 offset, _U_ guint len,
380                     proto_tree *tree, int hf_cause_value, guint8 *cause_value)
381 {
382   guint8 oct;
383   guint32 curr_offset;
384 
385   curr_offset = offset;
386   oct = tvb_get_guint8(tvb, curr_offset);
387 
388   *cause_value = oct & 0x7f;
389 
390   proto_tree_add_uint(tree, hf_cause_value, tvb, curr_offset, 1, oct);
391   curr_offset++;
392 
393   if ((oct & 0x80)) {
394     oct = tvb_get_guint8(tvb, curr_offset);
395     proto_tree_add_uint_format(tree, hf_cause_value,
396                                tvb, curr_offset, 1, oct,
397                                "Diagnostic : %u", oct);
398     curr_offset++;
399   }
400   return(curr_offset - offset);
401 }
402 
403 static int dissect_camel_InitialDPArgExtensionV2(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
404 
405 #include "packet-camel-fn.c"
406 
407 #include "packet-camel-table2.c"
408 
409 /*
410  * Functions needed for Hash-Table
411  */
412 
413 /* compare 2 keys */
414 static gint
camelsrt_call_equal(gconstpointer k1,gconstpointer k2)415 camelsrt_call_equal(gconstpointer k1, gconstpointer k2)
416 {
417   const struct camelsrt_call_info_key_t *key1 = (const struct camelsrt_call_info_key_t *) k1;
418   const struct camelsrt_call_info_key_t *key2 = (const struct camelsrt_call_info_key_t *) k2;
419 
420   return (key1->SessionIdKey == key2->SessionIdKey) ;
421 }
422 
423 /* calculate a hash key */
424 static guint
camelsrt_call_hash(gconstpointer k)425 camelsrt_call_hash(gconstpointer k)
426 {
427   const struct camelsrt_call_info_key_t *key = (const struct camelsrt_call_info_key_t *) k;
428   return key->SessionIdKey;
429 }
430 
431 /*
432  * Find the dialog by Key and Time
433  */
434 static struct camelsrt_call_t *
find_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key)435 find_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key)
436 {
437   struct camelsrt_call_t *p_camelsrt_call = NULL;
438   p_camelsrt_call = (struct camelsrt_call_t *)wmem_map_lookup(srt_calls, p_camelsrt_call_key);
439 
440 #ifdef DEBUG_CAMELSRT
441   if(p_camelsrt_call) {
442     dbg(10,"D%d ", p_camelsrt_call->session_id);
443   } else {
444     dbg(23,"Not in hash ");
445   }
446 #endif
447 
448   return p_camelsrt_call;
449 }
450 
451 /*
452  * Initialize the data per call for the Service Response Time Statistics
453  * Data are linked to a Camel operation in a TCAP transaction
454  */
455 static void
raz_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call)456 raz_camelsrt_call (struct camelsrt_call_t *p_camelsrt_call)
457 {
458   memset(p_camelsrt_call,0,sizeof(struct camelsrt_call_t));
459 }
460 
461 /*
462  * New record to create, to identify a new transaction
463  */
464 static struct camelsrt_call_t *
new_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key)465 new_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key)
466 {
467   struct camelsrt_call_info_key_t *p_new_camelsrt_call_key;
468   struct camelsrt_call_t *p_new_camelsrt_call = NULL;
469 
470   /* Register the transaction in the hash table
471      with the tcap transaction Id as main Key
472      Once created, this entry will be updated later */
473 
474   p_new_camelsrt_call_key = wmem_new(wmem_file_scope(), struct camelsrt_call_info_key_t);
475   p_new_camelsrt_call_key->SessionIdKey = p_camelsrt_call_key->SessionIdKey;
476   p_new_camelsrt_call = wmem_new(wmem_file_scope(), struct camelsrt_call_t);
477   raz_camelsrt_call(p_new_camelsrt_call);
478   p_new_camelsrt_call->session_id = camelsrt_global_SessionId++;
479 #ifdef DEBUG_CAMELSRT
480   dbg(10,"D%d ", p_new_camelsrt_call->session_id);
481 #endif
482   /* store it */
483   wmem_map_insert(srt_calls, p_new_camelsrt_call_key, p_new_camelsrt_call);
484   return p_new_camelsrt_call;
485 }
486 
487 /*
488  * Routine called when the TAP is initialized.
489  * so hash table are (re)created
490  */
491 static void
camelsrt_init_routine(void)492 camelsrt_init_routine(void)
493 {
494   /* Reset the session counter */
495   camelsrt_global_SessionId=1;
496 
497   /* The Display of SRT is enable
498    * 1) For wireshark only if Persistent Stat is enable
499    * 2) For Tshark, if the SRT handling is enable
500    */
501   gcamel_DisplaySRT=gcamel_PersistentSRT || gcamel_HandleSRT&gcamel_StatSRT;
502 }
503 
504 
505 /*
506  * Update a record with the data of the Request
507  */
508 static void
update_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call,packet_info * pinfo,guint msg_category)509 update_camelsrt_call(struct camelsrt_call_t *p_camelsrt_call, packet_info *pinfo,
510                      guint msg_category)
511 {
512   p_camelsrt_call->category[msg_category].req_num = pinfo->num;
513   p_camelsrt_call->category[msg_category].rsp_num = 0;
514   p_camelsrt_call->category[msg_category].responded = FALSE;
515   p_camelsrt_call->category[msg_category].req_time = pinfo->abs_ts;
516 }
517 
518 /*
519  * Update the Camel session info, and close the session.
520  * Then remove the associated context, if we do not have persistentSRT enable
521  */
522 static void
camelsrt_close_call_matching(packet_info * pinfo,struct camelsrt_info_t * p_camelsrt_info)523 camelsrt_close_call_matching(packet_info *pinfo,
524                              struct camelsrt_info_t *p_camelsrt_info)
525 {
526   struct camelsrt_call_t *p_camelsrt_call;
527   struct camelsrt_call_info_key_t camelsrt_call_key;
528   nstime_t delta;
529 
530   p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
531 #ifdef DEBUG_CAMELSRT
532   dbg(10,"\n Session end #%u\n", pinfo->num);
533 #endif
534   /* look only for matching request, if matching conversation is available. */
535   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
536 
537 #ifdef DEBUG_CAMELSRT
538   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
539 #endif
540   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
541   if(p_camelsrt_call) {
542 #ifdef DEBUG_CAMELSRT
543     dbg(12,"Found ");
544 #endif
545     /* Calculate Service Response Time */
546     nstime_delta(&delta, &pinfo->abs_ts, &p_camelsrt_call->category[CAMELSRT_SESSION].req_time);
547     p_camelsrt_call->category[CAMELSRT_SESSION].responded = TRUE;
548     p_camelsrt_info->msginfo[CAMELSRT_SESSION].request_available = TRUE;
549     p_camelsrt_info->msginfo[CAMELSRT_SESSION].is_delta_time = TRUE;
550     p_camelsrt_info->msginfo[CAMELSRT_SESSION].delta_time = delta; /* give it to tap */
551     p_camelsrt_info->msginfo[CAMELSRT_SESSION].req_time = p_camelsrt_call->category[CAMELSRT_SESSION].req_time;
552 
553     if ( !gcamel_PersistentSRT ) {
554       wmem_map_remove(srt_calls, &camelsrt_call_key);
555 #ifdef DEBUG_CAMELSRT
556       dbg(20,"remove hash ");
557 #endif
558     } else {
559 #ifdef DEBUG_CAMELSRT
560       dbg(20,"keep hash ");
561 #endif
562     }
563   } /* call reference found */
564 }
565 
566 /*
567  * Callback function for the TCAP dissector
568  * This callback function is used to inform the camel layer, that the session
569  * has been Closed or Aborted by a TCAP message without Camel component
570  * So, we can close the context for camel session, and update the stats.
571  */
572 static void
camelsrt_tcap_matching(tvbuff_t * tvb _U_,packet_info * pinfo,proto_tree * tree _U_,struct tcaphash_context_t * p_tcap_context)573 camelsrt_tcap_matching(tvbuff_t *tvb _U_, packet_info *pinfo,
574                        proto_tree *tree _U_,
575                        struct tcaphash_context_t *p_tcap_context)
576 {
577   struct camelsrt_info_t *p_camelsrt_info;
578 
579 #ifdef DEBUG_CAMELSRT
580   dbg(11,"Camel_CallBack ");
581 #endif
582   p_camelsrt_info=camelsrt_razinfo();
583 
584   p_camelsrt_info->tcap_context=p_tcap_context;
585   if (p_tcap_context) {
586 #ifdef DEBUG_CAMELSRT
587     dbg(11,"Close TCAP ");
588 #endif
589     p_camelsrt_info->tcap_session_id = p_tcap_context->session_id;
590     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
591     tap_queue_packet(camel_tap, pinfo, p_camelsrt_info);
592   }
593 }
594 
595 /*
596  * Create the record identifiying the Camel session
597  * As the Tcap session id given by the TCAP dissector is uniq, it will be
598  * used as main key.
599  */
600 static void
camelsrt_begin_call_matching(packet_info * pinfo,struct camelsrt_info_t * p_camelsrt_info)601 camelsrt_begin_call_matching(packet_info *pinfo,
602                              struct camelsrt_info_t *p_camelsrt_info)
603 {
604   struct camelsrt_call_t *p_camelsrt_call;
605   struct camelsrt_call_info_key_t camelsrt_call_key;
606 
607   p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
608 
609   /* prepare the key data */
610   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
611 
612   /* look up the request */
613 #ifdef DEBUG_CAMELSRT
614   dbg(10,"\n Session begin #%u\n", pinfo->num);
615   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
616 #endif
617   p_camelsrt_call = (struct camelsrt_call_t *)wmem_map_lookup(srt_calls, &camelsrt_call_key);
618   if (p_camelsrt_call) {
619     /* We have seen this request before -> do nothing */
620 #ifdef DEBUG_CAMELSRT
621     dbg(22,"Already seen ");
622 #endif
623   } else { /* p_camelsrt_call has not been found */
624 #ifdef DEBUG_CAMELSRT
625     dbg(10,"New key %lu ",camelsrt_call_key.SessionIdKey);
626 #endif
627     p_camelsrt_call = new_camelsrt_call(&camelsrt_call_key);
628     p_camelsrt_call->tcap_context=(struct tcaphash_context_t *)p_camelsrt_info->tcap_context;
629     update_camelsrt_call(p_camelsrt_call, pinfo,CAMELSRT_SESSION);
630 
631 #ifdef DEBUG_CAMELSRT
632     dbg(11,"Update Callback ");
633 #endif
634     p_camelsrt_call->tcap_context->callback=camelsrt_tcap_matching;
635   }
636 }
637 
638 /*
639  * Register the request, and try to find the response
640  *
641  */
642 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)643 camelsrt_request_call_matching(tvbuff_t *tvb, packet_info *pinfo,
644                                proto_tree *tree,
645                                struct camelsrt_info_t *p_camelsrt_info,
646                                guint srt_type )
647 {
648   struct camelsrt_call_t *p_camelsrt_call;
649   struct camelsrt_call_info_key_t camelsrt_call_key;
650   proto_item *ti, *hidden_item;
651 
652 #ifdef DEBUG_CAMELSRT
653   dbg(10,"\n %s #%u\n", val_to_str_const(srt_type, camelSRTtype_naming, "Unk"),pinfo->num);
654 #endif
655 
656   /* look only for matching request, if matching conversation is available. */
657   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
658 
659 #ifdef DEBUG_CAMELSRT
660   dbg(11,"Search key %lu ", camelsrt_call_key.SessionIdKey);
661 #endif
662   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
663   if(p_camelsrt_call) {
664 #ifdef DEBUG_CAMELSRT
665     dbg(12,"Found ");
666 #endif
667     if (gcamel_DisplaySRT)
668       proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
669 
670 
671     /* Hmm.. As there are several slices ApplyChargingReport/ApplyCharging
672      * we will prepare the measurement for 3 slices with 3 categories */
673     if (srt_type==CAMELSRT_VOICE_ACR1) {
674       if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num == 0) {
675         srt_type=CAMELSRT_VOICE_ACR1;
676       } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num == 0)
677                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0)
678                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num < pinfo->num) ) {
679         srt_type=CAMELSRT_VOICE_ACR2;
680       } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num == 0)
681                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0)
682                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num < pinfo->num) ) {
683         srt_type=CAMELSRT_VOICE_ACR3;
684       } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
685                  && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num > pinfo->num) {
686         srt_type=CAMELSRT_VOICE_ACR1;
687       } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0
688                    && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num > pinfo->num) {
689         srt_type=CAMELSRT_VOICE_ACR2;
690       } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
691                   && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num > pinfo->num) {
692         srt_type=CAMELSRT_VOICE_ACR3;
693       }
694 #ifdef DEBUG_CAMELSRT
695       dbg(70,"Request ACR %u ",srt_type);
696       dbg(70,"ACR1 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num);
697       dbg(70,"ACR2 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num);
698       dbg(70,"ACR3 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num);
699 #endif
700     } /* not ACR */
701     p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
702 
703 
704     if (p_camelsrt_call->category[srt_type].req_num == 0) {
705       /* We have not yet seen a request to that call, so this must be the first request
706          remember its frame number. */
707 #ifdef DEBUG_CAMELSRT
708       dbg(5,"Set reqlink #%u ", pinfo->num);
709 #endif
710       update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
711     } else {
712       /* We have seen a request to this call - but was it *this* request? */
713       if (p_camelsrt_call->category[srt_type].req_num != pinfo->num) {
714 
715         if (srt_type!=CAMELSRT_VOICE_DISC) {
716           /* No, so it's a duplicate request. Mark it as such. */
717 #ifdef DEBUG_CAMELSRT
718           dbg(21,"Display_duplicate with req %d ", p_camelsrt_call->category[srt_type].req_num);
719 #endif
720           p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE;
721           if (gcamel_DisplaySRT){
722             hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
723                 proto_item_set_hidden(hidden_item);
724           }
725 
726         } else {
727           /* Ignore duplicate frame */
728           if (pinfo->num > p_camelsrt_call->category[srt_type].req_num) {
729             p_camelsrt_call->category[srt_type].req_num = pinfo->num;
730 #ifdef DEBUG_CAMELSRT
731             dbg(5,"DISC Set reqlink #%u ", pinfo->num);
732 #endif
733             update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
734           } /* greater frame */
735         } /* DISC */
736       } /* req_num already seen */
737     } /* req_num != 0 */
738 
739       /* add link to response frame, if available */
740     if ( gcamel_DisplaySRT &&
741          (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
742          (p_camelsrt_call->category[srt_type].req_num != 0) &&
743          (p_camelsrt_call->category[srt_type].req_num == pinfo->num) ) {
744 #ifdef DEBUG_CAMELSRT
745       dbg(20,"Display_framersplink %d ",p_camelsrt_call->category[srt_type].rsp_num);
746 #endif
747       ti = proto_tree_add_uint_format(tree, hf_camelsrt_RequestFrame, tvb, 0, 0,
748                                       p_camelsrt_call->category[srt_type].rsp_num,
749                                       "Linked response %s in frame %u",
750                                       val_to_str_const(srt_type, camelSRTtype_naming, "Unk"),
751                                       p_camelsrt_call->category[srt_type].rsp_num);
752       proto_item_set_generated(ti);
753     } /* frame valid */
754   } /* call reference */
755 }
756 
757 /*
758  * Display the delta time between two messages in a field corresponding
759  * to the category (hf_camelsrt_DeltaTimexx).
760  */
761 static void
camelsrt_display_DeltaTime(proto_tree * tree,tvbuff_t * tvb,nstime_t * value_ptr,guint category)762 camelsrt_display_DeltaTime(proto_tree *tree, tvbuff_t *tvb, nstime_t *value_ptr,
763                            guint category)
764 {
765   proto_item *ti;
766 
767   if ( gcamel_DisplaySRT ) {
768     switch(category) {
769     case CAMELSRT_VOICE_INITIALDP:
770       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime31, tvb, 0, 0, value_ptr);
771       proto_item_set_generated(ti);
772       break;
773 
774     case CAMELSRT_VOICE_ACR1:
775     case CAMELSRT_VOICE_ACR2:
776     case CAMELSRT_VOICE_ACR3:
777       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime22, tvb, 0, 0, value_ptr);
778       proto_item_set_generated(ti);
779       break;
780 
781     case CAMELSRT_VOICE_DISC:
782       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime35, tvb, 0, 0, value_ptr);
783       proto_item_set_generated(ti);
784       break;
785 
786     case CAMELSRT_GPRS_INITIALDP:
787       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime75, tvb, 0, 0, value_ptr);
788       proto_item_set_generated(ti);
789       break;
790 
791     case CAMELSRT_GPRS_REPORT:
792       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime80, tvb, 0, 0, value_ptr);
793       proto_item_set_generated(ti);
794       break;
795 
796     case CAMELSRT_SMS_INITIALDP:
797       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime65, tvb, 0, 0, value_ptr);
798       proto_item_set_generated(ti);
799       break;
800 
801     default:
802       break;
803     }
804   }
805 }
806 
807 /*
808  * Check if the received message is a response to a previous request
809  * registered is the camel session context.
810  */
811 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)812 camelsrt_report_call_matching(tvbuff_t *tvb, packet_info *pinfo,
813                               proto_tree *tree,
814                               struct camelsrt_info_t *p_camelsrt_info,
815                               guint srt_type)
816 {
817   struct camelsrt_call_t *p_camelsrt_call;
818   struct camelsrt_call_info_key_t camelsrt_call_key;
819   nstime_t delta;
820   proto_item *ti, *hidden_item;
821 
822 #ifdef DEBUG_CAMELSRT
823   dbg(10,"\n %s #%u\n", val_to_str_const(srt_type, camelSRTtype_naming, "Unk"),pinfo->num);
824 #endif
825   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
826   /* look only for matching request, if matching conversation is available. */
827 
828 #ifdef DEBUG_CAMELSRT
829   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
830 #endif
831   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
832   if(p_camelsrt_call) {
833 #ifdef DEBUG_CAMELSRT
834     dbg(12,"Found, req=%d ",p_camelsrt_call->category[srt_type].req_num);
835 #endif
836     if ( gcamel_DisplaySRT )
837       proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
838 
839     if (srt_type==CAMELSRT_VOICE_ACR1) {
840       if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num != 0
841           && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num < pinfo->num) {
842         srt_type=CAMELSRT_VOICE_ACR1;
843       } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num != 0
844                    && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num < pinfo->num) {
845         srt_type=CAMELSRT_VOICE_ACR2;
846       } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num != 0
847                   && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num < pinfo->num) {
848         srt_type=CAMELSRT_VOICE_ACR1;
849       }
850 #ifdef DEBUG_CAMELSRT
851       dbg(70,"Report ACR %u ",srt_type);
852 #endif
853     } /* not ACR */
854     p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
855 
856     if (p_camelsrt_call->category[srt_type].rsp_num == 0) {
857       if  ( (p_camelsrt_call->category[srt_type].req_num != 0)
858             && (pinfo->num > p_camelsrt_call->category[srt_type].req_num) ){
859         /* We have not yet seen a response to that call, so this must be the first response;
860            remember its frame number only if response comes after request */
861 #ifdef DEBUG_CAMELSRT
862         dbg(14,"Set reslink #%d req %u ",pinfo->num, p_camelsrt_call->category[srt_type].req_num);
863 #endif
864         p_camelsrt_call->category[srt_type].rsp_num = pinfo->num;
865 
866       } else {
867 #ifdef DEBUG_CAMELSRT
868         dbg(2,"badreslink #%u req %u ",pinfo->num, p_camelsrt_call->category[srt_type].req_num);
869 #endif
870       } /* req_num != 0 */
871     } else { /* rsp_num != 0 */
872       /* We have seen a response to this call - but was it *this* response? */
873       if (p_camelsrt_call->category[srt_type].rsp_num != pinfo->num) {
874         /* No, so it's a duplicate response. Mark it as such. */
875 #ifdef DEBUG_CAMELSRT
876         dbg(21,"Display_duplicate rsp=%d ", p_camelsrt_call->category[srt_type].rsp_num);
877 #endif
878         p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE;
879         if ( gcamel_DisplaySRT ){
880           hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
881           proto_item_set_hidden(hidden_item);
882         }
883       }
884     } /* rsp_num != 0 */
885 
886     if ( (p_camelsrt_call->category[srt_type].req_num != 0) &&
887          (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
888          (p_camelsrt_call->category[srt_type].rsp_num == pinfo->num) ) {
889 
890       p_camelsrt_call->category[srt_type].responded = TRUE;
891       p_camelsrt_info->msginfo[srt_type].request_available = TRUE;
892 #ifdef DEBUG_CAMELSRT
893       dbg(20,"Display_frameReqlink %d ",p_camelsrt_call->category[srt_type].req_num);
894 #endif
895       /* Indicate the frame to which this is a reply. */
896       if ( gcamel_DisplaySRT ) {
897         ti = proto_tree_add_uint_format(tree, hf_camelsrt_ResponseFrame, tvb, 0, 0,
898                                         p_camelsrt_call->category[srt_type].req_num,
899                                         "Linked request %s in frame %u",
900                                         val_to_str_const(srt_type, camelSRTtype_naming, "Unk"),
901                                         p_camelsrt_call->category[srt_type].req_num);
902         proto_item_set_generated(ti);
903       }
904       /* Calculate Service Response Time */
905       nstime_delta(&delta, &pinfo->abs_ts, &p_camelsrt_call->category[srt_type].req_time);
906 
907       p_camelsrt_info->msginfo[srt_type].is_delta_time = TRUE;
908       p_camelsrt_info->msginfo[srt_type].delta_time = delta; /* give it to tap */
909       p_camelsrt_info->msginfo[srt_type].req_time = p_camelsrt_call->category[srt_type].req_time;
910 
911       /* display Service Response Time and make it filterable */
912       camelsrt_display_DeltaTime(tree, tvb, &delta, srt_type);
913 
914     } /*req_num != 0 && not duplicate */
915   } /* call reference found */
916 }
917 
918 /*
919  * Service Response Time analyze, called just after the camel dissector
920  * According to the camel operation, we
921  * - open/close a context for the camel session
922  * - look for a request, or look for the corresponding response
923  */
924 void
camelsrt_call_matching(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,struct camelsrt_info_t * p_camelsrt_info)925 camelsrt_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
926                        struct camelsrt_info_t *p_camelsrt_info)
927 {
928 
929 #ifdef DEBUG_CAMELSRT
930   dbg(10,"tcap_session #%d ", p_camelsrt_info->tcap_session_id);
931 #endif
932 
933   switch (p_camelsrt_info->opcode) {
934 
935   case 0:  /*InitialDP*/
936     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
937     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
938                                    CAMELSRT_VOICE_INITIALDP);
939     break;
940   case 60: /*InitialDPSMS*/
941     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
942     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
943                                    CAMELSRT_SMS_INITIALDP);
944     break;
945   case 78: /*InitialDPGPRS*/
946     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
947     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
948                                    CAMELSRT_GPRS_INITIALDP);
949     break;
950 
951   case 23: /*RequestReportBCSMEvent*/
952     break;
953 
954   case 63: /*RequestReportSMSEvent*/
955     break;
956 
957   case 81: /*RequestReportGPRSEvent*/
958     break;
959 
960   case 24: /*EventReportBCSMEvent*/
961     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
962                                    CAMELSRT_VOICE_DISC );
963     break;
964 
965   case 64: /*EventReportSMS*/
966     /* Session has been explicity closed without TC_END */
967     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
968     tcapsrt_close((struct tcaphash_context_t *)p_camelsrt_info->tcap_context, pinfo);
969     break;
970 
971   case 80: /*EventReportGPRS*/
972     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
973     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
974                                    CAMELSRT_GPRS_REPORT);
975     break;
976 
977   case 35: /*ApplyCharging*/
978     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
979                                   CAMELSRT_VOICE_ACR1 );
980     break;
981 
982   case 71: /*ApplyChargingGPRS*/
983     break;
984 
985   case 36: /*ApplyChargingReport*/
986     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
987                                    CAMELSRT_VOICE_ACR1 );
988     break;
989 
990   case 72: /*ApplyChargingReportGPRS*/
991     break;
992 
993   case 31: /*Continue*/
994     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
995                                       CAMELSRT_VOICE_INITIALDP);
996     break;
997   case 65: /*ContinueSMS*/
998     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
999                                   CAMELSRT_SMS_INITIALDP);
1000     break;
1001   case 75: /*ContinueGPRS*/
1002     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
1003                                   CAMELSRT_GPRS_INITIALDP);
1004     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
1005                                   CAMELSRT_GPRS_REPORT);
1006     break;
1007 
1008   case 22: /*ReleaseCall*/
1009     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
1010                                       CAMELSRT_VOICE_DISC);
1011     /* Session has been closed by Network */
1012     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
1013     break;
1014 
1015   case 66: /*ReleaseSMS*/
1016     /* Session has been closed by Network */
1017     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
1018     tcapsrt_close((struct tcaphash_context_t *)p_camelsrt_info->tcap_context,pinfo);
1019     break;
1020 
1021   case 79: /*ReleaseGPRS*/
1022     /* Session has been closed by Network */
1023     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
1024     break;
1025   } /* switch opcode */
1026 }
1027 
1028 /*
1029  * Initialize the Message Info used by the main dissector
1030  * Data are linked to a TCAP transaction
1031  */
1032 struct camelsrt_info_t *
camelsrt_razinfo(void)1033 camelsrt_razinfo(void)
1034 {
1035   struct camelsrt_info_t *p_camelsrt_info ;
1036 
1037   /* Global buffer for packet extraction */
1038   camelsrt_global_current++;
1039   if(camelsrt_global_current==MAX_CAMEL_INSTANCE){
1040     camelsrt_global_current=0;
1041   }
1042 
1043   p_camelsrt_info=&camelsrt_global_info[camelsrt_global_current];
1044   memset(p_camelsrt_info,0,sizeof(struct camelsrt_info_t));
1045 
1046   p_camelsrt_info->opcode=255;
1047 
1048   return p_camelsrt_info;
1049 }
1050 
1051 
1052 static guint8 camel_pdu_type = 0;
1053 static guint8 camel_pdu_size = 0;
1054 
1055 
1056 static int
dissect_camel_camelPDU(gboolean implicit_tag _U_,tvbuff_t * tvb,int offset,asn1_ctx_t * actx _U_,proto_tree * tree,int hf_index,struct tcap_private_t * p_private_tcap)1057 dissect_camel_camelPDU(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_,proto_tree *tree,
1058                         int hf_index, struct tcap_private_t * p_private_tcap) {
1059 
1060     opcode = 0;
1061     if (p_private_tcap != NULL){
1062         gp_camelsrt_info->tcap_context=p_private_tcap->context;
1063         if (p_private_tcap->context)
1064             gp_camelsrt_info->tcap_session_id = ( (struct tcaphash_context_t *) (p_private_tcap->context))->session_id;
1065     }
1066 
1067     camel_pdu_type = tvb_get_guint8(tvb, offset)&0x0f;
1068     /* Get the length and add 2 */
1069     camel_pdu_size = tvb_get_guint8(tvb, offset+1)+2;
1070 
1071     /* Populate the info column with PDU type*/
1072     col_add_str(actx->pinfo->cinfo, COL_INFO, val_to_str(camel_pdu_type, camel_Component_vals, "Unknown Camel (%u)"));
1073     col_append_str(actx->pinfo->cinfo, COL_INFO, " ");
1074 
1075     is_ExtensionField =FALSE;
1076     offset = dissect_camel_ROS(TRUE, tvb, offset, actx, tree, hf_index);
1077 
1078     return offset;
1079 }
1080 
1081 static int
dissect_camel_all(int version,const char * col_protocol,const char * suffix,tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1082 dissect_camel_all(int version, const char* col_protocol, const char* suffix,
1083                   tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1084 {
1085   proto_item  *item;
1086   proto_tree  *tree = NULL, *stat_tree = NULL;
1087   struct tcap_private_t * p_private_tcap = (struct tcap_private_t*)data;
1088   asn1_ctx_t asn1_ctx;
1089   asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1090 
1091   col_set_str(pinfo->cinfo, COL_PROTOCOL, col_protocol);
1092 
1093   camel_ver = version;
1094 
1095   /* create display subtree for the protocol */
1096   if(parent_tree){
1097      item = proto_tree_add_item(parent_tree, proto_camel, tvb, 0, -1, ENC_NA);
1098      tree = proto_item_add_subtree(item, ett_camel);
1099      proto_item_append_text(item, "%s", suffix);
1100   }
1101   /* camelsrt reset counter, and initialise global pointer
1102      to store service response time related data */
1103   gp_camelsrt_info=camelsrt_razinfo();
1104 
1105   dissect_camel_camelPDU(FALSE, tvb, 0, &asn1_ctx , tree, -1, p_private_tcap);
1106 
1107   /* If a Tcap context is associated to this transaction */
1108   if (gcamel_HandleSRT &&
1109       gp_camelsrt_info->tcap_context ) {
1110     if (gcamel_DisplaySRT && tree) {
1111       stat_tree = proto_tree_add_subtree(tree, tvb, 0, 0, ett_camel_stat, NULL, "Stat");
1112     }
1113     camelsrt_call_matching(tvb, pinfo, stat_tree, gp_camelsrt_info);
1114     tap_queue_packet(camel_tap, pinfo, gp_camelsrt_info);
1115   }
1116 
1117   return tvb_captured_length(tvb);
1118 }
1119 
1120 static int
dissect_camel_v1(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1121 dissect_camel_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1122 {
1123   return dissect_camel_all(1, "Camel-v1", "-V1", tvb, pinfo, parent_tree, data);
1124 }
1125 
1126 static int
dissect_camel_v2(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1127 dissect_camel_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1128 {
1129   return dissect_camel_all(2, "Camel-v2", "-V2", tvb, pinfo, parent_tree, data);
1130 }
1131 
1132 static int
dissect_camel_v3(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1133 dissect_camel_v3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1134 {
1135   return dissect_camel_all(3, "Camel-v3", "-V3", tvb, pinfo, parent_tree, data);
1136 }
1137 
1138 static int
dissect_camel_v4(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1139 dissect_camel_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1140 {
1141   return dissect_camel_all(4, "Camel-v4", "-V4", tvb, pinfo, parent_tree, data);
1142 }
1143 
1144 static int
dissect_camel(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)1145 dissect_camel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
1146 {
1147   return dissect_camel_all(4, "Camel", "", tvb, pinfo, parent_tree, data);
1148 }
1149 
1150 /* TAP STAT INFO */
1151 typedef enum
1152 {
1153   MESSAGE_TYPE_COLUMN = 0,
1154   COUNT_COLUMN
1155 } camel_stat_columns;
1156 
1157 static stat_tap_table_item camel_stat_fields[] = {{TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "Message Type or Reason", "%-25s"}, {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Count", "%d"}};
1158 
camel_stat_init(stat_tap_table_ui * new_stat)1159 static void camel_stat_init(stat_tap_table_ui* new_stat)
1160 {
1161   const char *table_name = "CAMEL Message Counters";
1162   int num_fields = sizeof(camel_stat_fields)/sizeof(stat_tap_table_item);
1163   stat_tap_table *table;
1164   int i;
1165   stat_tap_table_item_type items[sizeof(camel_stat_fields)/sizeof(stat_tap_table_item)];
1166 
1167   table = stat_tap_find_table(new_stat, table_name);
1168   if (table) {
1169     if (new_stat->stat_tap_reset_table_cb) {
1170       new_stat->stat_tap_reset_table_cb(table);
1171     }
1172     return;
1173   }
1174 
1175   table = stat_tap_init_table(table_name, num_fields, 0, NULL);
1176   stat_tap_add_table(new_stat, table);
1177 
1178   items[MESSAGE_TYPE_COLUMN].type = TABLE_ITEM_STRING;
1179   items[COUNT_COLUMN].type = TABLE_ITEM_UINT;
1180   items[COUNT_COLUMN].value.uint_value = 0;
1181 
1182   /* Add a row for each value type */
1183   for (i = 0; i < camel_MAX_NUM_OPR_CODES; i++)
1184   {
1185     const char *ocs = try_val_to_str(i, camel_opr_code_strings);
1186     char *col_str;
1187     if (ocs) {
1188       col_str = g_strdup_printf("Request %s", ocs);
1189     } else {
1190       col_str = g_strdup_printf("Unknown op code %d", i);
1191     }
1192 
1193     items[MESSAGE_TYPE_COLUMN].value.string_value = col_str;
1194     stat_tap_init_table_row(table, i, num_fields, items);
1195   }
1196 }
1197 
1198 static tap_packet_status
camel_stat_packet(void * tapdata,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * csi_ptr)1199 camel_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *csi_ptr)
1200 {
1201   stat_data_t* stat_data = (stat_data_t*)tapdata;
1202   const struct camelsrt_info_t *csi = (const struct camelsrt_info_t *) csi_ptr;
1203   stat_tap_table* table;
1204   stat_tap_table_item_type* msg_data;
1205 
1206   table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, 0);
1207   if (csi->opcode >= table->num_elements)
1208     return TAP_PACKET_DONT_REDRAW;
1209   msg_data = stat_tap_get_field_data(table, csi->opcode, COUNT_COLUMN);
1210   msg_data->value.uint_value++;
1211   stat_tap_set_field_data(table, csi->opcode, COUNT_COLUMN, msg_data);
1212 
1213   return TAP_PACKET_REDRAW;
1214 }
1215 
1216 static void
camel_stat_reset(stat_tap_table * table)1217 camel_stat_reset(stat_tap_table* table)
1218 {
1219   guint element;
1220   stat_tap_table_item_type* item_data;
1221 
1222   for (element = 0; element < table->num_elements; element++)
1223   {
1224     item_data = stat_tap_get_field_data(table, element, COUNT_COLUMN);
1225     item_data->value.uint_value = 0;
1226     stat_tap_set_field_data(table, element, COUNT_COLUMN, item_data);
1227   }
1228 }
1229 
1230 static void
camel_stat_free_table_item(stat_tap_table * table _U_,guint row _U_,guint column,stat_tap_table_item_type * field_data)1231 camel_stat_free_table_item(stat_tap_table* table _U_, guint row _U_, guint column, stat_tap_table_item_type* field_data)
1232 {
1233   if (column != MESSAGE_TYPE_COLUMN) return;
1234   g_free((char*)field_data->value.string_value);
1235 }
1236 
1237 /*--- proto_reg_handoff_camel ---------------------------------------*/
range_delete_callback(guint32 ssn,gpointer ptr _U_)1238 static void range_delete_callback(guint32 ssn, gpointer ptr _U_)
1239 {
1240   if (ssn) {
1241     delete_itu_tcap_subdissector(ssn, camel_handle);
1242   }
1243 }
1244 
range_add_callback(guint32 ssn,gpointer ptr _U_)1245 static void range_add_callback(guint32 ssn, gpointer ptr _U_)
1246 {
1247   if (ssn) {
1248     add_itu_tcap_subdissector(ssn, camel_handle);
1249   }
1250 }
1251 
proto_reg_handoff_camel(void)1252 void proto_reg_handoff_camel(void) {
1253   static gboolean camel_prefs_initialized = FALSE;
1254   static range_t *ssn_range;
1255 
1256   if (!camel_prefs_initialized) {
1257 
1258     camel_prefs_initialized = TRUE;
1259 
1260     register_ber_oid_dissector_handle("0.4.0.0.1.0.50.0",camel_v1_handle, proto_camel, "CAP-v1-gsmSSF-to-gsmSCF-AC" );
1261     register_ber_oid_dissector_handle("0.4.0.0.1.0.50.1",camel_v2_handle, proto_camel, "CAP-v2-gsmSSF-to-gsmSCF-AC" );
1262     register_ber_oid_dissector_handle("0.4.0.0.1.0.51.1",camel_v2_handle, proto_camel, "CAP-v2-assist-gsmSSF-to-gsmSCF-AC" );
1263     register_ber_oid_dissector_handle("0.4.0.0.1.0.52.1",camel_v2_handle, proto_camel, "CAP-v2-gsmSRF-to-gsmSCF-AC" );
1264 
1265     /* CAMEL Phase 3 Application Context Names */
1266     register_ber_oid_dissector_handle("0.4.0.0.1.21.3.4", camel_v3_handle, proto_camel, "capssf-scfGenericAC");
1267     register_ber_oid_dissector_handle("0.4.0.0.1.21.3.6", camel_v3_handle, proto_camel, "capssf-scfAssistHandoffAC");
1268     register_ber_oid_dissector_handle("0.4.0.0.1.20.3.14", camel_v3_handle, proto_camel, "gsmSRF-gsmSCF-ac");
1269     register_ber_oid_dissector_handle("0.4.0.0.1.21.3.50", camel_v3_handle, proto_camel, "cap3-gprssf-scfAC");
1270     register_ber_oid_dissector_handle("0.4.0.0.1.21.3.51", camel_v3_handle, proto_camel, "cap3-gsmscf-gprsssfAC");
1271     register_ber_oid_dissector_handle("0.4.0.0.1.21.3.61", camel_v3_handle, proto_camel, "cap3-sms-AC");
1272 
1273     /* CAMEL Phase 4 Application Context Names */
1274     register_ber_oid_dissector_handle("0.4.0.0.1.23.3.4", camel_v4_handle, proto_camel, "capssf-scfGenericAC");
1275     register_ber_oid_dissector_handle("0.4.0.0.1.23.3.6", camel_v4_handle, proto_camel, "capssf-scfAssistHandoffAC");
1276     register_ber_oid_dissector_handle("0.4.0.0.1.23.3.8", camel_v4_handle, proto_camel, "capscf-ssfGenericAC");
1277     register_ber_oid_dissector_handle("0.4.0.0.1.22.3.14", camel_v4_handle, proto_camel, "gsmSRF-gsmSCF-ac");
1278     register_ber_oid_dissector_handle("0.4.0.0.1.23.3.61", camel_v4_handle, proto_camel, "cap4-sms-AC");
1279 
1280 
1281 #include "packet-camel-dis-tab.c"
1282   } else {
1283     range_foreach(ssn_range, range_delete_callback, NULL);
1284     wmem_free(wmem_epan_scope(), ssn_range);
1285   }
1286 
1287   ssn_range = range_copy(wmem_epan_scope(), global_ssn_range);
1288 
1289   range_foreach(ssn_range, range_add_callback, NULL);
1290 
1291 }
1292 
proto_register_camel(void)1293 void proto_register_camel(void) {
1294   module_t *camel_module;
1295   /* List of fields */
1296   static hf_register_info hf[] = {
1297     { &hf_camel_extension_code_local,
1298       { "local", "camel.extension_code_local",
1299         FT_INT32, BASE_DEC, NULL, 0,
1300         "Extension local code", HFILL }},
1301         { &hf_camel_error_code_local,
1302       { "local", "camel.error_code_local",
1303         FT_INT32, BASE_DEC, VALS(camel_err_code_string_vals), 0,
1304         "ERROR code", HFILL }},
1305     { &hf_camel_cause_indicator, /* Currently not enabled */
1306       { "Cause indicator",  "camel.cause_indicator",
1307         FT_UINT8, BASE_DEC|BASE_EXT_STRING, &q850_cause_code_vals_ext, 0x7f,
1308         NULL, HFILL }},
1309     { &hf_digit,
1310       { "Digit Value",  "camel.digit_value",
1311         FT_UINT8, BASE_DEC, VALS(digit_value), 0, NULL, HFILL }},
1312     { &hf_camel_PDPTypeNumber_etsi,
1313       { "ETSI defined PDP Type Value",  "camel.PDPTypeNumber_etsi",
1314         FT_UINT8, BASE_HEX, VALS(gsm_map_etsi_defined_pdp_vals), 0,
1315         NULL, HFILL }},
1316     { &hf_camel_PDPTypeNumber_ietf,
1317       { "IETF defined PDP Type Value",  "camel.PDPTypeNumber_ietf",
1318         FT_UINT8, BASE_HEX, VALS(gsm_map_ietf_defined_pdp_vals), 0,
1319         NULL, HFILL }},
1320     { &hf_camel_PDPAddress_IPv4,
1321       { "PDPAddress IPv4",  "camel.PDPAddress_IPv4",
1322         FT_IPv4, BASE_NONE, NULL, 0,
1323         "IPAddress IPv4", HFILL }},
1324     { &hf_camel_PDPAddress_IPv6,
1325       { "PDPAddress IPv6",  "camel.PDPAddress_IPv6",
1326         FT_IPv6, BASE_NONE, NULL, 0,
1327         "IPAddress IPv6", HFILL }},
1328     { &hf_camel_cellGlobalIdOrServiceAreaIdFixedLength,
1329       { "CellGlobalIdOrServiceAreaIdFixedLength", "camel.CellGlobalIdOrServiceAreaIdFixedLength",
1330         FT_BYTES, BASE_NONE, NULL, 0,
1331         "LocationInformationGPRS/CellGlobalIdOrServiceAreaIdOrLAI", HFILL }},
1332     { &hf_camel_RP_Cause,
1333       { "RP Cause",  "camel.RP_Cause",
1334         FT_UINT8, BASE_DEC, VALS(camel_RP_Cause_values), 0x7F,
1335         "RP Cause Value", HFILL }},
1336 
1337     { &hf_camel_CAMEL_AChBillingChargingCharacteristics,
1338       { "CAMEL-AChBillingChargingCharacteristics", "camel.CAMEL_AChBillingChargingCharacteristics",
1339         FT_UINT32, BASE_DEC,  VALS(camel_CAMEL_AChBillingChargingCharacteristics_vals), 0,
1340         NULL, HFILL }},
1341 
1342     { &hf_camel_CAMEL_FCIBillingChargingCharacteristics,
1343       { "CAMEL-FCIBillingChargingCharacteristics", "camel.CAMEL_FCIBillingChargingCharacteristics",
1344         FT_UINT32, BASE_DEC, VALS(camel_CAMEL_FCIBillingChargingCharacteristics_vals), 0,
1345         NULL, HFILL }},
1346 
1347     { &hf_camel_CAMEL_FCIGPRSBillingChargingCharacteristics,
1348       { "CAMEL-FCIGPRSBillingChargingCharacteristics", "camel.CAMEL_FCIGPRSBillingChargingCharacteristics",
1349         FT_UINT32, BASE_DEC, NULL, 0,
1350         NULL, HFILL }},
1351 
1352     { &hf_camel_CAMEL_FCISMSBillingChargingCharacteristics,
1353       { "CAMEL-FCISMSBillingChargingCharacteristics", "camel.CAMEL_FCISMSBillingChargingCharacteristics",
1354         FT_UINT32, BASE_DEC, VALS(camel_CAMEL_FCISMSBillingChargingCharacteristics_vals), 0,
1355         NULL, HFILL }},
1356 
1357     { &hf_camel_CAMEL_SCIBillingChargingCharacteristics,
1358       { "CAMEL-SCIBillingChargingCharacteristics", "camel.CAMEL_SCIBillingChargingCharacteristics",
1359         FT_UINT32, BASE_DEC, VALS(camel_CAMEL_SCIBillingChargingCharacteristics_vals), 0,
1360         NULL, HFILL }},
1361 
1362     { &hf_camel_CAMEL_SCIGPRSBillingChargingCharacteristics,
1363       { "CAMEL-SCIGPRSBillingChargingCharacteristics", "camel.CAMEL_SCIGPRSBillingChargingCharacteristics",
1364         FT_UINT32, BASE_DEC, NULL, 0,
1365         "CAMEL-FSCIGPRSBillingChargingCharacteristics", HFILL }},
1366 
1367     { &hf_camel_CAMEL_CallResult,
1368       { "CAMEL-CAMEL_CallResult", "camel.CAMEL_CallResult",
1369         FT_UINT32, BASE_DEC, VALS(camel_CAMEL_CallResult_vals), 0,
1370         "CAMEL-CallResult", HFILL }},
1371 
1372   /* Camel Service Response Time */
1373     { &hf_camelsrt_SessionId,
1374       { "Session Id",
1375         "camel.srt.session_id",
1376         FT_UINT32, BASE_DEC, NULL, 0x0,
1377         NULL, HFILL }
1378     },
1379     { &hf_camelsrt_RequestNumber,
1380       { "Request Number",
1381         "camel.srt.request_number",
1382         FT_UINT64, BASE_DEC, NULL, 0x0,
1383         NULL, HFILL }
1384     },
1385     { &hf_camelsrt_Duplicate,
1386       { "Request Duplicate",
1387         "camel.srt.duplicate",
1388         FT_UINT32, BASE_DEC, NULL, 0x0,
1389         NULL, HFILL }
1390     },
1391     { &hf_camelsrt_RequestFrame,
1392       { "Requested Frame",
1393         "camel.srt.reqframe",
1394         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1395         "SRT Request Frame", HFILL }
1396     },
1397     { &hf_camelsrt_ResponseFrame,
1398       { "Response Frame",
1399         "camel.srt.rspframe",
1400         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1401         "SRT Response Frame", HFILL }
1402     },
1403     { &hf_camelsrt_DeltaTime,
1404       { "Service Response Time",
1405         "camel.srt.deltatime",
1406         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1407         "DeltaTime between Request and Response", HFILL }
1408     },
1409     { &hf_camelsrt_SessionTime,
1410       { "Session duration",
1411         "camel.srt.sessiontime",
1412         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1413         "Duration of the TCAP session", HFILL }
1414     },
1415     { &hf_camelsrt_DeltaTime31,
1416       { "Service Response Time",
1417         "camel.srt.deltatime31",
1418         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1419         "DeltaTime between InitialDP and Continue", HFILL }
1420     },
1421     { &hf_camelsrt_DeltaTime65,
1422       { "Service Response Time",
1423         "camel.srt.deltatime65",
1424         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1425         "DeltaTime between InitialDPSMS and ContinueSMS", HFILL }
1426     },
1427     { &hf_camelsrt_DeltaTime75,
1428       { "Service Response Time",
1429         "camel.srt.deltatime75",
1430         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1431         "DeltaTime between InitialDPGPRS and ContinueGPRS", HFILL }
1432     },
1433     { &hf_camelsrt_DeltaTime35,
1434       { "Service Response Time",
1435         "camel.srt.deltatime35",
1436         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1437         "DeltaTime between ApplyChargingReport and ApplyCharging", HFILL }
1438     },
1439     { &hf_camelsrt_DeltaTime22,
1440       { "Service Response Time",
1441         "camel.srt.deltatime22",
1442         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1443         "DeltaTime between EventReport(Disconnect) and Release Call", HFILL }
1444     },
1445     { &hf_camelsrt_DeltaTime80,
1446       { "Service Response Time",
1447         "camel.srt.deltatime80",
1448         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1449         "DeltaTime between EventReportGPRS and ContinueGPRS", HFILL }
1450     },
1451 
1452 #ifdef REMOVED
1453 #endif
1454 #include "packet-camel-hfarr.c"
1455   };
1456 
1457   /* List of subtrees */
1458   static gint *ett[] = {
1459     &ett_camel,
1460     &ett_camelisup_parameter,
1461     &ett_camel_AccessPointName,
1462     &ett_camel_pdptypenumber,
1463     &ett_camel_cause,
1464     &ett_camel_RPcause,
1465     &ett_camel_stat,
1466     &ett_camel_calledpartybcdnumber,
1467     &ett_camel_callingpartynumber,
1468     &ett_camel_originalcalledpartyid,
1469     &ett_camel_redirectingpartyid,
1470     &ett_camel_locationnumber,
1471     &ett_camel_additionalcallingpartynumber,
1472     &ett_camel_calledAddressValue,
1473     &ett_camel_callingAddressValue,
1474     &ett_camel_assistingSSPIPRoutingAddress,
1475     &ett_camel_correlationID,
1476     &ett_camel_dTMFDigitsCompleted,
1477     &ett_camel_dTMFDigitsTimeOut,
1478     &ett_camel_number,
1479     &ett_camel_digitsResponse,
1480 
1481 #include "packet-camel-ettarr.c"
1482   };
1483 
1484   static ei_register_info ei[] = {
1485      { &ei_camel_unknown_invokeData, { "camel.unknown.invokeData", PI_MALFORMED, PI_WARN, "Unknown invokeData", EXPFILL }},
1486      { &ei_camel_unknown_returnResultData, { "camel.unknown.returnResultData", PI_MALFORMED, PI_WARN, "Unknown returnResultData", EXPFILL }},
1487      { &ei_camel_unknown_returnErrorData, { "camel.unknown.returnErrorData", PI_MALFORMED, PI_WARN, "Unknown returnResultData", EXPFILL }},
1488   };
1489 
1490   expert_module_t* expert_camel;
1491 
1492   static tap_param camel_stat_params[] = {
1493     { PARAM_FILTER, "filter", "Filter", NULL, TRUE }
1494   };
1495 
1496   static stat_tap_table_ui camel_stat_table = {
1497     REGISTER_STAT_GROUP_TELEPHONY_GSM,
1498     "CAMEL Messages and Response Status",
1499     PSNAME,
1500     "camel,counter",
1501     camel_stat_init,
1502     camel_stat_packet,
1503     camel_stat_reset,
1504     camel_stat_free_table_item,
1505     NULL,
1506     sizeof(camel_stat_fields)/sizeof(stat_tap_table_item), camel_stat_fields,
1507     sizeof(camel_stat_params)/sizeof(tap_param), camel_stat_params,
1508     NULL,
1509     0
1510   };
1511 
1512   /* Register protocol */
1513   proto_camel = proto_register_protocol(PNAME, PSNAME, PFNAME);
1514 
1515   camel_handle = register_dissector("camel", dissect_camel, proto_camel);
1516   camel_v1_handle = register_dissector("camel-v1", dissect_camel_v1, proto_camel);
1517   camel_v2_handle = register_dissector("camel-v2", dissect_camel_v2, proto_camel);
1518   camel_v3_handle = register_dissector("camel-v3", dissect_camel_v3, proto_camel);
1519   camel_v4_handle = register_dissector("camel-v4", dissect_camel_v4, proto_camel);
1520 
1521   proto_register_field_array(proto_camel, hf, array_length(hf));
1522   proto_register_subtree_array(ett, array_length(ett));
1523   expert_camel = expert_register_protocol(proto_camel);
1524   expert_register_field_array(expert_camel, ei, array_length(ei));
1525 
1526   rose_ctx_init(&camel_rose_ctx);
1527 
1528   /* Register dissector tables */
1529   camel_rose_ctx.arg_local_dissector_table = register_dissector_table("camel.ros.local.arg",
1530                                                                       "CAMEL Operation Argument (local opcode)", proto_camel,
1531                                                                       FT_UINT32, BASE_HEX);
1532   camel_rose_ctx.res_local_dissector_table = register_dissector_table("camel.ros.local.res",
1533                                                                       "CAMEL Operation Result (local opcode)", proto_camel,
1534                                                                       FT_UINT32, BASE_HEX);
1535   camel_rose_ctx.err_local_dissector_table = register_dissector_table("camel.ros.local.err",
1536                                                                       "CAMEL Error (local opcode)", proto_camel,
1537                                                                       FT_UINT32, BASE_HEX);
1538 
1539   /* Register our configuration options, particularly our SSNs */
1540   /* Set default SSNs */
1541   range_convert_str(wmem_epan_scope(), &global_ssn_range, "146", MAX_SSN);
1542 
1543   camel_module = prefs_register_protocol(proto_camel, proto_reg_handoff_camel);
1544 
1545   prefs_register_enum_preference(camel_module, "date.format", "Date Format",
1546                                   "The date format: (DD/MM) or (MM/DD)",
1547                                   &date_format, date_options, FALSE);
1548 
1549 
1550   prefs_register_range_preference(camel_module, "tcap.ssn",
1551     "TCAP SSNs",
1552     "TCAP Subsystem numbers used for Camel",
1553     &global_ssn_range, MAX_SSN);
1554 
1555   prefs_register_bool_preference(camel_module, "srt",
1556                                  "Analyze Service Response Time",
1557                                  "Enable response time analysis",
1558                                  &gcamel_HandleSRT);
1559 
1560   prefs_register_bool_preference(camel_module, "persistentsrt",
1561                                  "Persistent stats for SRT",
1562                                  "Statistics for Response Time",
1563                                  &gcamel_PersistentSRT);
1564 
1565   /* Routine for statistic */
1566   register_init_routine(&camelsrt_init_routine);
1567 
1568   /* create new hash-table for SRT */
1569   srt_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), camelsrt_call_hash, camelsrt_call_equal);
1570 
1571   camel_tap=register_tap(PSNAME);
1572 
1573   register_srt_table(proto_camel, PSNAME, 1, camelstat_packet, camelstat_init, NULL);
1574   register_stat_tap_table_ui(&camel_stat_table);
1575 }
1576 
1577 /*
1578  * Editor modelines
1579  *
1580  * Local Variables:
1581  * c-basic-offset: 2
1582  * tab-width: 8
1583  * indent-tabs-mode: nil
1584  * End:
1585  *
1586  * ex: set shiftwidth=2 tabstop=8 expandtab:
1587  * :indentSize=2:tabSize=8:noTabs=true:
1588  */
1589