Add an additional "title" attribute for UAT fields; that's what's
[obnox/wireshark/wip.git] / epan / camel-persistentdata.c
1 /*
2  * camel-persistentdata.c
3  * Source for lists and hash tables used in wireshark's camel dissector
4  * for calculation of delays in camel calls
5  * Copyright 2006 Florent Drouin
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include <epan/emem.h>
37 #include "epan/packet.h"
38 #include "epan/tap.h"
39 #include <epan/asn1.h>
40 #include "epan/camel-persistentdata.h"
41 #include "epan/dissectors/packet-tcap.h"
42 #include "epan/dissectors/packet-mtp3.h"
43
44 const value_string  camelSRTtype_naming[]= {
45   { CAMELSRT_SESSION,         "TCAP_Session" },
46   { CAMELSRT_VOICE_INITIALDP, "InialDP/Continue" },
47   { CAMELSRT_VOICE_ACR1,      "Slice1_ACR/ACH" },
48   { CAMELSRT_VOICE_ACR2,      "Slice2_ACR/ACH" },
49   { CAMELSRT_VOICE_ACR3,      "Slice3_ACR/ACH" },
50   { CAMELSRT_VOICE_DISC,      "EvtRepBSCM/Release" },
51   { CAMELSRT_SMS_INITIALDP,   "InitialDP/ContinueSMS" },
52   { CAMELSRT_GPRS_INITIALDP,  "InitialDP/ContinueGPRS" },
53   { CAMELSRT_GPRS_REPORT,     "EvtRepGPRS/ContinueGPRS" },
54   { 0,NULL}
55 };
56
57 static gint camelsrt_call_equal(gconstpointer k1, gconstpointer k2);
58 static guint camelsrt_call_hash(gconstpointer k);
59 static struct camelsrt_call_t *find_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key);
60 static struct camelsrt_call_t *new_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key);
61
62 static void update_camelsrt_call(struct camelsrt_call_t *p_camelsrt_call,
63                                  packet_info *pinfo, guint msg_category);
64
65 static void camelsrt_begin_call_matching(packet_info *pinfo,
66                                          struct camelsrt_info_t *p_camelsrt_info);
67
68 static void camelsrt_request_call_matching(tvbuff_t *tvb, packet_info *pinfo,
69                                            proto_tree *tree,
70                                            struct camelsrt_info_t *p_camelsrt_info,
71                                            guint srt_type);
72
73 static void camelsrt_report_call_matching(tvbuff_t *tvb, packet_info *pinfo,
74                                           proto_tree *tree,
75                                           struct camelsrt_info_t *p_camelsrt_info,
76                                           guint srt_type);
77
78 static void camelsrt_close_call_matching(packet_info *pinfo,
79                                          struct camelsrt_info_t *p_camelsrt_info);
80
81 static void camelsrt_display_DeltaTime(proto_tree *tree, tvbuff_t *tvb,
82                                        nstime_t *value_ptr, guint category);
83
84 static void raz_camelsrt_call (struct camelsrt_call_t *p_camelsrt_call);
85
86 void camelsrt_tcap_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
87                             struct tcaphash_context_t *tcap_context);
88
89 /* When several Camel components are received in a single TCAP message,
90    we have to use several buffers for the stored parameters
91    because else this data are erased during TAP dissector call */
92 #define MAX_CAMEL_INSTANCE 10
93 int camelsrt_global_current=0;
94 struct camelsrt_info_t camelsrt_global_info[MAX_CAMEL_INSTANCE];
95
96 /* Configuration parameters to enable or disable the Service Response Time */
97 extern gboolean gcamel_HandleSRT;
98 gboolean gcamel_PersistentSRT=FALSE;
99 gboolean gcamel_DisplaySRT=FALSE;
100 gboolean gcamel_StatSRT=FALSE;
101
102 extern int camel_tap;
103
104 extern int hf_camelsrt_SessionId;
105 extern int hf_camelsrt_RequestNumber;
106 extern int hf_camelsrt_Duplicate;
107 extern int hf_camelsrt_RequestFrame;
108 extern int hf_camelsrt_ResponseFrame;
109 extern int hf_camelsrt_DeltaTime;
110 extern int hf_camelsrt_SessionTime;
111 extern int hf_camelsrt_DeltaTime31;
112 extern int hf_camelsrt_DeltaTime75;
113 extern int hf_camelsrt_DeltaTime65;
114 extern int hf_camelsrt_DeltaTime22;
115 extern int hf_camelsrt_DeltaTime35;
116 extern int hf_camelsrt_DeltaTime80;
117
118 /* Global hash tables*/
119 static GHashTable *srt_calls = NULL;
120 guint32 camelsrt_global_SessionId=1;
121
122 /*
123  * DEBUG fonctions
124  */
125
126 #undef DEBUG_CAMELSRT
127 /* #define DEBUG_CAMELSRT */
128
129 #ifdef DEBUG_CAMELSRT
130 #include <stdio.h>
131 #include <stdarg.h>
132 static unsigned debug_level = 99;
133
134 static void dbg(unsigned  level, char *fmt, ...) {
135   va_list ap;
136
137   if (level > debug_level) return;
138   va_start(ap,fmt);
139   vfprintf(stderr, fmt, ap);
140   va_end(ap);
141 }
142 #endif
143
144 /*
145  * Functions needed for Hash-Table
146  */
147
148 /* compare 2 keys */
149 static gint
150 camelsrt_call_equal(gconstpointer k1, gconstpointer k2)
151 {
152   const struct camelsrt_call_info_key_t *key1 = (const struct camelsrt_call_info_key_t *) k1;
153   const struct camelsrt_call_info_key_t *key2 = (const struct camelsrt_call_info_key_t *) k2;
154
155   return (key1->SessionIdKey == key2->SessionIdKey) ;
156 }
157
158 /* calculate a hash key */
159 static guint
160 camelsrt_call_hash(gconstpointer k)
161 {
162   const struct camelsrt_call_info_key_t *key = (const struct camelsrt_call_info_key_t *) k;
163   return key->SessionIdKey;
164 }
165
166 /*
167  * Find the dialog by Key and Time
168  */
169 static struct camelsrt_call_t *
170 find_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key)
171 {
172   struct camelsrt_call_t *p_camelsrt_call = NULL;
173   p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, p_camelsrt_call_key);
174
175   if(p_camelsrt_call) {
176 #ifdef DEBUG_CAMELSRT
177     dbg(10,"D%d ", p_camelsrt_call->session_id);
178 #endif
179   } else {
180 #ifdef DEBUG_CAMELSRT
181     dbg(23,"Not in hash ");
182 #endif
183   }
184
185   return p_camelsrt_call;
186 }
187
188 /*
189  * New record to create, to identify a new transaction
190  */
191 static struct camelsrt_call_t *
192 new_camelsrt_call(struct camelsrt_call_info_key_t *p_camelsrt_call_key)
193 {
194   struct camelsrt_call_info_key_t *p_new_camelsrt_call_key;
195   struct camelsrt_call_t *p_new_camelsrt_call = NULL;
196
197   /* Register the transaction in the hash table
198      with the tcap transaction Id as main Key
199      Once created, this entry will be updated later */
200
201   p_new_camelsrt_call_key = se_alloc(sizeof(struct camelsrt_call_info_key_t));
202   p_new_camelsrt_call_key->SessionIdKey = p_camelsrt_call_key->SessionIdKey;
203   p_new_camelsrt_call = se_alloc(sizeof(struct camelsrt_call_t));
204   raz_camelsrt_call(p_new_camelsrt_call);
205   p_new_camelsrt_call->session_id = camelsrt_global_SessionId++;
206 #ifdef DEBUG_CAMELSRT
207   dbg(10,"D%d ", p_new_camelsrt_call->session_id);
208 #endif
209   /* store it */
210   g_hash_table_insert(srt_calls, p_new_camelsrt_call_key, p_new_camelsrt_call);
211   return p_new_camelsrt_call;
212 }
213
214 /*
215  * Update a record with the data of the Request
216  */
217 static void
218 update_camelsrt_call(struct camelsrt_call_t *p_camelsrt_call, packet_info *pinfo,
219                      guint msg_category)
220 {
221   p_camelsrt_call->category[msg_category].req_num = pinfo->fd->num;
222   p_camelsrt_call->category[msg_category].rsp_num = 0;
223   p_camelsrt_call->category[msg_category].responded = FALSE;
224   p_camelsrt_call->category[msg_category].req_time = pinfo->fd->abs_ts;
225 }
226
227
228 /*
229  * Routine called when the TAP is initialized.
230  * so hash table are (re)created
231  */
232 void
233 camelsrt_init_routine(void)
234 {
235
236   /* free hash-tables and mem_chunks for SRT */
237   if (srt_calls != NULL) {
238 #ifdef DEBUG_CAMELSRT
239     dbg(16,"Destroy hash ");
240 #endif
241     g_hash_table_destroy(srt_calls);
242   }
243
244   /* create new hash-tables and mem_chunks for SRT */
245   srt_calls = g_hash_table_new(camelsrt_call_hash, camelsrt_call_equal);
246 #ifdef DEBUG_CAMELSRT
247   dbg(16,"Create hash ");
248 #endif
249   /* Reset the session counter */
250   camelsrt_global_SessionId=1;
251
252   /* The Display of SRT is enable
253    * 1) For wireshark only if Persistent Stat is enable
254    * 2) For Tshark, if the SRT handling is enable
255    */
256   gcamel_DisplaySRT=gcamel_PersistentSRT || gcamel_HandleSRT&gcamel_StatSRT;
257 }
258
259 /*
260  * Service Response Time analyze, called just after the camel dissector
261  * According to the camel operation, we
262  * - open/close a context for the camel session
263  * - look for a request, or look for the corresponding response
264  */
265 void
266 camelsrt_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
267                        struct camelsrt_info_t *p_camelsrt_info)
268 {
269
270 #ifdef DEBUG_CAMELSRT
271   dbg(10,"tcap_session #%d ", p_camelsrt_info->tcap_session_id);
272 #endif
273
274   switch (p_camelsrt_info->opcode) {
275
276   case 0:  /*InitialDP*/
277     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
278     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
279                                    CAMELSRT_VOICE_INITIALDP);
280     break;
281   case 60: /*InitialDPSMS*/
282     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
283     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
284                                    CAMELSRT_SMS_INITIALDP);
285     break;
286   case 78: /*InitialDPGPRS*/
287     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
288     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
289                                    CAMELSRT_GPRS_INITIALDP);
290     break;
291
292   case 23: /*RequestReportBCSMEvent*/
293     break;
294
295   case 63: /*RequestReportSMSEvent*/
296     break;
297
298   case 81: /*RequestReportGPRSEvent*/
299     break;
300
301   case 24: /*EventReportBCSMEvent*/
302     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
303                                    CAMELSRT_VOICE_DISC );
304     break;
305
306   case 64: /*EventReportSMS*/
307     /* Session has been explicity closed without TC_END */
308     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
309     tcapsrt_close(p_camelsrt_info->tcap_context, pinfo);
310     break;
311
312   case 80: /*EventReportGPRS*/
313     camelsrt_begin_call_matching(pinfo, p_camelsrt_info);
314     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
315                                    CAMELSRT_GPRS_REPORT);
316     break;
317
318   case 35: /*ApplyCharging*/
319     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
320                                   CAMELSRT_VOICE_ACR1 );
321     break;
322
323   case 71: /*ApplyChargingGPRS*/
324     break;
325
326   case 36: /*ApplyChargingReport*/
327     camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info,
328                                    CAMELSRT_VOICE_ACR1 );
329     break;
330
331   case 72: /*ApplyChargingReportGPRS*/
332     break;
333
334   case 31: /*Continue*/
335     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
336                                   CAMELSRT_VOICE_INITIALDP);
337     break;
338   case 65: /*ContinueSMS*/
339     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
340                                   CAMELSRT_SMS_INITIALDP);
341     break;
342   case 75: /*ContinueGPRS*/
343     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
344                                   CAMELSRT_GPRS_INITIALDP);
345     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
346                                   CAMELSRT_GPRS_REPORT);
347     break;
348
349   case 22: /*ReleaseCall*/
350     camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info,
351                                   CAMELSRT_VOICE_DISC);
352     /* Session has been closed by Network */
353     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
354     break;
355
356   case 66: /*ReleaseSMS*/
357     /* Session has been closed by Network */
358     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
359     tcapsrt_close(p_camelsrt_info->tcap_context,pinfo);
360     break;
361
362   case 79: /*ReleaseGPRS*/
363     /* Session has been closed by Network */
364     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
365     break;
366   } /* switch opcode */
367 }
368
369 /*
370  * Callback function for the TCAP dissector
371  * This callback function is used to inform the camel layer, that the session
372  * has been Closed or Aborted by a TCAP message without Camel component
373  * So, we can close the context for camel session, and update the stats.
374  */
375 void
376 camelsrt_tcap_matching(tvbuff_t *tvb _U_, packet_info *pinfo,
377                        proto_tree *tree _U_,
378                        struct tcaphash_context_t *p_tcap_context)
379 {
380   struct camelsrt_info_t *p_camelsrt_info;
381
382 #ifdef DEBUG_CAMELSRT
383   dbg(11,"Camel_CallBack ");
384 #endif
385   p_camelsrt_info=camelsrt_razinfo();
386
387   p_camelsrt_info->tcap_context=p_tcap_context;
388   if (p_tcap_context) {
389 #ifdef DEBUG_CAMELSRT
390     dbg(11,"Close TCAP ");
391 #endif
392     p_camelsrt_info->tcap_session_id = p_tcap_context->session_id;
393     camelsrt_close_call_matching(pinfo, p_camelsrt_info);
394     tap_queue_packet(camel_tap, pinfo, p_camelsrt_info);
395   }
396 }
397
398
399 /*
400  * Create the record identifiying the Camel session
401  * As the Tcap session id given by the TCAP dissector is uniq, it will be
402  * used as main key.
403  */
404 static void
405 camelsrt_begin_call_matching(packet_info *pinfo,
406                              struct camelsrt_info_t *p_camelsrt_info)
407 {
408   struct camelsrt_call_t *p_camelsrt_call;
409   struct camelsrt_call_info_key_t camelsrt_call_key;
410
411   p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
412
413   /* prepare the key data */
414   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
415
416   /* look up the request */
417 #ifdef DEBUG_CAMELSRT
418   dbg(10,"\n Session begin #%u\n", pinfo->fd->num);
419   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
420 #endif
421   p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, &camelsrt_call_key);
422   if (p_camelsrt_call) {
423     /* We have seen this request before -> do nothing */
424 #ifdef DEBUG_CAMELSRT
425     dbg(22,"Already seen ");
426 #endif
427   } else { /* p_camelsrt_call has not been found */
428 #ifdef DEBUG_CAMELSRT
429     dbg(10,"New key %lu ",camelsrt_call_key.SessionIdKey);
430 #endif
431     p_camelsrt_call = new_camelsrt_call(&camelsrt_call_key);
432     p_camelsrt_call->tcap_context=p_camelsrt_info->tcap_context;
433     update_camelsrt_call(p_camelsrt_call, pinfo,CAMELSRT_SESSION);
434
435 #ifdef DEBUG_CAMELSRT
436     dbg(11,"Update Callback ");
437 #endif
438     p_camelsrt_call->tcap_context->callback=camelsrt_tcap_matching;
439   }
440 }
441
442 /*
443  * Register the request, and try to find the response
444  *
445  */
446 static void
447 camelsrt_request_call_matching(tvbuff_t *tvb, packet_info *pinfo,
448                                proto_tree *tree,
449                                struct camelsrt_info_t *p_camelsrt_info,
450                                guint srt_type )
451 {
452   struct camelsrt_call_t *p_camelsrt_call;
453   struct camelsrt_call_info_key_t camelsrt_call_key;
454   proto_item *ti, *hidden_item;
455
456 #ifdef DEBUG_CAMELSRT
457   dbg(10,"\n %s #%u\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num);
458 #endif
459
460   /* look only for matching request, if matching conversation is available. */
461   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
462
463 #ifdef DEBUG_CAMELSRT
464   dbg(11,"Search key %lu ", camelsrt_call_key.SessionIdKey);
465 #endif
466   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
467   if(p_camelsrt_call) {
468 #ifdef DEBUG_CAMELSRT
469     dbg(12,"Found ");
470 #endif
471     if (gcamel_DisplaySRT)
472       proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
473
474
475     /* Hmm.. As there are several slices ApplyChargingReport/ApplyCharging
476      * we will prepare the measurement for 3 slices with 3 categories */
477     if (srt_type==CAMELSRT_VOICE_ACR1) {
478       if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num == 0) {
479         srt_type=CAMELSRT_VOICE_ACR1;
480       } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num == 0)
481                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0)
482                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num < pinfo->fd->num) ) {
483         srt_type=CAMELSRT_VOICE_ACR2;
484       } else  if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num == 0)
485                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0)
486                    && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num < pinfo->fd->num) ) {
487         srt_type=CAMELSRT_VOICE_ACR3;
488       } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
489                  && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num > pinfo->fd->num) {
490         srt_type=CAMELSRT_VOICE_ACR1;
491       } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0
492                    && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num > pinfo->fd->num) {
493         srt_type=CAMELSRT_VOICE_ACR2;
494       } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0
495                   && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num > pinfo->fd->num) {
496         srt_type=CAMELSRT_VOICE_ACR3;
497       }
498 #ifdef DEBUG_CAMELSRT
499       dbg(70,"Request ACR %u ",srt_type);
500       dbg(70,"ACR1 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num);
501       dbg(70,"ACR2 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num);
502       dbg(70,"ACR3 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num);
503 #endif
504     } /* not ACR */
505     p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
506
507
508     if (p_camelsrt_call->category[srt_type].req_num == 0) {
509       /* We have not yet seen a request to that call, so this must be the first request
510          remember its frame number. */
511 #ifdef DEBUG_CAMELSRT
512       dbg(5,"Set reqlink #%u ", pinfo->fd->num);
513 #endif
514       update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
515     } else {
516       /* We have seen a request to this call - but was it *this* request? */
517       if (p_camelsrt_call->category[srt_type].req_num != pinfo->fd->num) {
518
519         if (srt_type!=CAMELSRT_VOICE_DISC) {
520           /* No, so it's a duplicate resquest. Mark it as such. */
521 #ifdef DEBUG_CAMELSRT
522           dbg(21,"Display_duplicate with req %d ", p_camelsrt_call->category[srt_type].req_num);
523 #endif
524           p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE;
525           if (gcamel_DisplaySRT){
526             hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
527                 PROTO_ITEM_SET_HIDDEN(hidden_item);
528           }
529
530         } else {
531           /* Ignore duplicate frame */
532           if (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) {
533             p_camelsrt_call->category[srt_type].req_num = pinfo->fd->num;
534 #ifdef DEBUG_CAMELSRT
535             dbg(5,"DISC Set reqlink #%u ", pinfo->fd->num);
536 #endif
537             update_camelsrt_call(p_camelsrt_call, pinfo, srt_type);
538           } /* greater frame */
539         } /* DISC */
540       } /* req_num already seen */
541     } /* req_num != 0 */
542
543       /* add link to response frame, if available */
544     if ( gcamel_DisplaySRT &&
545          (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
546          (p_camelsrt_call->category[srt_type].req_num != 0) &&
547          (p_camelsrt_call->category[srt_type].req_num == pinfo->fd->num) ) {
548 #ifdef DEBUG_CAMELSRT
549       dbg(20,"Display_framersplink %d ",p_camelsrt_call->category[srt_type].rsp_num);
550 #endif
551       ti = proto_tree_add_uint_format(tree, hf_camelsrt_RequestFrame, tvb, 0, 0,
552                                       p_camelsrt_call->category[srt_type].rsp_num,
553                                       "Linked response %s in frame %u",
554                                       val_to_str(srt_type, camelSRTtype_naming, "Unk"),
555                                       p_camelsrt_call->category[srt_type].rsp_num);
556       PROTO_ITEM_SET_GENERATED(ti);
557     } /* frame valid */
558   } /* call reference */
559 }
560
561
562 /*
563  * Check if the received message is a response to a previous request
564  * registered is the camel session context.
565  */
566 static void
567 camelsrt_report_call_matching(tvbuff_t *tvb, packet_info *pinfo,
568                               proto_tree *tree,
569                               struct camelsrt_info_t *p_camelsrt_info,
570                               guint srt_type)
571 {
572   struct camelsrt_call_t *p_camelsrt_call;
573   struct camelsrt_call_info_key_t camelsrt_call_key;
574   nstime_t delta;
575   proto_item *ti, *hidden_item;
576
577 #ifdef DEBUG_CAMELSRT
578   dbg(10,"\n %s #%u\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num);
579 #endif
580   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
581   /* look only for matching request, if matching conversation is available. */
582
583 #ifdef DEBUG_CAMELSRT
584   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
585 #endif
586   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
587   if(p_camelsrt_call) {
588 #ifdef DEBUG_CAMELSRT
589     dbg(12,"Found, req=%d ",p_camelsrt_call->category[srt_type].req_num);
590 #endif
591     if ( gcamel_DisplaySRT )
592       proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id);
593
594     if (srt_type==CAMELSRT_VOICE_ACR1) {
595       if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num != 0
596           && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num < pinfo->fd->num) {
597         srt_type=CAMELSRT_VOICE_ACR1;
598       } else  if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num != 0
599                    && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num < pinfo->fd->num) {
600         srt_type=CAMELSRT_VOICE_ACR2;
601       } else  if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num != 0
602                   && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num < pinfo->fd->num) {
603         srt_type=CAMELSRT_VOICE_ACR1;
604       }
605 #ifdef DEBUG_CAMELSRT
606       dbg(70,"Report ACR %u ",srt_type);
607 #endif
608     } /* not ACR */
609     p_camelsrt_info->bool_msginfo[srt_type]=TRUE;
610
611     if (p_camelsrt_call->category[srt_type].rsp_num == 0) {
612       if  ( (p_camelsrt_call->category[srt_type].req_num != 0)
613             && (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) ){
614         /* We have not yet seen a response to that call, so this must be the first response;
615            remember its frame number only if response comes after request */
616 #ifdef DEBUG_CAMELSRT
617         dbg(14,"Set reslink #%d req %u ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num);
618 #endif
619         p_camelsrt_call->category[srt_type].rsp_num = pinfo->fd->num;
620
621       } else {
622 #ifdef DEBUG_CAMELSRT
623         dbg(2,"badreslink #%u req %u ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num);
624 #endif
625       } /* req_num != 0 */
626     } else { /* rsp_num != 0 */
627       /* We have seen a response to this call - but was it *this* response? */
628       if (p_camelsrt_call->category[srt_type].rsp_num != pinfo->fd->num) {
629         /* No, so it's a duplicate response. Mark it as such. */
630 #ifdef DEBUG_CAMELSRT
631         dbg(21,"Display_duplicate rsp=%d ", p_camelsrt_call->category[srt_type].rsp_num);
632 #endif
633         p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE;
634         if ( gcamel_DisplaySRT ){
635           hidden_item = proto_tree_add_uint(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77);
636           PROTO_ITEM_SET_HIDDEN(hidden_item);
637         }
638       }
639     } /* rsp_num != 0 */
640
641     if ( (p_camelsrt_call->category[srt_type].req_num != 0) &&
642          (p_camelsrt_call->category[srt_type].rsp_num != 0) &&
643          (p_camelsrt_call->category[srt_type].rsp_num == pinfo->fd->num) ) {
644
645       p_camelsrt_call->category[srt_type].responded = TRUE;
646       p_camelsrt_info->msginfo[srt_type].request_available = TRUE;
647 #ifdef DEBUG_CAMELSRT
648       dbg(20,"Display_frameReqlink %d ",p_camelsrt_call->category[srt_type].req_num);
649 #endif
650       /* Indicate the frame to which this is a reply. */
651       if ( gcamel_DisplaySRT ) {
652         ti = proto_tree_add_uint_format(tree, hf_camelsrt_ResponseFrame, tvb, 0, 0,
653                                         p_camelsrt_call->category[srt_type].req_num,
654                                         "Linked request %s in frame %u",
655                                         val_to_str(srt_type, camelSRTtype_naming, "Unk"),
656                                         p_camelsrt_call->category[srt_type].req_num);
657         PROTO_ITEM_SET_GENERATED(ti);
658       }
659       /* Calculate Service Response Time */
660       nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[srt_type].req_time);
661
662       p_camelsrt_info->msginfo[srt_type].is_delta_time = TRUE;
663       p_camelsrt_info->msginfo[srt_type].delta_time = delta; /* give it to tap */
664       p_camelsrt_info->msginfo[srt_type].req_time = p_camelsrt_call->category[srt_type].req_time;
665
666       /* display Service Response Time and make it filterable */
667       camelsrt_display_DeltaTime(tree, tvb, &delta, srt_type);
668
669     } /*req_num != 0 && not duplicate */
670   } /* call reference found */
671 }
672
673 /*
674  * Update the Camel session info, and close the session.
675  * Then remove the associated context, if we do not have persistentSRT enable
676  */
677 static void
678 camelsrt_close_call_matching(packet_info *pinfo,
679                              struct camelsrt_info_t *p_camelsrt_info)
680 {
681   struct camelsrt_call_t *p_camelsrt_call;
682   struct camelsrt_call_info_key_t camelsrt_call_key;
683   nstime_t delta;
684
685   p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE;
686 #ifdef DEBUG_CAMELSRT
687   dbg(10,"\n Session end #%u\n", pinfo->fd->num);
688 #endif
689   /* look only for matching request, if matching conversation is available. */
690   camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id;
691
692 #ifdef DEBUG_CAMELSRT
693   dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey);
694 #endif
695   p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key);
696   if(p_camelsrt_call) {
697 #ifdef DEBUG_CAMELSRT
698     dbg(12,"Found ");
699 #endif
700     /* Calculate Service Response Time */
701     nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[CAMELSRT_SESSION].req_time);
702     p_camelsrt_call->category[CAMELSRT_SESSION].responded = TRUE;
703     p_camelsrt_info->msginfo[CAMELSRT_SESSION].request_available = TRUE;
704     p_camelsrt_info->msginfo[CAMELSRT_SESSION].is_delta_time = TRUE;
705     p_camelsrt_info->msginfo[CAMELSRT_SESSION].delta_time = delta; /* give it to tap */
706     p_camelsrt_info->msginfo[CAMELSRT_SESSION].req_time = p_camelsrt_call->category[CAMELSRT_SESSION].req_time;
707
708     if ( !gcamel_PersistentSRT ) {
709       g_hash_table_remove(srt_calls, &camelsrt_call_key);
710 #ifdef DEBUG_CAMELSRT
711       dbg(20,"remove hash ");
712 #endif
713     } else {
714 #ifdef DEBUG_CAMELSRT
715       dbg(20,"keep hash ");
716 #endif
717     }
718   } /* call reference found */
719 }
720
721 /*
722  * Display the delta time between two messages in a field corresponding
723  * to the category (hf_camelsrt_DeltaTimexx).
724  */
725 static void
726 camelsrt_display_DeltaTime(proto_tree *tree, tvbuff_t *tvb, nstime_t *value_ptr,
727                            guint category)
728 {
729   proto_item *ti;
730
731   if ( gcamel_DisplaySRT ) {
732     switch(category) {
733     case CAMELSRT_VOICE_INITIALDP:
734       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime31, tvb, 0, 0, value_ptr);
735       PROTO_ITEM_SET_GENERATED(ti);
736       break;
737
738     case CAMELSRT_VOICE_ACR1:
739     case CAMELSRT_VOICE_ACR2:
740     case CAMELSRT_VOICE_ACR3:
741       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime22, tvb, 0, 0, value_ptr);
742       PROTO_ITEM_SET_GENERATED(ti);
743       break;
744
745     case CAMELSRT_VOICE_DISC:
746       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime35, tvb, 0, 0, value_ptr);
747       PROTO_ITEM_SET_GENERATED(ti);
748       break;
749
750     case CAMELSRT_GPRS_INITIALDP:
751       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime75, tvb, 0, 0, value_ptr);
752       PROTO_ITEM_SET_GENERATED(ti);
753       break;
754
755     case CAMELSRT_GPRS_REPORT:
756       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime80, tvb, 0, 0, value_ptr);
757       PROTO_ITEM_SET_GENERATED(ti);
758       break;
759
760     case CAMELSRT_SMS_INITIALDP:
761       ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime65, tvb, 0, 0, value_ptr);
762       PROTO_ITEM_SET_GENERATED(ti);
763       break;
764
765     default:
766       break;
767     }
768   }
769 }
770
771 /*
772  * Initialize the Message Info used by the main dissector
773  * Data are linked to a TCAP transaction
774  */
775 struct camelsrt_info_t *
776 camelsrt_razinfo(void)
777 {
778   struct camelsrt_info_t *p_camelsrt_info ;
779
780   /* Global buffer for packet extraction */
781   camelsrt_global_current++;
782   if(camelsrt_global_current==MAX_CAMEL_INSTANCE){
783     camelsrt_global_current=0;
784   }
785
786   p_camelsrt_info=&camelsrt_global_info[camelsrt_global_current];
787   memset(p_camelsrt_info,0,sizeof(struct camelsrt_info_t));
788
789   p_camelsrt_info->opcode=255;
790
791   return p_camelsrt_info;
792 }
793
794 /*
795  * Initialize the data per call for the Service Response Time Statistics
796  * Data are linked to a Camel operation in a TCAP transaction
797  */
798 static void
799 raz_camelsrt_call (struct camelsrt_call_t *p_camelsrt_call)
800 {
801   memset(p_camelsrt_call,0,sizeof(struct camelsrt_call_t));
802 }