1 /* packet-tcap-template.c
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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * References: ETSI 300 374
31 #include <epan/packet.h>
32 #include <epan/exceptions.h>
33 #include <epan/prefs.h>
34 #include <epan/oids.h>
35 #include <epan/asn1.h>
36 #include <epan/strutil.h>
37 #include <epan/show_exception.h>
40 #include "packet-ber.h"
41 #include "packet-tcap.h"
42 #include <epan/tcap-persistentdata.h>
44 #define PNAME "Transaction Capabilities Application Part"
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;
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;
61 #include "packet-tcap-hf.c"
63 /* Initialize the subtree pointers */
64 static gint ett_tcap
= -1;
65 static gint ett_param
= -1;
67 static gint ett_otid
= -1;
68 static gint ett_dtid
= -1;
69 gint ett_tcap_stat
= -1;
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
;
75 static struct tcaphash_context_t
* gp_tcap_context
=NULL
;
77 #include "packet-tcap-ett.c"
80 static range_t
*global_ssn_range
;
81 static range_t
*ssn_range
;
82 struct tcap_private_t tcap_private
;
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
;
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
;
97 static dissector_handle_t data_handle
;
98 static dissector_handle_t ansi_tcap_handle
;
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_
);
104 static GHashTable
* ansi_sub_dissectors
= NULL
;
105 static GHashTable
* itu_sub_dissectors
= NULL
;
107 static void dissect_tcap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
);
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_uint("sccp.ssn",ssn
,tcap_handle
);
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_uint("sccp.ssn",ssn
,tcap_handle
);
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_uint("sccp.ssn",ssn
,tcap_handle
);
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_uint("sccp.ssn", ssn
,tcap_handle
);
130 dissector_handle_t
get_ansi_tcap_subdissector(guint32 ssn
) {
131 return (dissector_handle_t
)g_hash_table_lookup(ansi_sub_dissectors
,GUINT_TO_POINTER(ssn
));
134 dissector_handle_t
get_itu_tcap_subdissector(guint32 ssn
) {
135 return (dissector_handle_t
)g_hash_table_lookup(itu_sub_dissectors
,GUINT_TO_POINTER(ssn
));
140 #include "packet-tcap-fn.c"
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)" },
154 dissect_tcap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
)
156 proto_item
*item
=NULL
;
157 proto_tree
*tree
=NULL
;
159 struct tcaphash_context_t
* p_tcap_context
;
160 dissector_handle_t subdissector_handle
;
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
178 get_ber_identifier(tvb
, 0, &ber_class
, &pc
, &tag
);
180 if(ber_class
== BER_CLASS_PRI
){
189 call_dissector(ansi_tcap_handle
, tvb
, pinfo
, parent_tree
);
198 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, TRUE
, pinfo
);
200 tcap_top_tree
= parent_tree
;
201 tcap_stat_tree
= NULL
;
203 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TCAP");
205 /* create display subtree for the protocol */
207 item
= proto_tree_add_item(parent_tree
, proto_tcap
, tvb
, 0, -1, ENC_NA
);
208 tree
= proto_item_add_subtree(item
, ett_tcap
);
213 raz_tcap_private(&tcap_private
);
215 asn1_ctx
.value_ptr
= &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);
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
;
225 /* If the current message is TCAP only,
226 * save the Application Context Name for the next messages
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
, sizeof(p_tcap_context
->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
;
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
);
245 proto_reg_handoff_tcap(void)
248 data_handle
= find_dissector("data");
249 ansi_tcap_handle
= find_dissector("ansi_tcap");
250 ber_oid_dissector_table
= find_dissector_table("ber.oid");
252 #include "packet-tcap-dis-tab.c"
255 static void init_tcap(void);
258 proto_register_tcap(void)
261 /* Setup list of header fields See Section 1.6.1 for details*/
262 static hf_register_info hf
[] = {
264 { "Tag", "tcap.msgtype",
265 FT_UINT8
, BASE_HEX
, NULL
, 0,
269 { "Length", "tcap.len",
270 FT_UINT8
, BASE_DEC
, NULL
, 0,
274 { "Data", "tcap.data",
275 FT_BYTES
, BASE_NONE
, NULL
, 0,
279 { "Transaction Id", "tcap.tid",
280 FT_BYTES
, BASE_NONE
, NULL
, 0,
283 /* Tcap Service Response Time */
284 { &hf_tcapsrt_SessionId
,
286 "tcap.srt.session_id",
287 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
290 { &hf_tcapsrt_BeginSession
,
293 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
294 "SRT Begin of Session", HFILL
}
296 { &hf_tcapsrt_EndSession
,
299 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
300 "SRT End of Session", HFILL
}
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
}
308 { &hf_tcapsrt_Duplicate
,
309 { "Session Duplicate",
310 "tcap.srt.duplicate",
311 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
312 "SRT Duplicated with Session", HFILL
}
314 #include "packet-tcap-hfarr.c"
317 /* Setup protocol subtree array */
318 static gint
*ett
[] = {
324 #include "packet-tcap-ettarr.c"
327 /*static enum_val_t tcap_options[] = {
328 { "itu", "ITU", ITU_TCAP_STANDARD },
329 { "ansi", "ANSI", ANSI_TCAP_STANDARD },
333 module_t
*tcap_module
;
335 /* Register the protocol name and description */
336 proto_tcap
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
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
));
342 tcap_module
= prefs_register_protocol(proto_tcap
, NULL
);
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
);
349 prefs_register_obsolete_preference(tcap_module
, "standard");
353 prefs_register_bool_preference(tcap_module
, "lock_info_col", "Lock Info column",
354 "Always show TCAP in Info column",
357 prefs_register_obsolete_preference(tcap_module
, "lock_info_col");
360 /* Set default SSNs */
361 range_convert_str(&global_ssn_range
, "", MAX_SSN
);
362 ssn_range
= range_empty();
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
);
368 prefs_register_bool_preference(tcap_module
, "srt",
369 "Service Response Time Analyse",
370 "Activate the analyse for Response Time",
373 prefs_register_bool_preference(tcap_module
, "persistentsrt",
374 "Persistent stats for SRT",
375 "Statistics for Response Time",
376 >cap_PersistentSRT
);
378 prefs_register_uint_preference(tcap_module
, "repetitiontimeout",
379 "Repetition timeout",
380 "Maximal delay for message repetion",
381 10, >cap_RepetitionTimeout
);
383 prefs_register_uint_preference(tcap_module
, "losttimeout",
385 "Maximal delay for message lost",
386 10, >cap_LostTimeout
);
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
);
391 /* 'globally' register dissector */
392 register_dissector("tcap", dissect_tcap
, proto_tcap
);
394 tcap_handle
= create_dissector_handle(dissect_tcap
, proto_tcap
);
396 register_init_routine(&init_tcap
);
400 static void range_delete_callback(guint32 ssn
)
402 if ( ssn
&& !get_ansi_tcap_subdissector(ssn
) && !get_itu_tcap_subdissector(ssn
) ) {
403 dissector_delete_uint("sccp.ssn", ssn
, tcap_handle
);
407 static void range_add_callback(guint32 ssn
)
409 if (ssn
&& !get_ansi_tcap_subdissector(ssn
) && !get_itu_tcap_subdissector(ssn
) ) {
410 dissector_add_uint("sccp.ssn", ssn
, tcap_handle
);
415 static void init_tcap(void) {
417 range_foreach(ssn_range
, range_delete_callback
);
421 ssn_range
= range_copy(global_ssn_range
);
422 range_foreach(ssn_range
, range_add_callback
);
423 tcapsrt_init_routine();
427 dissect_tcap_param(asn1_ctx_t
*actx
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
429 gint tag_offset
, saved_offset
, len_offset
;
441 while (tvb_reported_length_remaining(tvb
, offset
) > 0)
443 saved_offset
= offset
;
445 offset
= get_ber_identifier(tvb
, offset
, &ber_class
, &pc
, &tag
);
447 offset
= get_ber_length(tvb
, offset
, &len
, &ind_field
);
450 tag_length
= tag_offset
- saved_offset
;
451 len_length
= len_offset
- tag_offset
;
455 pi
= proto_tree_add_text(tree
, tvb
, saved_offset
,
456 len
+ (len_offset
- saved_offset
),
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
,
462 proto_tree_add_uint(subtree
, hf_tcap_tag
, tvb
, saved_offset
,
463 tag_length
, ber_class
);
465 proto_tree_add_uint(subtree
, hf_tcap_length
, tvb
, tag_offset
,
468 if (len
-(2*ind_field
)) /*should always be positive unless we get an empty contructor pointless? */
470 next_tvb
= tvb_new_subset(tvb
, offset
, len
-(2*ind_field
),
472 dissect_tcap_param(actx
, subtree
,next_tvb
,0);
476 proto_tree_add_text(subtree
, tvb
, offset
+len
-2, 2, "CONSTRUCTOR EOC");
482 pi
= proto_tree_add_text(tree
, tvb
, saved_offset
,
483 len
+ (len_offset
- saved_offset
),
484 "Parameter (0x%.2x)", tag
);
486 subtree
= proto_item_add_subtree(pi
, ett_param
);
488 proto_tree_add_uint(subtree
, hf_tcap_tag
, tvb
, saved_offset
,
491 proto_tree_add_uint(subtree
, hf_tcap_length
, tvb
,
492 saved_offset
+tag_length
, len_length
, len
);
494 if (len
) /* check for NULLS */
496 next_tvb
= tvb_new_subset(tvb
, offset
, len
, len
);
497 dissect_ber_octet_string(TRUE
, actx
, tree
, next_tvb
, 0,
507 static void raz_tcap_private(struct tcap_private_t
* p_tcap_private
)
509 memset(p_tcap_private
,0,sizeof(struct tcap_private_t
) );
513 * Call ITU Subdissector to decode the Tcap Component
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_
)
518 dissector_handle_t subdissector_handle
=NULL
;
519 gboolean is_subdissector
=FALSE
;
520 struct tcaphash_context_t
* p_tcap_context
=NULL
;
523 * ok lets look at the oid and ssn and try and find a dissector, otherwise lets decode it.
527 * Handle The TCAP Service Response Time
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
;
536 /* Take the last TCAP context */
537 p_tcap_context
= gp_tcap_context
;
538 tcap_private
.context
=p_tcap_context
;
541 if (p_tcap_context
) {
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
, sizeof(p_tcap_context
->oid
))!=0) {
547 /* ACN, changed, Fallback to lower version
548 * and update the subdissector (purely formal)
550 g_strlcpy(p_tcap_context
->oid
,cur_oid
, sizeof(p_tcap_context
->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
;
557 /* We do not have the OID in the TCAP context, so store it */
558 g_strlcpy(p_tcap_context
->oid
, cur_oid
, sizeof(p_tcap_context
->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
;
566 /* Not found, so try to find a subdissector according to SSN */
567 if ( (subdissector_handle
= get_itu_tcap_subdissector(actx
->pinfo
->match_uint
))) {
568 /* Found according to SSN */
569 p_tcap_context
->subdissector_handle
=subdissector_handle
;
570 p_tcap_context
->subdissector_present
=TRUE
;
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
;
581 } /* no 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
;
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
;
597 if (!is_subdissector
) {
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
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
)) ) {
609 is_subdissector
=TRUE
;
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_uint
))) {
614 /* Found according to SSN */
615 is_subdissector
=TRUE
;
617 /* Nothing found, take the Data handler */
618 subdissector_handle
= data_handle
;
619 is_subdissector
=TRUE
;
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_uint
))) {
625 /* Found according to SSN */
626 is_subdissector
=TRUE
;
628 subdissector_handle
= data_handle
;
629 is_subdissector
=TRUE
;
633 /* We have it already */
636 /* Call the sub dissector if present, and not already called */
638 call_dissector_with_data(subdissector_handle
, tvb
, actx
->pinfo
, tree
, actx
->value_ptr
);
643 void call_tcap_dissector(dissector_handle_t handle
, tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
) {
645 requested_subdissector_handle
= handle
;
648 dissect_tcap(tvb
, pinfo
, tree
);
650 requested_subdissector_handle
= NULL
;
654 requested_subdissector_handle
= NULL
;