MSWSP: use GuidPropertySet_find_guid() in parse_CFullPropSpec()
[wireshark-wip.git] / asn1 / tcap / packet-tcap-template.c
blob869ac0f9c9c8f8700da6b86e2efd1926a1d09251
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>
6 * $Id$
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
28 #include "config.h"
30 #include <glib.h>
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>
39 #include <string.h>
40 #include "packet-ber.h"
41 #include "packet-tcap.h"
42 #include <epan/tcap-persistentdata.h>
44 #define PNAME "Transaction Capabilities Application Part"
45 #define PSNAME "TCAP"
46 #define PFNAME "tcap"
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"
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;
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)" },
150 { 0, NULL } };
153 static void
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;
161 asn1_ctx_t asn1_ctx;
162 gint8 ber_class;
163 gboolean pc;
164 gint tag;
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){
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;
197 /* ITU TCAP */
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 */
206 if(parent_tree){
207 item = proto_tree_add_item(parent_tree, proto_tcap, tvb, 0, -1, ENC_NA);
208 tree = proto_item_add_subtree(item, ett_tcap);
209 tcap_stat_tree=tree;
211 cur_oid = NULL;
212 tcapext_oid = NULL;
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);
244 void
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);
257 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[] = {
263 { &hf_tcap_tag,
264 { "Tag", "tcap.msgtype",
265 FT_UINT8, BASE_HEX, NULL, 0,
266 NULL, HFILL }
268 { &hf_tcap_length,
269 { "Length", "tcap.len",
270 FT_UINT8, BASE_DEC, NULL, 0,
271 NULL, HFILL }
273 { &hf_tcap_data,
274 { "Data", "tcap.data",
275 FT_BYTES, BASE_NONE, NULL, 0,
276 NULL, HFILL }
278 { &hf_tcap_tid,
279 { "Transaction Id", "tcap.tid",
280 FT_BYTES, BASE_NONE, NULL, 0,
281 NULL, HFILL }
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 }
290 { &hf_tcapsrt_BeginSession,
291 { "Begin Session",
292 "tcap.srt.begin",
293 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
294 "SRT Begin of Session", HFILL }
296 { &hf_tcapsrt_EndSession,
297 { "End Session",
298 "tcap.srt.end",
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[] = {
319 &ett_tcap,
320 &ett_param,
321 &ett_otid,
322 &ett_dtid,
323 &ett_tcap_stat,
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 },
330 { NULL, NULL, 0 }
331 };*/
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);
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
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
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",
371 &gtcap_HandleSRT);
373 prefs_register_bool_preference(tcap_module, "persistentsrt",
374 "Persistent stats for SRT",
375 "Statistics for Response Time",
376 &gtcap_PersistentSRT);
378 prefs_register_uint_preference(tcap_module, "repetitiontimeout",
379 "Repetition timeout",
380 "Maximal delay for message repetion",
381 10, &gtcap_RepetitionTimeout);
383 prefs_register_uint_preference(tcap_module, "losttimeout",
384 "lost timeout",
385 "Maximal delay for message lost",
386 10, &gtcap_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) {
416 if (ssn_range) {
417 range_foreach(ssn_range, range_delete_callback);
418 g_free(ssn_range);
421 ssn_range = range_copy(global_ssn_range);
422 range_foreach(ssn_range, range_add_callback);
423 tcapsrt_init_routine();
426 static int
427 dissect_tcap_param(asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb, int offset)
429 gint tag_offset, saved_offset, len_offset;
430 tvbuff_t *next_tvb;
431 proto_tree *subtree;
432 proto_item *pi;
433 gint8 ber_class;
434 gboolean pc;
435 gint32 tag;
436 guint32 len;
437 guint32 tag_length;
438 guint32 len_length;
439 gboolean ind_field;
441 while (tvb_reported_length_remaining(tvb, offset) > 0)
443 saved_offset = offset;
445 offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
446 tag_offset = offset;
447 offset = get_ber_length(tvb, offset, &len, &ind_field);
448 len_offset = offset;
450 tag_length = tag_offset - saved_offset;
451 len_length = len_offset - tag_offset;
453 if (pc)
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, ber_class);
465 proto_tree_add_uint(subtree, hf_tcap_length, tvb, tag_offset,
466 len_length, len);
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),
471 len-(2*ind_field));
472 dissect_tcap_param(actx, subtree,next_tvb,0);
475 if (ind_field)
476 proto_tree_add_text(subtree, tvb, offset+len-2, 2, "CONSTRUCTOR EOC");
478 offset += len;
480 else
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,
489 tag_length, tag);
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,
498 hf_tcap_data, NULL);
501 offset += len;
504 return offset;
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
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_)
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;
535 }else{
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) {
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, 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;
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, 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;
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_uint))) {
568 /* Found according to SSN */
569 p_tcap_context->subdissector_handle=subdissector_handle;
570 p_tcap_context->subdissector_present=TRUE;
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;
580 } /* no OID */
581 } /* no TCAP context */
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;
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)) ) {
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_uint))) {
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_uint))) {
625 /* Found according to SSN */
626 is_subdissector=TRUE;
627 } else {
628 subdissector_handle = data_handle;
629 is_subdissector=TRUE;
631 } /* OID */
632 } else {
633 /* We have it already */
636 /* Call the sub dissector if present, and not already called */
637 if (is_subdissector)
638 call_dissector_with_data(subdissector_handle, tvb, actx->pinfo, tree, actx->value_ptr);
640 return offset;
643 void call_tcap_dissector(dissector_handle_t handle, tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree) {
645 requested_subdissector_handle = handle;
647 TRY {
648 dissect_tcap(tvb, pinfo, tree);
649 } CATCH_ALL {
650 requested_subdissector_handle = NULL;
651 RETHROW;
652 } ENDTRY;
654 requested_subdissector_handle = NULL;