#include <stdio.h> not needed.
[obnox/wireshark/wip.git] / asn1 / tcap / packet-tcap-template.c
1 /* packet-tcap-template.c
2  * Routines for  TCAP
3  * Copyright 2004 - 2005, Tim Endean <endeant@hotmail.com>
4  * Built from the gsm-map dissector Copyright 2004 - 2005, Anders Broman <anders.broman@ericsson.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  * References: ETSI 300 374
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
35 #include <epan/oids.h>
36 #include <epan/asn1.h>
37 #include <epan/strutil.h>
38
39 #include <string.h>
40 #include "packet-ber.h"
41 #include "packet-tcap.h"
42 #include <epan/tcap-persistentdata.h>
43
44 #define PNAME  "Transaction Capabilities Application Part"
45 #define PSNAME "TCAP"
46 #define PFNAME "tcap"
47
48 /* Initialize the protocol and registered fields */
49 static int proto_tcap = -1;
50 static int hf_tcap_tag = -1;
51 static int hf_tcap_length = -1;
52 static int hf_tcap_data = -1;
53 static int hf_tcap_tid = -1;
54
55 int hf_tcapsrt_SessionId=-1;
56 int hf_tcapsrt_Duplicate=-1;
57 int hf_tcapsrt_BeginSession=-1;
58 int hf_tcapsrt_EndSession=-1;
59 int hf_tcapsrt_SessionTime=-1;
60
61 #include "packet-tcap-hf.c"
62
63 /* Initialize the subtree pointers */
64 static gint ett_tcap = -1;
65 static gint ett_param = -1;
66
67 static gint ett_otid = -1;
68 static gint ett_dtid = -1;
69 gint ett_tcap_stat = -1;
70
71 static struct tcapsrt_info_t * gp_tcapsrt_info;
72 static gboolean tcap_subdissector_used=FALSE;
73 static dissector_handle_t requested_subdissector_handle = NULL;
74
75 static struct tcaphash_context_t * gp_tcap_context=NULL;
76
77 #include "packet-tcap-ett.c"
78
79 #define MAX_SSN 254
80 static range_t *global_ssn_range;
81 static range_t *ssn_range;
82 struct tcap_private_t tcap_private;
83
84 gboolean gtcap_HandleSRT=FALSE;
85 extern gboolean gtcap_PersistentSRT;
86 extern gboolean gtcap_DisplaySRT;
87 extern guint gtcap_RepetitionTimeout;
88 extern guint gtcap_LostTimeout;
89
90 static dissector_handle_t       tcap_handle = NULL;
91 static dissector_table_t ber_oid_dissector_table;
92 static const char * cur_oid;
93 static const char * tcapext_oid;
94 static proto_tree * tcap_top_tree=NULL;
95 static proto_tree * tcap_stat_tree=NULL;
96
97 static dissector_handle_t data_handle;
98 static dissector_handle_t ansi_tcap_handle;
99
100 static void raz_tcap_private(struct tcap_private_t * p_tcap_private);
101 static int dissect_tcap_param(asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset);
102 static int dissect_tcap_ITU_ComponentPDU(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index _U_);
103
104 static GHashTable* ansi_sub_dissectors = NULL;
105 static GHashTable* itu_sub_dissectors = NULL;
106
107 static void dissect_tcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree);
108
109 extern void add_ansi_tcap_subdissector(guint32 ssn, dissector_handle_t dissector) {
110     g_hash_table_insert(ansi_sub_dissectors,GUINT_TO_POINTER(ssn),dissector);
111     dissector_add("sccp.ssn",ssn,tcap_handle);
112 }
113
114 extern void add_itu_tcap_subdissector(guint32 ssn, dissector_handle_t dissector) {
115     g_hash_table_insert(itu_sub_dissectors,GUINT_TO_POINTER(ssn),dissector);
116     dissector_add("sccp.ssn",ssn,tcap_handle);
117 }
118
119 extern void delete_ansi_tcap_subdissector(guint32 ssn, dissector_handle_t dissector _U_) {
120     g_hash_table_remove(ansi_sub_dissectors,GUINT_TO_POINTER(ssn));
121     if (!get_itu_tcap_subdissector(ssn))
122       dissector_delete("sccp.ssn",ssn,tcap_handle);
123 }
124 extern void delete_itu_tcap_subdissector(guint32 ssn, dissector_handle_t dissector _U_) {
125     g_hash_table_remove(itu_sub_dissectors,GUINT_TO_POINTER(ssn));
126     if (!get_ansi_tcap_subdissector(ssn))
127       dissector_delete("sccp.ssn", ssn,tcap_handle);
128 }
129
130 dissector_handle_t get_ansi_tcap_subdissector(guint32 ssn) {
131     return g_hash_table_lookup(ansi_sub_dissectors,GUINT_TO_POINTER(ssn));
132 }
133
134 dissector_handle_t get_itu_tcap_subdissector(guint32 ssn) {
135     return g_hash_table_lookup(itu_sub_dissectors,GUINT_TO_POINTER(ssn));
136 }
137
138
139
140 #include "packet-tcap-fn.c"
141
142
143
144 const value_string tcap_component_type_str[] = {
145     { TCAP_COMP_INVOKE,         "Invoke" },
146     { TCAP_COMP_RRL,            "Return Result(L)" },
147     { TCAP_COMP_RE,                     "Return Error" },
148     { TCAP_COMP_REJECT,         "Reject" },
149     { TCAP_COMP_RRN,            "Return Result(NL)" },
150     { 0,                        NULL } };
151
152
153 static void
154 dissect_tcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
155 {
156     proto_item          *item=NULL;
157     proto_tree          *tree=NULL;
158
159     struct tcaphash_context_t * p_tcap_context;
160     dissector_handle_t subdissector_handle;
161         asn1_ctx_t asn1_ctx;
162         gint8 class;
163         gboolean pc;
164         gint tag;
165
166         /* Check if ANSI TCAP and call the ANSI TCAP dissector if that's the case 
167          * PackageType ::= CHOICE { unidirectional                      [PRIVATE 1] IMPLICIT UniTransactionPDU,
168          *                                               queryWithPerm                          [PRIVATE 2] IMPLICIT TransactionPDU,
169          *                                               queryWithoutPerm                       [PRIVATE 3] IMPLICIT TransactionPDU,
170          *                                               response                                       [PRIVATE 4] IMPLICIT TransactionPDU,
171          *                                               conversationWithPerm           [PRIVATE 5] IMPLICIT TransactionPDU,
172          *                                               conversationWithoutPerm        [PRIVATE 6] IMPLICIT TransactionPDU,
173          *                                               abort                                          [PRIVATE 22] IMPLICIT Abort 
174          *                                               }
175          *      
176          * 
177          */
178         get_ber_identifier(tvb, 0, &class, &pc, &tag);
179
180         if(class == BER_CLASS_PRI){
181                 switch(tag){
182                 case 1:
183                 case 2:
184                 case 3:
185                 case 4:
186                 case 5:
187                 case 6:
188                 case 22:
189                         call_dissector(ansi_tcap_handle, tvb, pinfo, parent_tree);
190                         return;
191                         break;
192                 default:
193                         return;
194                 }
195         }
196
197         /* ITU TCAP */
198         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
199
200     tcap_top_tree = parent_tree;
201     tcap_stat_tree = NULL;
202
203     col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCAP");
204
205     /* create display subtree for the protocol */
206     if(parent_tree){
207       item = proto_tree_add_item(parent_tree, proto_tcap, tvb, 0, -1, FALSE);
208       tree = proto_item_add_subtree(item, ett_tcap);
209       tcap_stat_tree=tree;
210     }
211     cur_oid = NULL;
212     tcapext_oid = NULL;
213     raz_tcap_private(&tcap_private);
214
215     pinfo->private_data = &tcap_private;
216     gp_tcapsrt_info=tcapsrt_razinfo();
217     tcap_subdissector_used=FALSE;
218     gp_tcap_context=NULL;
219     dissect_tcap_TCMessage(FALSE, tvb, 0, &asn1_ctx, tree, -1);
220
221     if (gtcap_HandleSRT && !tcap_subdissector_used ) {
222       p_tcap_context=tcapsrt_call_matching(tvb, pinfo, tcap_stat_tree, gp_tcapsrt_info);
223       tcap_private.context=p_tcap_context;
224
225                 /* If the current message is TCAP only,
226                  * save the Application Context Name for the next messages
227                  */
228                 if ( p_tcap_context && cur_oid && !p_tcap_context->oid_present ) {
229                         /* Save the application context and the sub dissector */
230                         g_strlcpy(p_tcap_context->oid,cur_oid, LENGTH_OID);
231                         p_tcap_context->oid_present=TRUE;
232                         if ( (subdissector_handle = dissector_get_string_handle(ber_oid_dissector_table, cur_oid)) ) {
233                                 p_tcap_context->subdissector_handle=subdissector_handle;
234                                 p_tcap_context->subdissector_present=TRUE;
235                         }
236                 }
237                 if (gtcap_HandleSRT && p_tcap_context && p_tcap_context->callback) {
238                         /* Callback fonction for the upper layer */
239                         (p_tcap_context->callback)(tvb, pinfo, tcap_stat_tree, p_tcap_context);
240                 }
241         }
242 }
243
244 void
245 proto_reg_handoff_tcap(void)
246 {
247
248     data_handle = find_dissector("data");
249     ansi_tcap_handle = find_dissector("ansi_tcap");
250     ber_oid_dissector_table = find_dissector_table("ber.oid");
251
252 #include "packet-tcap-dis-tab.c"
253 }
254
255 static void init_tcap(void);
256
257 void
258 proto_register_tcap(void)
259 {
260
261 /* Setup list of header fields  See Section 1.6.1 for details*/
262     static hf_register_info hf[] = {
263         { &hf_tcap_tag,
264                 { "Tag",           "tcap.msgtype",
265                 FT_UINT8, BASE_HEX, NULL, 0,
266                 NULL, HFILL }
267         },
268         { &hf_tcap_length,
269                 { "Length", "tcap.len",
270                 FT_UINT8, BASE_DEC, NULL, 0,
271                 NULL, HFILL }
272         },
273         { &hf_tcap_data,
274                 { "Data", "tcap.data",
275                 FT_BYTES, BASE_NONE, NULL, 0,
276                 NULL, HFILL }
277         },
278                 { &hf_tcap_tid,
279                 { "Transaction Id", "tcap.tid",
280                 FT_BYTES, BASE_NONE, NULL, 0,
281                 NULL, HFILL }
282         },
283         /* Tcap Service Response Time */
284         { &hf_tcapsrt_SessionId,
285           { "Session Id",
286             "tcap.srt.session_id",
287             FT_UINT32, BASE_DEC, NULL, 0x0,
288             NULL, HFILL }
289         },
290         { &hf_tcapsrt_BeginSession,
291           { "Begin Session",
292             "tcap.srt.begin",
293             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
294             "SRT Begin of Session", HFILL }
295         },
296         { &hf_tcapsrt_EndSession,
297           { "End Session",
298             "tcap.srt.end",
299             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
300             "SRT End of Session", HFILL }
301         },
302         { &hf_tcapsrt_SessionTime,
303           { "Session duration",
304             "tcap.srt.sessiontime",
305             FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
306             "Duration of the TCAP session", HFILL }
307         },
308         { &hf_tcapsrt_Duplicate,
309           { "Session Duplicate",
310             "tcap.srt.duplicate",
311             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
312             "SRT Duplicated with Session", HFILL }
313         },
314 #include "packet-tcap-hfarr.c"
315     };
316
317 /* Setup protocol subtree array */
318     static gint *ett[] = {
319         &ett_tcap,
320         &ett_param,
321         &ett_otid,
322         &ett_dtid,
323         &ett_tcap_stat,
324         #include "packet-tcap-ettarr.c"
325     };
326
327     /*static enum_val_t tcap_options[] = {
328         { "itu", "ITU",  ITU_TCAP_STANDARD },
329         { "ansi", "ANSI", ANSI_TCAP_STANDARD },
330         { NULL, NULL, 0 }
331     };*/
332
333     module_t *tcap_module;
334
335 /* Register the protocol name and description */
336     proto_tcap = proto_register_protocol(PNAME, PSNAME, PFNAME);
337
338 /* Required function calls to register the header fields and subtrees used */
339     proto_register_field_array(proto_tcap, hf, array_length(hf));
340     proto_register_subtree_array(ett, array_length(ett));
341
342     tcap_module = prefs_register_protocol(proto_tcap, NULL);
343
344 #if 0
345     prefs_register_enum_preference(tcap_module, "standard", "ITU TCAP standard",
346         "The SS7 standard used in ITU TCAP packets",
347         &tcap_standard, tcap_options, FALSE);
348 #else
349     prefs_register_obsolete_preference(tcap_module, "standard");
350 #endif
351
352 #if 0
353     prefs_register_bool_preference(tcap_module, "lock_info_col", "Lock Info column",
354         "Always show TCAP in Info column",
355         &lock_info_col);
356 #else
357     prefs_register_obsolete_preference(tcap_module, "lock_info_col");
358 #endif
359
360     /* Set default SSNs */
361     range_convert_str(&global_ssn_range, "", MAX_SSN);
362     ssn_range = range_empty();
363
364     prefs_register_range_preference(tcap_module, "ssn", "SCCP SSNs",
365         "SCCP (and SUA) SSNs to decode as TCAP",
366         &global_ssn_range, MAX_SSN);
367
368     prefs_register_bool_preference(tcap_module, "srt",
369                                    "Service Response Time Analyse",
370                                    "Activate the analyse for Response Time",
371                                    &gtcap_HandleSRT);
372
373     prefs_register_bool_preference(tcap_module, "persistentsrt",
374                                    "Persistent stats for SRT",
375                                    "Statistics for Response Time",
376                                    &gtcap_PersistentSRT);
377
378     prefs_register_uint_preference(tcap_module, "repetitiontimeout",
379                                    "Repetition timeout",
380                                    "Maximal delay for message repetion",
381                                    10, &gtcap_RepetitionTimeout);
382
383     prefs_register_uint_preference(tcap_module, "losttimeout",
384                                    "lost timeout",
385                                    "Maximal delay for message lost",
386                                    10, &gtcap_LostTimeout);
387
388     ansi_sub_dissectors = g_hash_table_new(g_direct_hash,g_direct_equal);
389     itu_sub_dissectors = g_hash_table_new(g_direct_hash,g_direct_equal);
390
391     /* 'globally' register dissector */
392     register_dissector("tcap", dissect_tcap, proto_tcap);
393
394     tcap_handle = create_dissector_handle(dissect_tcap, proto_tcap);
395
396     register_init_routine(&init_tcap);
397 }
398
399
400 static void range_delete_callback(guint32 ssn)
401 {
402     if ( ssn && !get_ansi_tcap_subdissector(ssn) && !get_itu_tcap_subdissector(ssn) ) {
403         dissector_delete("sccp.ssn", ssn, tcap_handle);
404     }
405 }
406
407 static void range_add_callback(guint32 ssn)
408 {
409     if (ssn && !get_ansi_tcap_subdissector(ssn) && !get_itu_tcap_subdissector(ssn) ) {
410         dissector_add("sccp.ssn", ssn, tcap_handle);
411     }
412 }
413
414
415 static void init_tcap(void) {
416     if (ssn_range) {
417         range_foreach(ssn_range, range_delete_callback);
418         g_free(ssn_range);
419     }
420
421     ssn_range = range_copy(global_ssn_range);
422     range_foreach(ssn_range, range_add_callback);
423     tcapsrt_init_routine();
424 }
425
426 static int
427 dissect_tcap_param(asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset)
428 {
429     gint tag_offset, saved_offset, len_offset;
430     tvbuff_t    *next_tvb;
431     proto_tree *subtree;
432     proto_item *pi;
433     gint8 class;
434     gboolean pc;
435     gint32 tag;
436     guint32 len;
437     guint32 tag_length;
438     guint32 len_length;
439     gboolean ind_field;
440
441     while (tvb_reported_length_remaining(tvb, offset) > 0)
442     {
443         saved_offset = offset;
444
445         offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
446         tag_offset = offset;
447         offset = get_ber_length(tvb, offset, &len, &ind_field);
448         len_offset = offset;
449
450         tag_length = tag_offset - saved_offset;
451         len_length = len_offset - tag_offset;
452
453         if (pc)
454         {
455             pi = proto_tree_add_text(tree, tvb, saved_offset,
456                                      len + (len_offset - saved_offset),
457                                      "CONSTRUCTOR");
458             subtree = proto_item_add_subtree(pi, ett_param);
459             proto_tree_add_uint_format(subtree, hf_tcap_tag, tvb,
460                                        saved_offset, tag_length, tag,
461                                        "CONSTRUCTOR Tag");
462             proto_tree_add_uint(subtree, hf_tcap_tag, tvb, saved_offset,
463                                 tag_length, class);
464
465             proto_tree_add_uint(subtree, hf_tcap_length, tvb, tag_offset,
466                                 len_length, len);
467
468             if (len-(2*ind_field)) /*should always be positive unless we get an empty contructor pointless? */
469             {
470                 next_tvb = tvb_new_subset(tvb, offset, len-(2*ind_field),
471                                           len-(2*ind_field));
472                 dissect_tcap_param(actx, subtree,next_tvb,0);
473             }
474
475             if (ind_field)
476                     proto_tree_add_text(subtree, tvb, offset+len-2, 2, "CONSTRUCTOR EOC");
477
478             offset += len;
479         }
480         else
481         {
482             pi = proto_tree_add_text(tree, tvb, saved_offset,
483                                      len + (len_offset - saved_offset),
484                                      "Parameter (0x%.2x)", tag);
485
486             subtree = proto_item_add_subtree(pi, ett_param);
487
488             proto_tree_add_uint(subtree, hf_tcap_tag, tvb, saved_offset,
489                                 tag_length, tag);
490
491             proto_tree_add_uint(subtree, hf_tcap_length, tvb,
492                                 saved_offset+tag_length, len_length, len);
493
494             if (len) /* check for NULLS */
495             {
496                 next_tvb = tvb_new_subset(tvb, offset, len, len);
497                 dissect_ber_octet_string(TRUE, actx, tree, next_tvb, 0,
498                                          hf_tcap_data, NULL);
499             }
500
501             offset += len;
502         }
503     }
504     return offset;
505 }
506
507 static void raz_tcap_private(struct tcap_private_t * p_tcap_private)
508 {
509   memset(p_tcap_private,0,sizeof(struct tcap_private_t) );
510 }
511
512 /*
513  * Call ITU Subdissector to decode the Tcap Component
514  */
515 static int
516 dissect_tcap_ITU_ComponentPDU(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index _U_)
517 {
518   dissector_handle_t subdissector_handle=NULL;
519   gboolean is_subdissector=FALSE;
520   struct tcaphash_context_t * p_tcap_context=NULL;
521
522   /*
523    * ok lets look at the oid and ssn and try and find a dissector, otherwise lets decode it.
524    */
525
526   /*
527    * Handle The TCAP Service Response Time
528    */
529   if ( gtcap_HandleSRT ) {
530           if (!tcap_subdissector_used) {
531             p_tcap_context=tcapsrt_call_matching(tvb, actx->pinfo, tcap_stat_tree, gp_tcapsrt_info);
532             tcap_subdissector_used=TRUE;
533             gp_tcap_context=p_tcap_context;
534             tcap_private.context=p_tcap_context;
535           }else{
536                   /* Take the last TCAP context */
537                   p_tcap_context = gp_tcap_context;
538                   tcap_private.context=p_tcap_context;
539           }
540   }
541   if (p_tcap_context) {
542           if (cur_oid) {
543                   if (p_tcap_context->oid_present) {
544                           /* We have already an Application Context, check if we have
545                              to fallback to a lower version */
546                           if ( strncmp(p_tcap_context->oid,cur_oid, LENGTH_OID)!=0) {
547                                   /* ACN, changed, Fallback to lower version
548                                    * and update the subdissector (purely formal)
549                                    */
550                                   g_strlcpy(p_tcap_context->oid,cur_oid, LENGTH_OID);
551                                   if ( (subdissector_handle = dissector_get_string_handle(ber_oid_dissector_table, cur_oid)) ) {
552                                           p_tcap_context->subdissector_handle=subdissector_handle;
553                                           p_tcap_context->subdissector_present=TRUE;
554                                   }
555                           }
556                   } else {
557                           /* We do not have the OID in the TCAP context, so store it */
558                           g_strlcpy(p_tcap_context->oid,cur_oid, LENGTH_OID);
559                           p_tcap_context->oid_present=TRUE;
560                           /* Try to find a subdissector according to OID */
561                           if ( (subdissector_handle
562                                   = dissector_get_string_handle(ber_oid_dissector_table, cur_oid)) ) {
563                                   p_tcap_context->subdissector_handle=subdissector_handle;
564                                   p_tcap_context->subdissector_present=TRUE;
565                           } else {
566                             /* Not found, so try to find a subdissector according to SSN */
567                             if ( (subdissector_handle = get_itu_tcap_subdissector(actx->pinfo->match_port))) {
568                               /* Found according to SSN */
569                               p_tcap_context->subdissector_handle=subdissector_handle;
570                               p_tcap_context->subdissector_present=TRUE;
571                             }
572                           }
573                   } /* context OID */
574           } else {
575                   /* Copy the OID from the TCAP context to the current oid */
576                   if (p_tcap_context->oid_present) {
577                           tcap_private.oid= (void*) p_tcap_context->oid;
578                           tcap_private.acv=TRUE;
579                   }
580           } /* no OID */
581   } /* no TCAP context */
582
583
584   if ( p_tcap_context
585        && p_tcap_context->subdissector_present) {
586     /* Take the subdissector from the context */
587     subdissector_handle=p_tcap_context->subdissector_handle;
588     is_subdissector=TRUE;
589   }
590
591   /* Have SccpUsersTable protocol taking precedence over sccp.ssn table */
592   if (!is_subdissector && requested_subdissector_handle) {
593           is_subdissector = TRUE;
594           subdissector_handle = requested_subdissector_handle;
595   }
596
597   if (!is_subdissector) {
598     /*
599      * If we do not currently know the subdissector, we have to find it
600      * - first, according to the OID
601      * - then according to the SSN
602      * - and at least, take the default Data handler
603      */
604     if (ber_oid_dissector_table && cur_oid) {
605       /* Search if we can find the sub protocol according to the A.C.N */
606       if ( (subdissector_handle
607             = dissector_get_string_handle(ber_oid_dissector_table, cur_oid)) ) {
608                   /* found */
609                   is_subdissector=TRUE;
610       } else {
611                   /* Search if we can found the sub protocol according to the SSN table */
612                   if ( (subdissector_handle
613                           = get_itu_tcap_subdissector(actx->pinfo->match_port))) {
614                           /* Found according to SSN */
615                           is_subdissector=TRUE;
616                   } else {
617                           /* Nothing found, take the Data handler */
618                           subdissector_handle = data_handle;
619                           is_subdissector=TRUE;
620                   } /* SSN */
621           } /* ACN */
622         } else {
623                 /* There is no A.C.N for this transaction, so search in the SSN table */
624                 if ( (subdissector_handle = get_itu_tcap_subdissector(actx->pinfo->match_port))) {
625                         /* Found according to SSN */
626                         is_subdissector=TRUE;
627                 } else {
628                         subdissector_handle = data_handle;
629                         is_subdissector=TRUE;
630                 }
631         } /* OID */
632   } else {
633           /* We have it already */
634   }
635
636   /* Call the sub dissector if present, and not already called */
637   if (is_subdissector)
638     call_dissector(subdissector_handle, tvb, actx->pinfo, tree);
639
640   return offset;
641 }
642
643 void call_tcap_dissector(dissector_handle_t handle, tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree) {
644
645         requested_subdissector_handle = handle;
646
647         TRY {
648                 dissect_tcap(tvb, pinfo, tree);
649         } CATCH_ALL {
650                 requested_subdissector_handle = NULL;
651                 RETHROW;
652         } ENDTRY;
653
654         requested_subdissector_handle = NULL;
655
656 }
657
658