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