From Anders Broman:
[obnox/wireshark/wip.git] / packet-tcap.c
1 /* packet-tcap.c
2  * Routines for TCAP dissection
3  *
4  * Copyright 2000, Samuel Qu <samuel.qu [AT] utstar.com>,
5  *
6  * Michael Lum <mlum [AT] telostech.com>,
7  * Modified for ANSI TCAP support and many changes for
8  * EOC matching.  (2003)
9  *
10  * (append your name here for newer version)
11  *
12  * $Id: packet-tcap.c,v 1.1 2003/10/02 06:13:28 guy Exp $
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
17  *
18  * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
19  * is a dissector file; if you just copied this from README.developer,
20  * don't bother with the "Copied from" - you don't even need to put
21  * in a "Copied from" if you copied an existing dissector, especially
22  * if the bulk of the code in the new dissector is your code)
23  *
24  * This program is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU General Public License
26  * as published by the Free Software Foundation; either version 2
27  * of the License, or (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program; if not, write to the Free Software
36  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 # include "config.h"
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <gmodule.h>
47
48 #ifdef HAVE_SYS_TYPES_H
49 # include <sys/types.h>
50 #endif
51
52 #ifdef HAVE_NETINET_IN_H
53 # include <netinet/in.h>
54 #endif
55
56 #include <glib.h>
57
58 #ifdef NEED_SNPRINTF_H
59 # include "snprintf.h"
60 #endif
61
62 #include <epan/packet.h>
63 #include "prefs.h"
64 #include "packet-tcap.h"
65 #include "asn1.h"
66
67 Tcap_Standard_Type tcap_standard = ITU_TCAP_STANDARD;
68
69 void proto_reg_handoff_tcap(void);
70
71 /* saved pinfo */
72 static packet_info *g_pinfo = NULL;
73 static proto_tree *g_tcap_tree = NULL;
74 static gboolean g_tcap_ends_def_len = FALSE;
75
76 /* Initialize the protocol and registered fields */
77 static int proto_tcap = -1;
78 static int hf_tcap_message_type = -1;
79 static int hf_ansi_tcap_message_type = -1;
80 static int hf_tcap_none = -1;
81 static int hf_tcap_tag = -1;
82 static int hf_tcap_length = -1;
83 static int hf_tcap_bytes = -1;
84 static int hf_tcap_app_con_name = -1;
85 static int hf_tcap_id = -1;
86 static int hf_tcap_tid = -1;
87 static int hf_tcap_ssn = -1; /* faked */
88 static int hf_tcap_dlg_type = -1;
89 static int hf_tcap_cmp_type = -1;
90 static int hf_ansi_tcap_cmp_type = -1;
91 static int hf_tcap_int = -1;
92
93 /* Initialize the subtree pointers */
94 static gint ett_tcap = -1;
95 /* Samuel */
96 static gint ett_otid = -1;
97 static gint ett_dtid = -1;
98 static gint ett_dlg_portion = -1;
99 static gint ett_dlg_req = -1;
100 static gint ett_dlg_rsp = -1;
101 static gint ett_dlg_abrt = -1;
102 static gint ett_cmp_portion = -1;
103 static gint ett_reason = -1;
104 static gint ett_component = -1;
105 static gint ett_problem = -1;
106 static gint ett_error = -1;
107 static gint ett_params = -1;
108 static gint ett_param = -1;
109
110 static dissector_handle_t data_handle;
111 static dissector_table_t tcap_itu_ssn_dissector_table; /* map use ssn in sccp */
112 static dissector_table_t tcap_ansi_ssn_dissector_table; /* map use ssn in sccp */
113 static gboolean lock_info_col = TRUE;
114
115 #define TC_SEQ_TAG 0x30
116 #define TC_SET_TAG 0x31
117
118 #define TC_EOC_LEN      2 /* 0x00 0x00 */
119
120 /* TCAP transaction message type definition - Samuel */
121 #define ST_MSG_TYP_UNI 0x61 /*0b01100001*/
122 #define ST_MSG_TYP_BGN 0x62 /*0b01100010*/
123 #define ST_MSG_TYP_CNT 0x65 /*0b01100101*/
124 #define ST_MSG_TYP_END 0x64 /*0b01100100*/
125 #define ST_MSG_TYP_PABT 0x67 /*0b01100111*/
126 static const value_string msg_type_strings[] = {
127         { ST_MSG_TYP_UNI, "TC-UNI" },
128         { ST_MSG_TYP_BGN, "TC-BEGIN" },
129         { ST_MSG_TYP_CNT, "TC-CONTINUE" },
130         { ST_MSG_TYP_END, "TC-END" },
131         { ST_MSG_TYP_PABT, "TC-PABORT" },
132         { 0, NULL },
133 };
134
135 /* ANSI TCAP transaction message type definition */
136 #define ANSI_ST_MSG_TYP_UNI 0xe1
137 #define ANSI_ST_MSG_TYP_QWP 0xe2
138 #define ANSI_ST_MSG_TYP_QWOP 0xe3
139 #define ANSI_ST_MSG_TYP_RSP 0xe4
140 #define ANSI_ST_MSG_TYP_CWP 0xe5
141 #define ANSI_ST_MSG_TYP_CWOP 0xe6
142 #define ANSI_ST_MSG_TYP_PABT 0xf6
143 static const value_string ansi_msg_type_strings[] = {
144         { ANSI_ST_MSG_TYP_UNI, "TC-UNI" },
145         { ANSI_ST_MSG_TYP_QWP, "TC-QUERY W PERM" },
146         { ANSI_ST_MSG_TYP_QWOP, "TC-QUERY WO PERM" },
147         { ANSI_ST_MSG_TYP_RSP, "TC-RESPONSE" },
148         { ANSI_ST_MSG_TYP_CWP, "TC-CONV W PERM" },
149         { ANSI_ST_MSG_TYP_CWOP, "TC-CONV WO PERM" },
150         { ANSI_ST_MSG_TYP_PABT, "TC-PABORT" },
151         { 0, NULL },
152 };
153
154 #define ST_ANSI_CMP_TAG 0xe8
155 #define ST_ANSI_TID_TAG 0xc7
156
157 /* TCAP TID tag value - Samuel */
158 #define ST_TID_SOURCE 0
159 #define ST_TID_DEST 1
160 #define ST_ITU_ORG_TID_TAG 0x48 /*0b01001000*/
161 #define ST_ITU_DST_TID_TAG 0x49 /*0b01001001*/
162 #define ST_ITU_PABT_TAG 0x4a /*0b01001010*/
163 #define ST_ITU_DLG_TAG 0x6b
164 #define ST_ITU_CMP_TAG 0x6c
165
166 static const value_string tid_strings[] = {
167         { ST_ITU_ORG_TID_TAG, "Source Transaction ID" },
168         { ST_ITU_DST_TID_TAG, "Destination Transaction ID" },
169         { 0, NULL },
170 };
171
172 /* TCAP dialog type */
173 #define TC_DLG_REQ 0x60
174 #define TC_DLG_RSP 0x61
175 #define TC_DLG_ABRT 0x64
176
177 static const value_string dlg_type_strings[] = {
178         { TC_DLG_REQ , "Dialogue Request" },
179         { TC_DLG_RSP , "Dialogue Response" },
180         { TC_DLG_ABRT, "Dialogue Abort" },
181         { 0, NULL },
182 };
183
184 /* TCAP component type */
185 #define TC_INVOKE 0xa1
186 #define TC_RRL 0xa2
187 #define TC_RE 0xa3
188 #define TC_REJECT 0xa4
189 #define TC_RRN 0xa7
190
191 static const value_string cmp_type_strings[] = {
192         { TC_INVOKE, "Invoke" },
193         { TC_RRL, "Return Result(Last)" },
194         { TC_RE, "Return Error" },
195         { TC_REJECT, "Reject" },
196         { TC_RRN, "Return Result(Not Last)" },
197         { 0, NULL },
198 };
199
200 /* ANSI TCAP component type */
201 #define ANSI_TC_INVOKE_L 0xe9
202 #define ANSI_TC_RRL 0xea
203 #define ANSI_TC_RE 0xeb
204 #define ANSI_TC_REJECT 0xec
205 #define ANSI_TC_INVOKE_N 0xed
206 #define ANSI_TC_RRN 0xee
207
208 static const value_string ansi_cmp_type_strings[] = {
209         { ANSI_TC_INVOKE_L, "Invoke(Last)" },
210         { ANSI_TC_RRL, "Return Result(Last)" },
211         { ANSI_TC_RE, "Return Error" },
212         { ANSI_TC_REJECT, "Reject" },
213         { ANSI_TC_INVOKE_N, "Invoke(Not Last)" },
214         { ANSI_TC_RRN, "Return Result(Not Last)" },
215         { 0, NULL },
216 };
217
218
219 #define TC_DS_OK 1
220 #define TC_DS_FAIL 0
221
222 /* dissect length */
223 static int
224 dissect_tcap_len(ASN1_SCK *asn1, proto_tree *tree, gboolean *def_len, guint *len)
225 {
226     guint saved_offset;
227     int ret;
228
229     saved_offset = asn1->offset;
230     *len = 0;
231     *def_len = FALSE;
232     ret = asn1_length_decode(asn1, def_len, len);
233
234     if (*def_len)
235     {
236         proto_tree_add_uint(tree, hf_tcap_length, asn1->tvb, saved_offset, asn1->offset - saved_offset, *len);
237     }
238     else
239     {
240         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
241             saved_offset, asn1->offset - saved_offset, "Length: Indefinite");
242     }
243
244     return TC_DS_OK;
245 }
246
247 static int
248 dissect_tcap_eoc(ASN1_SCK *asn1, proto_tree *tree)
249 {
250     guint saved_offset, ret;
251
252     saved_offset = asn1->offset;
253
254     if (tvb_length_remaining(asn1->tvb, saved_offset) <= 0)
255     {
256         return TC_DS_FAIL;
257     }
258
259     if (!asn1_eoc(asn1, -1))
260     {
261         return TC_DS_FAIL;
262     }
263
264     ret = asn1_eoc_decode(asn1, -1);
265
266     proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
267         saved_offset, asn1->offset - saved_offset, "End of Contents");
268
269     return TC_DS_OK;
270 }
271
272 static int
273 dissect_tcap_tag(ASN1_SCK *asn1, proto_tree *tree, guint *tag, guchar * str)
274 {
275     guint saved_offset, real_tag;
276
277     saved_offset = asn1->offset;
278     asn1_id_decode1(asn1, &real_tag);
279     if ((*tag != (guint) -1) && (real_tag != *tag))
280     {
281         asn1->offset = saved_offset;
282         return TC_DS_FAIL;
283     }
284     proto_tree_add_uint_format(tree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
285             real_tag, str);
286     return TC_DS_OK;
287 }
288
289 static int
290 dissect_tcap_octet(ASN1_SCK *asn1, proto_tree *tree, guchar * str)
291 {
292     guint saved_offset;
293     guchar my_oct;
294
295     saved_offset = asn1->offset;
296     asn1_octet_decode(asn1, &my_oct);
297     proto_tree_add_uint_format(tree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset,
298                                             my_oct, "%s %d", str, my_oct);
299     return TC_DS_OK;
300 }
301
302 static int
303 dissect_tcap_integer(ASN1_SCK *asn1, proto_tree *tree, guint len, guchar * str)
304 {
305     guint saved_offset;
306     gint32 invokeId;
307
308     saved_offset = asn1->offset;
309     asn1_int32_value_decode(asn1, len, &invokeId);
310     proto_tree_add_int_format(tree, hf_tcap_int, asn1->tvb, saved_offset, asn1->offset - saved_offset,
311                                             invokeId, "%s %d", str, invokeId);
312     return TC_DS_OK;
313 }
314
315 static gboolean
316 check_tcap_tag(ASN1_SCK *asn1, guint tag)
317 {
318     guint saved_offset, real_tag;
319
320     if (tvb_length_remaining(asn1->tvb, asn1->offset) <= 0)
321     {
322         return (FALSE);
323     }
324
325     saved_offset = asn1->offset;
326     asn1_id_decode1(asn1, &real_tag);
327     asn1->offset = saved_offset;
328     return (tag == real_tag);
329 }
330
331 /* dissect tid */
332 static int
333 dissect_tcap_tid(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti, int type)
334 {
335     guint saved_offset, org_offset = 0;
336     guint len;
337     guint tag;
338     int ret;
339     proto_item *tid_item;
340     proto_tree *subtree;
341     guchar *poctets;
342     guint32 val;
343     gboolean def_len;
344
345     org_offset = asn1->offset;
346     if ( ST_TID_SOURCE == type)
347     {
348         tid_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, asn1->offset, -1, "Source Transaction ID");
349         subtree = proto_item_add_subtree(tid_item, ett_otid);
350     }
351     else
352     {
353         tid_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, asn1->offset, -1, "Destination Transaction ID");
354         subtree = proto_item_add_subtree(tid_item, ett_dtid);
355     }
356
357     saved_offset = asn1->offset;
358     ret = asn1_id_decode1(asn1, &tag);
359     proto_tree_add_uint(subtree, hf_tcap_tid, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag);
360
361     /* error handling */
362     switch(type)
363     {
364     case ST_TID_SOURCE:
365         if (ST_ITU_ORG_TID_TAG != tag)
366         {
367             asn1->offset = saved_offset;
368             return TC_DS_FAIL;
369         }
370         break;
371     case ST_TID_DEST:
372         if (ST_ITU_DST_TID_TAG != tag)
373         {
374             asn1->offset = saved_offset;
375             return TC_DS_FAIL;
376         }
377         break;
378     default:
379         break;
380     }
381
382
383     dissect_tcap_len(asn1, subtree, &def_len, &len);
384
385     saved_offset = asn1->offset;
386     ret = asn1_string_value_decode(asn1, len, &poctets);
387     val = 0;
388     memcpy(&val, poctets, len);
389
390     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
391     g_free(poctets);
392
393     proto_item_set_len(tid_item, asn1->offset - org_offset);
394
395     if (type == ST_TID_DEST)
396     {
397         if (check_col(g_pinfo->cinfo, COL_INFO))
398             col_append_fstr(g_pinfo->cinfo, COL_INFO, "dtid(%x) ", val);
399     }
400     else
401     {
402         if (check_col(g_pinfo->cinfo, COL_INFO))
403             col_append_fstr(g_pinfo->cinfo, COL_INFO, "stid(%x) ", val);
404     }
405
406     return TC_DS_OK;
407 }
408
409 /* Samuel */
410 /* dissect operation portion */
411 static int
412 dissect_tcap_invokeId(ASN1_SCK *asn1, proto_tree *tree)
413 {
414     guint len;
415     guint tag;
416     gboolean def_len;
417
418 #define INVOKE_ID_TAG 0x2
419     if (check_tcap_tag(asn1, INVOKE_ID_TAG))
420     {
421         tag = -1;
422         dissect_tcap_tag(asn1, tree, &tag, "Invoke ID Tag");
423         dissect_tcap_len(asn1, tree, &def_len, &len);
424         dissect_tcap_integer(asn1, tree, len, "Invoke ID:");
425     }
426
427     return TC_DS_OK;
428 }
429
430 static int
431 dissect_tcap_lnkId(ASN1_SCK *asn1, proto_tree *tree)
432 {
433     guint len;
434     guint tag;
435     gboolean def_len;
436
437 #define LINK_ID_TAG 0x80
438     if (check_tcap_tag(asn1, LINK_ID_TAG))
439     {
440         tag = -1;
441         dissect_tcap_tag(asn1, tree, &tag, "Linked ID Tag");
442         dissect_tcap_len(asn1, tree, &def_len, &len);
443         dissect_tcap_integer(asn1, tree, len, "Linked ID:");
444     }
445
446     return TC_DS_OK;
447 }
448
449 static void
450 dissect_tcap_opr_code(ASN1_SCK *asn1, proto_tree *tree)
451 {
452     guint len;
453     guint tag;
454     gboolean got_it = FALSE;
455     gboolean def_len;
456
457 #define TCAP_LOC_OPR_CODE_TAG 0x02
458     if (check_tcap_tag(asn1, TCAP_LOC_OPR_CODE_TAG))
459     {
460         tag = -1;
461         dissect_tcap_tag(asn1, tree, &tag, "Local Operation Code Tag");
462         got_it = TRUE;
463     }
464 #define TCAP_GLB_OPR_CODE_TAG 0x06
465     else if (check_tcap_tag(asn1, TCAP_GLB_OPR_CODE_TAG))
466     {
467         tag = -1;
468         dissect_tcap_tag(asn1, tree, &tag, "Global Operation Code Tag");
469         got_it = TRUE;
470     }
471
472     if (got_it)
473     {
474         dissect_tcap_len(asn1, tree, &def_len, &len);
475
476         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, asn1->offset, len, "Operation Code");
477
478         asn1->offset += len;
479     }
480 }
481
482 static int
483 dissect_tcap_param(ASN1_SCK *asn1, proto_tree *tree)
484 {
485     guint off_tree[100], saved_offset, len_offset;
486     int num_seq;
487     guint tag, len;
488     gboolean def_len;
489     proto_item *item_tree[100], *item;
490     proto_tree *seq_tree[100], *use_tree, *subtree;
491
492     num_seq = 0;
493     use_tree = tree;
494
495 #define TC_INVALID_TAG 0
496     while ((tvb_length_remaining(asn1->tvb, asn1->offset) > 0) &&
497         (!check_tcap_tag(asn1, 0)))
498     {
499         saved_offset = asn1->offset;
500         asn1_id_decode1(asn1, &tag);
501         len_offset = asn1->offset;
502         asn1_length_decode(asn1, &def_len, &len);
503
504         if (tag == TC_SEQ_TAG)
505         {
506             item =
507                 proto_tree_add_none_format(use_tree, hf_tcap_none, asn1->tvb,
508                     saved_offset, -1, "Sequence");
509
510             subtree = proto_item_add_subtree(item, ett_params);
511
512             proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
513                 saved_offset, len_offset - saved_offset, tag, "Sequence Tag");
514
515             if (!def_len)
516             {
517                 proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
518                     len_offset, asn1->offset - len_offset, "Length: Indefinite");
519
520                 seq_tree[num_seq] = subtree;
521                 item_tree[num_seq] = item;
522                 off_tree[num_seq] = saved_offset;
523                 num_seq++;
524             }
525             else
526             {
527                 proto_tree_add_uint(subtree, hf_tcap_length, asn1->tvb,
528                     len_offset, asn1->offset - len_offset, len);
529
530                 proto_item_set_len(item, (asn1->offset - saved_offset) + len);
531             }
532
533             use_tree = subtree;
534             continue;
535         }
536
537         if (!def_len)
538         {
539             proto_tree_add_uint_format(use_tree, hf_tcap_tag, asn1->tvb,
540                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
541             proto_tree_add_none_format(use_tree, hf_tcap_none, asn1->tvb,
542                 len_offset, asn1->offset - len_offset, "Length: Indefinite");
543
544             seq_tree[num_seq] = use_tree;
545             item_tree[num_seq] = NULL;
546             num_seq++;
547             continue;
548         }
549         else
550         {
551             item =
552                 proto_tree_add_none_format(use_tree, hf_tcap_none, asn1->tvb,
553                     saved_offset, -1, "Parameter");
554
555             subtree = proto_item_add_subtree(item, ett_param);
556
557             proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
558                 saved_offset, len_offset - saved_offset, tag, "Parameter Tag");
559
560             proto_tree_add_uint(subtree, hf_tcap_length, asn1->tvb,
561                 len_offset, asn1->offset - len_offset, len);
562
563             proto_item_set_len(item, (asn1->offset - saved_offset) + len);
564
565             proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
566                 asn1->offset, len, "Parameter Data");
567
568             asn1->offset += len;
569         }
570
571         if (tvb_length_remaining(asn1->tvb, asn1->offset) <=0) break;
572
573         while ((num_seq > 0) &&
574             asn1_eoc(asn1, -1))
575         {
576             saved_offset = asn1->offset;
577             asn1_eoc_decode(asn1, -1);
578
579             proto_tree_add_none_format(seq_tree[num_seq-1], hf_tcap_none, asn1->tvb,
580                 saved_offset, asn1->offset - saved_offset, "End of Contents");
581
582             if (item_tree[num_seq-1] != NULL)
583             {
584                 proto_item_set_len(item_tree[num_seq-1], asn1->offset - off_tree[num_seq-1]);
585             }
586
587             num_seq--;
588         }
589     }
590
591     return TC_DS_OK;
592 }
593
594 static proto_tree *
595 dissect_tcap_component(ASN1_SCK *asn1, proto_tree *tree, guint *len_p)
596 {
597     guint saved_offset;
598     guint tag;
599     proto_item *item;
600     proto_tree *subtree;
601     gboolean def_len;
602
603
604     saved_offset = asn1->offset;
605     asn1_id_decode1(asn1, &tag);
606
607     item =
608         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
609             saved_offset, -1, "Component ID");
610
611     subtree = proto_item_add_subtree(item, ett_component);
612
613     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
614         saved_offset, asn1->offset - saved_offset, tag,
615         "Component ID Identifier");
616
617     dissect_tcap_len(asn1, subtree, &def_len, len_p);
618
619     proto_item_set_len(item, (asn1->offset - saved_offset) + *len_p);
620
621     return(subtree);
622 }
623
624 static void
625 dissect_tcap_problem(ASN1_SCK *asn1, proto_tree *tree)
626 {
627     guint orig_offset, saved_offset = 0;
628     guint len, tag_len;
629     guint tag;
630     proto_tree *subtree;
631     proto_item *item = NULL;
632     gchar *str = NULL;
633     gchar *type_str = NULL;
634     gint32 spec;
635     gboolean def_len;
636
637
638     orig_offset = asn1->offset;
639     saved_offset = asn1->offset;
640     asn1_id_decode1(asn1, &tag);
641     tag_len = asn1->offset - saved_offset;
642
643     item =
644         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
645             saved_offset, -1, "Problem Code");
646
647     subtree = proto_item_add_subtree(item, ett_problem);
648
649     dissect_tcap_len(asn1, subtree, &def_len, &len);
650     proto_item_set_len(item, (asn1->offset - saved_offset) + len);
651
652     if (len != 1)
653     {
654         proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
655             asn1->offset, len, "Unknown encoding of Problem Code");
656
657         asn1->offset += len;
658         return;
659     }
660
661     saved_offset = asn1->offset;
662     asn1_int32_value_decode(asn1, 1, &spec);
663
664     switch (tag)
665     {
666     case 0x80:
667         type_str = "General Problem";
668         switch (spec)
669         {
670         case 0: str = "Unrecognized Component"; break;
671         case 1: str = "Mistyped Component"; break;
672         case 2: str = "Badly Structured Component"; break;
673         default:
674             str = "Undefined";
675             break;
676         }
677         break;
678
679     case 0x81:
680         type_str = "Invoke";
681         switch (spec)
682         {
683         case 0: str = "Duplicate Invoke ID"; break;
684         case 1: str = "Unrecognized Operation"; break;
685         case 2: str = "Mistyped Parameter"; break;
686         case 3: str = "Resource Limitation"; break;
687         case 4: str = "Initiating Release"; break;
688         case 5: str = "Unrecognized Linked ID"; break;
689         case 6: str = "Linked Response Unexpected"; break;
690         case 7: str = "Unexpected Linked Operation"; break;
691         default:
692             str = "Undefined";
693             break;
694         }
695         break;
696
697     case 0x82:
698         type_str = "Return Result";
699         switch (spec)
700         {
701         case 0: str = "Unrecognized Invoke ID"; break;
702         case 1: str = "Return Result Unexpected"; break;
703         case 2: str = "Mistyped Parameter"; break;
704         default:
705             str = "Undefined";
706             break;
707         }
708         break;
709
710     case 0x83:
711         type_str = "Return Error";
712         switch (spec)
713         {
714         case 0: str = "Unrecognized Invoke ID"; break;
715         case 1: str = "Return Error Unexpected"; break;
716         case 2: str = "Unrecognized Error"; break;
717         case 3: str = "Unexpected Error"; break;
718         case 4: str = "Mistyped Parameter"; break;
719         default:
720             str = "Undefined";
721             break;
722         }
723         break;
724
725     default:
726         type_str = "Undefined";
727         break;
728     }
729
730     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
731         orig_offset, tag_len, tag, type_str);
732
733     proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
734         saved_offset, 1, "Problem Specifier %s", str);
735 }
736
737
738 static void
739 dissect_ansi_opr_code(ASN1_SCK *asn1, proto_tree *tree)
740 {
741     guint len;
742     guint tag;
743     gboolean got_it = FALSE;
744     gboolean def_len;
745
746 #define TCAP_NAT_OPR_CODE_TAG 0xd0
747     if (check_tcap_tag(asn1, TCAP_NAT_OPR_CODE_TAG))
748     {
749         tag = -1;
750         dissect_tcap_tag(asn1, tree, &tag, "National TCAP Operation Code Identifier");
751         got_it = TRUE;
752     }
753 #define TCAP_PRIV_OPR_CODE_TAG 0xd1
754     else if (check_tcap_tag(asn1, TCAP_PRIV_OPR_CODE_TAG))
755     {
756         tag = -1;
757         dissect_tcap_tag(asn1, tree, &tag, "Private TCAP Operation Code Identifier");
758         got_it = TRUE;
759     }
760
761     if (got_it)
762     {
763         dissect_tcap_len(asn1, tree, &def_len, &len);
764
765         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, asn1->offset, len, "Operation Code");
766
767         asn1->offset += len;
768     }
769 }
770
771 static void
772 dissect_ansi_problem(ASN1_SCK *asn1, proto_tree *tree)
773 {
774     guint saved_offset = 0;
775     guint len;
776     guint tag;
777     proto_tree *subtree;
778     proto_item *item = NULL;
779     gchar *str = NULL;
780     gchar *type_str = NULL;
781     gint32 type, spec;
782     gboolean def_len;
783
784
785 #define TCAP_PROB_CODE_TAG 0xd5
786     if (check_tcap_tag(asn1, TCAP_PROB_CODE_TAG))
787     {
788         str = "Problem Code Identifier";
789     }
790     else
791     {
792         /* XXX */
793         return;
794     }
795
796     saved_offset = asn1->offset;
797     asn1_id_decode1(asn1, &tag);
798
799     item =
800         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
801             saved_offset, -1, "Problem Code");
802
803     subtree = proto_item_add_subtree(item, ett_problem);
804
805     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
806         saved_offset, asn1->offset - saved_offset, tag, str);
807
808     dissect_tcap_len(asn1, subtree, &def_len, &len);
809     proto_item_set_len(item, (asn1->offset - saved_offset) + len);
810
811     if (len != 2)
812     {
813         proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
814             asn1->offset, len, "Unknown encoding of Problem Code");
815
816         asn1->offset += len;
817         return;
818     }
819
820     saved_offset = asn1->offset;
821     asn1_int32_value_decode(asn1, 1, &type);
822     asn1_int32_value_decode(asn1, 1, &spec);
823
824     switch (type)
825     {
826     case 0: type_str = "Not used"; break;
827
828     case 1:
829         type_str = "General";
830         switch (spec)
831         {
832         case 1: str = "Unrecognized Component Type"; break;
833         case 2: str = "Incorrect Component Portion"; break;
834         case 3: str = "Badly Structured Component Portion"; break;
835         default:
836             str = "Undefined";
837             break;
838         }
839         break;
840
841     case 2:
842         type_str = "Invoke";
843         switch (spec)
844         {
845         case 1: str = "Duplicate Invoke ID"; break;
846         case 2: str = "Unrecognized Operation Code"; break;
847         case 3: str = "Incorrect Parameter"; break;
848         case 4: str = "Unrecognized Correlation ID"; break;
849         default:
850             str = "Undefined";
851             break;
852         }
853         break;
854
855     case 3:
856         type_str = "Return Result";
857         switch (spec)
858         {
859         case 1: str = "Unrecognized Correlation ID"; break;
860         case 2: str = "Unexpected Return Result"; break;
861         case 3: str = "Incorrect Parameter"; break;
862         default:
863             str = "Undefined";
864             break;
865         }
866         break;
867
868     case 4:
869         type_str = "Return Error";
870         switch (spec)
871         {
872         case 1: str = "Unrecognized Correlation ID"; break;
873         case 2: str = "Unexpected Return Error"; break;
874         case 3: str = "Unrecognized Error"; break;
875         case 4: str = "Unexpected Error"; break;
876         case 5: str = "Incorrect Parameter"; break;
877         default:
878             str = "Undefined";
879             break;
880         }
881         break;
882
883     case 5:
884         type_str = "Transaction Portion";
885         switch (spec)
886         {
887         case 1: str = "Unrecognized Package Type"; break;
888         case 2: str = "Incorrect Transaction Portion"; break;
889         case 3: str = "Badly Structured Transaction Portion"; break;
890         case 4: str = "Unrecognized Transaction ID"; break;
891         case 5: str = "Permission to Release"; break;
892         case 6: str = "Resource Unavailable"; break;
893         default:
894             str = "Undefined";
895             break;
896         }
897         break;
898
899     default:
900         type_str = "Undefined";
901         break;
902     }
903
904     if (spec == 255) { str = "Reserved"; }
905     else if (spec == 0) { str = "Not used"; }
906
907     proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
908         saved_offset, 1, "Problem Type %s", type_str);
909
910     proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
911         saved_offset + 1, 1, "Problem Specifier %s", str);
912 }
913
914
915 static void
916 dissect_ansi_error(ASN1_SCK *asn1, proto_tree *tree)
917 {
918     guint saved_offset = 0;
919     guint len;
920     guint tag;
921     proto_tree *subtree;
922     proto_item *item = NULL;
923     gchar *str = NULL;
924     gboolean def_len;
925
926
927 #define TCAP_NAT_ERR_CODE_TAG 0xd3
928     if (check_tcap_tag(asn1, TCAP_NAT_ERR_CODE_TAG))
929     {
930         str = "National TCAP Error Code Identifier";
931     }
932 #define TCAP_PRIV_ERR_CODE_TAG 0xd4
933     else if (check_tcap_tag(asn1, TCAP_PRIV_ERR_CODE_TAG))
934     {
935         str = "Private TCAP Error Code Identifier";
936     }
937     else
938     {
939         /* XXX */
940         return;
941     }
942
943     saved_offset = asn1->offset;
944     asn1_id_decode1(asn1, &tag);
945
946     item =
947         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb,
948             saved_offset, -1, "TCAP Error Code");
949
950     subtree = proto_item_add_subtree(item, ett_error);
951
952     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
953         saved_offset, asn1->offset - saved_offset, tag, str);
954
955     dissect_tcap_len(asn1, subtree, &def_len, &len);
956     proto_item_set_len(item, (asn1->offset - saved_offset) + len);
957
958     proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
959         asn1->offset, len, "Error Code");
960
961     asn1->offset += len;
962 }
963
964
965 static void
966 dissect_ansi_param(ASN1_SCK *asn1, proto_tree *tree)
967 {
968     guint len;
969     guint tag;
970     gboolean got_it = FALSE;
971     gboolean def_len;
972
973 #define TCAP_PARAM_SET_TAG 0xf2
974     if (check_tcap_tag(asn1, TCAP_PARAM_SET_TAG))
975     {
976         tag = -1;
977         dissect_tcap_tag(asn1, tree, &tag, "Parameter Set Identifier");
978         got_it = TRUE;
979     }
980 #define TCAP_PARAM_SEQ_TAG 0x30
981     else if (check_tcap_tag(asn1, TCAP_PARAM_SEQ_TAG))
982     {
983         tag = -1;
984         dissect_tcap_tag(asn1, tree, &tag, "Parameter Sequence Identifier");
985         got_it = TRUE;
986     }
987
988     if (got_it)
989     {
990         dissect_tcap_len(asn1, tree, &def_len, &len);
991
992         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, asn1->offset, len, "Parameter Data");
993
994         asn1->offset += len;
995     }
996 }
997
998 static void
999 dissect_ansi_tcap_reject(ASN1_SCK *asn1, proto_tree *tree)
1000 {
1001     guint len;
1002     proto_tree *subtree;
1003
1004 #define COMPONENT_ID_TAG 0xcf
1005     if (check_tcap_tag(asn1, COMPONENT_ID_TAG))
1006     {
1007         subtree = dissect_tcap_component(asn1, tree, &len);
1008
1009         switch (len)
1010         {
1011         case 1:
1012             dissect_tcap_octet(asn1, subtree, "Correlation ID:");
1013             break;
1014         }
1015     }
1016
1017     dissect_ansi_problem(asn1, tree);
1018
1019     dissect_ansi_param(asn1, tree);
1020 }
1021
1022 static void
1023 dissect_ansi_tcap_re(ASN1_SCK *asn1, proto_tree *tree)
1024 {
1025     guint len;
1026     proto_tree *subtree;
1027
1028 #define COMPONENT_ID_TAG 0xcf
1029     if (check_tcap_tag(asn1, COMPONENT_ID_TAG))
1030     {
1031         subtree = dissect_tcap_component(asn1, tree, &len);
1032
1033         switch (len)
1034         {
1035         case 1:
1036             dissect_tcap_octet(asn1, tree, "Correlation ID:");
1037             break;
1038         }
1039     }
1040
1041     dissect_ansi_error(asn1, tree);
1042
1043     dissect_ansi_param(asn1, tree);
1044 }
1045
1046 static void
1047 dissect_ansi_tcap_rr(ASN1_SCK *asn1, proto_tree *tree)
1048 {
1049     guint len;
1050     proto_tree *subtree;
1051
1052 #define COMPONENT_ID_TAG 0xcf
1053     if (check_tcap_tag(asn1, COMPONENT_ID_TAG))
1054     {
1055         subtree = dissect_tcap_component(asn1, tree, &len);
1056
1057         switch (len)
1058         {
1059         case 1:
1060             dissect_tcap_octet(asn1, tree, "Correlation ID:");
1061             break;
1062         }
1063     }
1064
1065     dissect_ansi_param(asn1, tree);
1066 }
1067
1068 static void
1069 dissect_ansi_tcap_invoke(ASN1_SCK *asn1, proto_tree *tree)
1070 {
1071     guint len;
1072     proto_tree *subtree;
1073
1074 #define COMPONENT_ID_TAG 0xcf
1075     if (check_tcap_tag(asn1, COMPONENT_ID_TAG))
1076     {
1077         subtree = dissect_tcap_component(asn1, tree, &len);
1078
1079         switch (len)
1080         {
1081         case 1:
1082             dissect_tcap_octet(asn1, tree, "Invoke ID:");
1083             break;
1084
1085         case 2:
1086             dissect_tcap_octet(asn1, tree, "Invoke ID:");
1087             dissect_tcap_octet(asn1, tree, "Correlation ID:");
1088             break;
1089         }
1090     }
1091
1092     dissect_ansi_opr_code(asn1, tree);
1093
1094     dissect_ansi_param(asn1, tree);
1095 }
1096
1097 static void
1098 dissect_tcap_invoke(ASN1_SCK *asn1, proto_tree *tree)
1099 {
1100     proto_tree *subtree;
1101     guint saved_offset = 0;
1102     guint len;
1103     guint tag;
1104     int ret;
1105     proto_item *item;
1106     guint start = asn1->offset;
1107     gboolean def_len;
1108
1109     saved_offset = asn1->offset;
1110     ret = asn1_id_decode1(asn1, &tag);
1111     item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components");
1112     subtree = proto_item_add_subtree(item, ett_component);
1113     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1114                                             tag, "Invoke Type Tag");
1115
1116     dissect_tcap_len(asn1, subtree, &def_len, &len);
1117
1118     if (def_len)
1119     {
1120         proto_item_set_len(item, (asn1->offset - start) + len);
1121     }
1122
1123     dissect_tcap_invokeId(asn1, subtree);
1124
1125     dissect_tcap_lnkId(asn1, subtree);
1126
1127     dissect_tcap_opr_code(asn1, subtree);
1128
1129     dissect_tcap_param(asn1, subtree);
1130
1131     if (!def_len)
1132     {
1133         dissect_tcap_eoc(asn1, subtree);
1134     }
1135 }
1136
1137 static void
1138 dissect_tcap_rr(ASN1_SCK *asn1, proto_tree *tree, gchar *str)
1139 {
1140     guint tag, len, comp_len;
1141     guint saved_offset;
1142     proto_item *item;
1143     proto_tree *subtree;
1144     gboolean def_len;
1145     gboolean comp_def_len;
1146
1147     tag = -1;
1148     saved_offset = asn1->offset;
1149     asn1_id_decode1(asn1, &tag);
1150     item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components");
1151     subtree = proto_item_add_subtree(item, ett_component);
1152     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1153                                             tag, str);
1154
1155     dissect_tcap_len(asn1, subtree, &comp_def_len, &comp_len);
1156
1157     if (comp_def_len)
1158     {
1159         proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
1160     }
1161
1162     dissect_tcap_invokeId(asn1, subtree);
1163
1164     tag = TC_SEQ_TAG;
1165     if (check_tcap_tag(asn1, TC_SEQ_TAG))
1166     {
1167         tag = -1;
1168         dissect_tcap_tag(asn1, subtree, &tag, "Sequence Tag");
1169         dissect_tcap_len(asn1, subtree, &def_len, &len);
1170     }
1171
1172     dissect_tcap_opr_code(asn1, subtree);
1173
1174     dissect_tcap_param(asn1, subtree);
1175
1176     if (!comp_def_len)
1177     {
1178         dissect_tcap_eoc(asn1, subtree);
1179     }
1180 }
1181
1182 static int
1183 dissect_tcap_re(ASN1_SCK *asn1, proto_tree *tree)
1184 {
1185     guint tag, len, comp_len;
1186     guint saved_offset;
1187     proto_item *item;
1188     proto_tree *subtree;
1189     gboolean def_len;
1190
1191     tag = -1;
1192     saved_offset = asn1->offset;
1193     asn1_id_decode1(asn1, &tag);
1194     item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components");
1195     subtree = proto_item_add_subtree(item, ett_component);
1196     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1197                                             tag, "Return Error Type Tag");
1198
1199     dissect_tcap_len(asn1, subtree, &def_len, &comp_len);
1200
1201     if (def_len)
1202     {
1203         proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
1204     }
1205
1206     saved_offset = asn1->offset;
1207     dissect_tcap_invokeId(asn1, subtree);
1208
1209 #define TC_LOCAL_ERR_CODE_TAG 0x2
1210 #define TC_GBL_ERR_CODE_TAG 0x6
1211     if (check_tcap_tag(asn1, TC_LOCAL_ERR_CODE_TAG))
1212     {
1213         tag = -1;
1214         dissect_tcap_tag(asn1, subtree, &tag, "Local Error Code Tag");
1215     }
1216     else if (check_tcap_tag(asn1, TC_GBL_ERR_CODE_TAG))
1217     {
1218         tag = -1;
1219         dissect_tcap_tag(asn1, subtree, &tag, "Global Error Code Tag");
1220     }
1221     else
1222     {
1223         proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb, asn1->offset, comp_len,
1224             "Unknown Error Code");
1225
1226         asn1->offset += (comp_len - (asn1->offset - saved_offset));
1227         return(TC_DS_OK);
1228     }
1229
1230     dissect_tcap_len(asn1, subtree, &def_len, &len);
1231     dissect_tcap_integer(asn1, subtree, len, "Error Code:");
1232
1233     dissect_tcap_param(asn1, subtree);
1234
1235     if (!def_len)
1236     {
1237         dissect_tcap_eoc(asn1, subtree);
1238     }
1239
1240     return(TC_DS_OK);
1241 }
1242
1243 static void
1244 dissect_tcap_reject(ASN1_SCK *asn1, proto_tree *tree)
1245 {
1246     guint tag, comp_len;
1247     guint saved_offset;
1248     proto_item *item;
1249     proto_tree *subtree;
1250     gboolean def_len;
1251
1252     tag = -1;
1253
1254     saved_offset = asn1->offset;
1255     asn1_id_decode1(asn1, &tag);
1256
1257     item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components");
1258
1259     subtree = proto_item_add_subtree(item, ett_component);
1260
1261     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1262                                             tag, "Reject Type Tag");
1263
1264     dissect_tcap_len(asn1, subtree, &def_len, &comp_len);
1265
1266     if (def_len)
1267     {
1268         proto_item_set_len(item, (asn1->offset - saved_offset) + comp_len);
1269     }
1270
1271     dissect_tcap_invokeId(asn1, subtree);
1272
1273     dissect_tcap_problem(asn1, tree);
1274
1275     if (!def_len)
1276     {
1277         dissect_tcap_eoc(asn1, subtree);
1278     }
1279 }
1280
1281 static void
1282 dissect_ansi_tcap_next_tvb(ASN1_SCK *asn1, guint len, proto_tree *tree)
1283 {
1284     tvbuff_t *next_tvb;
1285     guint saved_offset;
1286     int ret;
1287     gboolean flag = TRUE;
1288     guint tag;
1289     proto_item *item, *tag_item;
1290     proto_tree *subtree, *tag_subtree;
1291     gboolean def_len;
1292
1293
1294     if (lock_info_col) col_set_fence(g_pinfo->cinfo, COL_INFO);
1295
1296     next_tvb = tvb_new_subset(asn1->tvb, asn1->offset, len, len);
1297
1298     /* process components data */
1299     if (!dissector_try_port(tcap_ansi_ssn_dissector_table, g_pinfo->match_port, next_tvb, g_pinfo, g_tcap_tree))
1300     {
1301         /* dissect cmp */
1302
1303         saved_offset = asn1->offset;
1304         ret = asn1_id_decode1(asn1, &tag);
1305
1306         /*
1307          * verify tag type is known
1308          */
1309         switch (tag)
1310         {
1311         case ANSI_TC_INVOKE_L :
1312         case ANSI_TC_RRL :
1313         case ANSI_TC_RE :
1314         case ANSI_TC_REJECT :
1315         case ANSI_TC_INVOKE_N :
1316         case ANSI_TC_RRN :
1317             flag = TRUE;
1318             break;
1319
1320         default:
1321             flag = FALSE;
1322             break;
1323         }
1324
1325         if (flag != FALSE)
1326         {
1327             item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components");
1328             subtree = proto_item_add_subtree(item, ett_component);
1329
1330             switch (tag)
1331             {
1332             case ANSI_TC_INVOKE_L :
1333                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1334                             asn1->offset - saved_offset, tag, "Invoke(Last)");
1335                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1336                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1337
1338                 dissect_ansi_tcap_invoke(asn1, tag_subtree);
1339                 break;
1340             case ANSI_TC_RRL :
1341                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1342                             asn1->offset - saved_offset, tag, "Return Result(Last)");
1343                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1344                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1345
1346                 dissect_ansi_tcap_rr(asn1, tag_subtree);
1347                 break;
1348             case ANSI_TC_RE :
1349                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1350                             asn1->offset - saved_offset, tag, "Return Error");
1351                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1352                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1353
1354                 dissect_ansi_tcap_re(asn1, tag_subtree);
1355                 break;
1356             case ANSI_TC_REJECT :
1357                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1358                             asn1->offset - saved_offset, tag, "Reject");
1359                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1360                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1361
1362                 dissect_ansi_tcap_reject(asn1, tag_subtree);
1363                 break;
1364             case ANSI_TC_INVOKE_N :
1365                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1366                             asn1->offset - saved_offset, tag, "Invoke(Not Last)");
1367                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1368                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1369
1370                 dissect_ansi_tcap_invoke(asn1, tag_subtree);
1371                 break;
1372             case ANSI_TC_RRN :
1373                 tag_item = proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset,
1374                             asn1->offset - saved_offset, tag, "Return Result(Not Last)");
1375                 dissect_tcap_len(asn1, subtree, &def_len, &len);
1376                 tag_subtree = proto_item_add_subtree(tag_item, ett_component);
1377
1378                 dissect_ansi_tcap_rr(asn1, tag_subtree);
1379                 break;
1380             }
1381
1382             proto_item_set_len(item, asn1->offset - saved_offset);
1383         }
1384     }
1385
1386     if (!flag)
1387     {
1388         /* No sub-dissection occured, treat it as raw data */
1389         call_dissector(data_handle, next_tvb, g_pinfo, g_tcap_tree);
1390     }
1391 }
1392
1393 static void
1394 dissect_tcap_next_tvb(ASN1_SCK *asn1, guint len, proto_tree *tree)
1395 {
1396     tvbuff_t *next_tvb;
1397     guint saved_offset;
1398     int ret;
1399     guint tag;
1400
1401     if (lock_info_col) col_set_fence(g_pinfo->cinfo, COL_INFO);
1402
1403     next_tvb = tvb_new_subset(asn1->tvb, asn1->offset, len, len);
1404
1405     /* process components data */
1406     if (dissector_try_port(tcap_itu_ssn_dissector_table, g_pinfo->match_port, next_tvb, g_pinfo, g_tcap_tree))
1407     {
1408         asn1->offset += len;
1409     }
1410     else
1411     {
1412         saved_offset = asn1->offset;
1413         ret = asn1_id_decode1(asn1, &tag);
1414         asn1->offset = saved_offset;
1415
1416         switch (tag)
1417         {
1418         case TC_INVOKE :
1419             dissect_tcap_invoke(asn1, tree);
1420             break;
1421         case TC_RRL :
1422             dissect_tcap_rr(asn1, tree, "Return Result(Last) Type Tag");
1423             break;
1424         case TC_RE :
1425             dissect_tcap_re(asn1, tree);
1426             break;
1427         case TC_REJECT :
1428             dissect_tcap_reject(asn1, tree);
1429             break;
1430         case TC_RRN :
1431             /* same definition as RRL */
1432             dissect_tcap_rr(asn1, tree, "Return Result(Not Last) Type Tag");
1433             break;
1434         default:
1435             /* treat it as raw data */
1436             call_dissector(data_handle, next_tvb, g_pinfo, g_tcap_tree);
1437             break;
1438         }
1439     }
1440 }
1441
1442 static int
1443 dissect_tcap_components(ASN1_SCK *asn1, proto_tree *tcap_tree)
1444 {
1445     proto_tree *subtree;
1446     guint saved_offset = 0;
1447     guint len, next_tvb_len;
1448     guint tag;
1449     int ret;
1450     proto_item *cmp_item;
1451     guint cmp_start = asn1->offset;
1452     gboolean def_len;
1453
1454     if (tvb_length_remaining(asn1->tvb, asn1->offset) <= 0)
1455     {
1456         return TC_DS_FAIL;
1457     }
1458
1459     saved_offset = asn1->offset;
1460     ret = asn1_id_decode1(asn1, &tag);
1461
1462     if (ST_ITU_CMP_TAG != tag)
1463     {
1464         asn1->offset = saved_offset;
1465         return TC_DS_FAIL;
1466     }
1467
1468     cmp_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components Portion");
1469     subtree = proto_item_add_subtree(cmp_item, ett_cmp_portion);
1470
1471     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
1472                                     "Component Portion Tag");
1473
1474     dissect_tcap_len(asn1, subtree, &def_len, &len);
1475
1476     if (def_len)
1477     {
1478         proto_item_set_len(cmp_item, (asn1->offset - cmp_start) + len);
1479     }
1480
1481     /* call next dissector */
1482
1483     if (!def_len)
1484     {
1485         /*
1486          * take remaining length minus the EOC for the indefinite
1487          * component length
1488          */
1489         next_tvb_len =
1490             tvb_length_remaining(asn1->tvb, asn1->offset) - TC_EOC_LEN;
1491     }
1492     else
1493     {
1494         next_tvb_len = len;
1495     }
1496
1497     /*
1498      * take length minus the EOC for the indefinite
1499      * transaction message length
1500      */
1501     next_tvb_len -= g_tcap_ends_def_len ? 0 : TC_EOC_LEN;
1502
1503     dissect_tcap_next_tvb(asn1, next_tvb_len, subtree);
1504
1505     if (!def_len)
1506     {
1507         dissect_tcap_eoc(asn1, subtree);
1508     }
1509
1510     proto_item_set_len(cmp_item, asn1->offset - cmp_start);
1511
1512     return TC_DS_OK;
1513 }
1514
1515 /* dissect dialog portion */
1516 static int
1517 dissect_tcap_dlg_protocol_version(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
1518 {
1519     guint saved_offset = 0;
1520     guint len;
1521     guint tag;
1522     int ret;
1523     gboolean def_len;
1524
1525 #define TC_DLG_PROTO_VER_TAG 0x80
1526     if (check_tcap_tag(asn1, TC_DLG_PROTO_VER_TAG))
1527     {
1528         saved_offset = asn1->offset;
1529         ret = asn1_id_decode1(asn1, &tag);
1530         proto_tree_add_uint_format(tcap_tree, hf_tcap_tag, asn1->tvb,
1531             saved_offset, asn1->offset - saved_offset, tag,
1532             "Protocol Version Tag: 0x%x", tag);
1533
1534         dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
1535         saved_offset = asn1->offset;
1536         ti =
1537             proto_tree_add_bytes(tcap_tree, hf_tcap_bytes, asn1->tvb, saved_offset, len,
1538                 (guchar*)(tvb_get_ptr(asn1->tvb, saved_offset, len)));
1539         asn1->offset += len;
1540     }
1541
1542     return TC_DS_OK;
1543 }
1544
1545 static int
1546 dissect_tcap_dlg_application_context_name(ASN1_SCK *asn1, proto_tree *tcap_tree)
1547 {
1548     guint saved_offset = 0;
1549     guint name_len, len, len2;
1550     guint tag;
1551     subid_t *oid;
1552     int ret;
1553     gboolean def_len;
1554
1555     saved_offset = asn1->offset;
1556     ret = asn1_id_decode1(asn1, &tag);
1557     proto_tree_add_uint_format(tcap_tree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
1558                             "Application Context Name Tag: 0x%x", tag);
1559
1560     dissect_tcap_len(asn1, tcap_tree, &def_len, &name_len);
1561
1562     saved_offset = asn1->offset;
1563     ret = asn1_oid_decode (asn1, &oid, &len, &len2);
1564     proto_tree_add_bytes(tcap_tree, hf_tcap_app_con_name, asn1->tvb, saved_offset, len2, tvb_get_ptr(asn1->tvb, saved_offset, len2));
1565     if (ret == ASN1_ERR_NOERROR) g_free(oid);
1566
1567     if (!def_len)
1568     {
1569         /* for Application Context Name Tag */
1570         dissect_tcap_eoc(asn1, tcap_tree);
1571     }
1572
1573     return TC_DS_OK;
1574 }
1575
1576 static int
1577 dissect_tcap_dlg_result(ASN1_SCK *asn1, proto_tree *tree)
1578 {
1579     guint tag, rtag_len, itag_len;
1580     guint saved_offset = 0;
1581     gint32 value;
1582     gchar *str;
1583     gboolean def_len;
1584     gboolean rtag_def_len;
1585
1586     tag = -1;
1587     dissect_tcap_tag(asn1, tree, &tag, "Result Tag");
1588
1589     dissect_tcap_len(asn1, tree, &rtag_def_len, &rtag_len);
1590
1591     tag = -1;
1592     dissect_tcap_tag(asn1, tree, &tag, "Integer Tag");
1593
1594     dissect_tcap_len(asn1, tree, &def_len, &itag_len);
1595
1596     saved_offset = asn1->offset;
1597     asn1_int32_value_decode(asn1, itag_len, &value);
1598
1599     switch (value)
1600     {
1601     case 0x00: str = "Accepted"; break;
1602     case 0x01: str = "Reject-permanent"; break;
1603     default: str = "Unknown value"; break;
1604     }
1605
1606     proto_tree_add_int_format(tree, hf_tcap_int, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1607         value, "%s %d", str, value);
1608
1609     if (!rtag_def_len)
1610     {
1611         /* for Result Tag */
1612         dissect_tcap_eoc(asn1, tree);
1613     }
1614
1615     return TC_DS_OK;
1616 }
1617
1618 static int
1619 dissect_tcap_dlg_result_src_diag(ASN1_SCK *asn1, proto_tree *tree)
1620 {
1621     guint saved_offset = 0;
1622     guint len, tag;
1623     gint32 value;
1624     gboolean user;
1625     gchar *str;
1626     gboolean def_len;
1627     gboolean serv_def_len;
1628     gboolean diag_def_len;
1629
1630     tag = -1;
1631     dissect_tcap_tag(asn1, tree, &tag, "Result Source Diagnostic Tag");
1632
1633     dissect_tcap_len(asn1, tree, &diag_def_len, &len);
1634
1635 #define TC_DIAG_SERV_USER_TAG 0xa1
1636 #define TC_DIAG_SERV_PROV_TAG 0xa2
1637     if (check_tcap_tag(asn1, TC_DIAG_SERV_USER_TAG))
1638     {
1639         tag = -1;
1640         dissect_tcap_tag(asn1, tree, &tag, "Dialogue Service User Tag");
1641         user = TRUE;
1642     }
1643     else if (check_tcap_tag(asn1, TC_DIAG_SERV_PROV_TAG))
1644     {
1645         tag = -1;
1646         dissect_tcap_tag(asn1, tree, &tag, "Dialogue Service Provider Tag");
1647         user = FALSE;
1648     }
1649     else
1650     {
1651         proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, asn1->offset, len,
1652             "Unknown Result Source Diagnostic");
1653
1654         asn1->offset += len;
1655         return(TC_DS_OK);
1656     }
1657
1658     dissect_tcap_len(asn1, tree, &serv_def_len, &len);
1659
1660     tag = -1;
1661     dissect_tcap_tag(asn1, tree, &tag, "Integer Tag");
1662
1663     dissect_tcap_len(asn1, tree, &def_len, &len);
1664
1665     saved_offset = asn1->offset;
1666     asn1_int32_value_decode(asn1, len, &value);
1667
1668     if (user)
1669     {
1670         switch (value)
1671         {
1672         case 0x00: str = "Null"; break;
1673         case 0x01: str = "No reason given"; break;
1674         case 0x02: str = "Application Context Name not supplied"; break;
1675         default: str = "Unknown value"; break;
1676         }
1677     }
1678     else
1679     {
1680         switch (value)
1681         {
1682         case 0x00: str = "Null"; break;
1683         case 0x01: str = "No reason given"; break;
1684         case 0x02: str = "No common dialogue portion"; break;
1685         default: str = "Unknown value"; break;
1686         }
1687     }
1688
1689     proto_tree_add_int_format(tree, hf_tcap_int, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1690         value, "%s %d", str, value);
1691
1692     if (!serv_def_len)
1693     {
1694         /* for Dialogue Service User/Provider Tag */
1695         dissect_tcap_eoc(asn1, tree);
1696     }
1697
1698     if (!diag_def_len)
1699     {
1700         /* for Result Source Diagnostic Tag */
1701         dissect_tcap_eoc(asn1, tree);
1702     }
1703
1704     return TC_DS_OK;
1705 }
1706
1707 static int
1708 dissect_tcap_dlg_user_info(ASN1_SCK *asn1, proto_tree *tree)
1709 {
1710         guint tag, len;
1711         guint saved_offset = 0;
1712         gboolean def_len;
1713         gboolean user_info_def_len;
1714
1715 #define TC_USR_INFO_TAG 0xbe
1716         if (check_tcap_tag(asn1, TC_USR_INFO_TAG))
1717         {
1718             tag = -1;
1719             dissect_tcap_tag(asn1, tree, &tag, "User Info Tag");
1720             dissect_tcap_len(asn1, tree, &user_info_def_len, &len);
1721
1722 #define TC_EXT_TAG 0x28
1723             if (check_tcap_tag(asn1, TC_EXT_TAG))
1724             {
1725                 saved_offset = asn1->offset;
1726                 asn1_id_decode1(asn1, &tag);
1727                 proto_tree_add_uint_format(tree, hf_tcap_length, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1728                     tag, "External Tag: 0x%x", tag);
1729
1730                 dissect_tcap_len(asn1, tree, &def_len, &len);
1731             }
1732
1733             proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, asn1->offset, len, "Parameter Data");
1734             asn1->offset += len;
1735
1736             if (!user_info_def_len)
1737             {
1738                 /* for User Information Tag */
1739                 dissect_tcap_eoc(asn1, tree);
1740             }
1741         }
1742
1743         return TC_DS_OK;
1744 }
1745
1746 static int
1747 dissect_tcap_dlg_req(ASN1_SCK *asn1, proto_tree *tcap_tree)
1748 {
1749     proto_tree *subtree;
1750     guint saved_offset = 0;
1751     guint len;
1752     guint tag;
1753     int ret;
1754     proto_item *req_item;
1755     guint req_start = asn1->offset;
1756     gboolean def_len;
1757
1758     /* dissect dialog portion */
1759     saved_offset = asn1->offset;
1760     ret = asn1_id_decode1(asn1, &tag);
1761     req_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Dialogue Request");
1762     subtree = proto_item_add_subtree(req_item, ett_dlg_req);
1763     proto_tree_add_uint(subtree, hf_tcap_dlg_type, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag);
1764
1765     dissect_tcap_len(asn1, subtree, &def_len, &len);
1766
1767     dissect_tcap_dlg_protocol_version(asn1, subtree, NULL);
1768
1769     dissect_tcap_dlg_application_context_name(asn1, subtree);
1770
1771     dissect_tcap_dlg_user_info(asn1, subtree);
1772
1773     /* decode end of sequence */
1774
1775     if (!def_len)
1776     {
1777         /* for Dialogue Request Tag */
1778         dissect_tcap_eoc(asn1, subtree);
1779     }
1780
1781     proto_item_set_len(req_item, asn1->offset - req_start);
1782
1783     return TC_DS_OK;
1784 }
1785
1786 static int
1787 dissect_tcap_dlg_rsp(ASN1_SCK *asn1, proto_tree *tcap_tree)
1788 {
1789     proto_tree *subtree;
1790     guint saved_offset = 0;
1791     guint len;
1792     guint tag;
1793     int ret;
1794     proto_item *req_item;
1795     guint req_start = asn1->offset;
1796     gboolean def_len;
1797
1798     /* dissect dialog portion */
1799     saved_offset = asn1->offset;
1800     ret = asn1_id_decode1(asn1, &tag);
1801     req_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Dialogue Response");
1802     subtree = proto_item_add_subtree(req_item, ett_dlg_rsp);
1803     proto_tree_add_uint(subtree, hf_tcap_dlg_type, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag);
1804
1805     dissect_tcap_len(asn1, subtree, &def_len, &len);
1806
1807     dissect_tcap_dlg_protocol_version(asn1, subtree, NULL);
1808
1809     dissect_tcap_dlg_application_context_name(asn1, subtree);
1810
1811     /* result */
1812     dissect_tcap_dlg_result(asn1, subtree);
1813
1814     /* result source diag */
1815     dissect_tcap_dlg_result_src_diag(asn1, subtree);
1816
1817     dissect_tcap_dlg_user_info(asn1, subtree);
1818
1819     if (!def_len)
1820     {
1821         /* for Dialogue Response Tag */
1822         dissect_tcap_eoc(asn1, subtree);
1823     }
1824
1825     proto_item_set_len(req_item, asn1->offset - req_start);
1826
1827     return TC_DS_OK;
1828 }
1829
1830 static int
1831 dissect_tcap_dlg_abrt(ASN1_SCK *asn1, proto_tree *tree)
1832 {
1833     proto_tree *subtree;
1834     guint saved_offset = 0;
1835     guint len;
1836     guint tag;
1837     int ret;
1838     proto_item *req_item;
1839     gint32 value;
1840     gchar *str;
1841     gboolean def_len, abort_def_len;
1842
1843     /* dissect dialog pabort portion */
1844     saved_offset = asn1->offset;
1845     ret = asn1_id_decode1(asn1, &tag);
1846     req_item = proto_tree_add_none_format(tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Dialogue Abort");
1847     subtree = proto_item_add_subtree(req_item, ett_dlg_abrt );
1848     proto_tree_add_uint(subtree, hf_tcap_dlg_type, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag);
1849
1850     dissect_tcap_len(asn1, subtree, &abort_def_len, &len);
1851
1852     tag = -1;
1853     dissect_tcap_tag(asn1, subtree, &tag, "Abort Source Tag");
1854     dissect_tcap_len(asn1, subtree, &def_len, &len);
1855
1856     saved_offset = asn1->offset;
1857     asn1_int32_value_decode(asn1, len, &value);
1858
1859     switch (value)
1860     {
1861     case 0x00: str = "Dialogue Service User"; break;
1862     case 0x01: str = "Dialogue Service Provider"; break;
1863     default: str = "Unknown value"; break;
1864     }
1865
1866     proto_tree_add_int_format(subtree, hf_tcap_int, asn1->tvb, saved_offset, asn1->offset - saved_offset,
1867         value, "Abort Source: %s %d", str, value);
1868
1869     dissect_tcap_dlg_user_info(asn1, subtree);
1870
1871     if (!abort_def_len)
1872     {
1873         /* for Dialogue Abort Tag */
1874         dissect_tcap_eoc(asn1, subtree);
1875     }
1876
1877     return TC_DS_OK;
1878 }
1879
1880 static int
1881 dissect_tcap_dialog_portion(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
1882 {
1883     proto_tree *subtree;
1884     guint saved_offset = 0;
1885     guint len;
1886     guint tag;
1887     int ret;
1888     proto_item *dlg_item;
1889     guint dlg_start = asn1->offset;
1890     gboolean def_len, ext_tag_def_len, portion_def_len;
1891
1892     if (tvb_length_remaining(asn1->tvb, asn1->offset) <= 0)
1893     {
1894         return TC_DS_FAIL;
1895     }
1896
1897     /* dissect dialog portion */
1898     saved_offset = asn1->offset;
1899     ret = asn1_id_decode1(asn1, &tag);
1900
1901     /* error handling */
1902     if (ST_ITU_DLG_TAG != tag)
1903     {
1904             asn1->offset = saved_offset;
1905             return TC_DS_FAIL;
1906     }
1907
1908     dlg_item =
1909         proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb,
1910             saved_offset, -1, "Dialogue Portion");
1911
1912     subtree = proto_item_add_subtree(dlg_item, ett_dlg_portion);
1913
1914     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
1915         saved_offset, asn1->offset - saved_offset, tag, "Dialogue Portion Tag");
1916
1917     dissect_tcap_len(asn1, subtree, &portion_def_len, &len);
1918
1919     if (portion_def_len)
1920     {
1921         proto_item_set_len(dlg_item, len);
1922     }
1923
1924     ext_tag_def_len = FALSE;
1925     saved_offset = asn1->offset;
1926     ret = asn1_id_decode1(asn1, &tag);
1927 #define TC_EXT_TAG 0x28
1928     if (TC_EXT_TAG != tag)
1929     {
1930         asn1->offset = saved_offset;
1931     }
1932     else
1933     {
1934         proto_tree_add_uint_format(subtree, hf_tcap_length, asn1->tvb,
1935             saved_offset, asn1->offset - saved_offset, tag,
1936             "External Tag: 0x%x", tag);
1937
1938         dissect_tcap_len(asn1, subtree, &ext_tag_def_len, &len);
1939     }
1940
1941     saved_offset = asn1->offset;
1942     ret = asn1_id_decode1(asn1, &tag);
1943 #define TC_OID_TAG 0x06
1944     if (TC_OID_TAG != tag)
1945     {
1946         asn1->offset = saved_offset;
1947     }
1948     else
1949     {
1950         proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
1951             saved_offset, asn1->offset - saved_offset, tag,
1952             "Object Identifier Tag");
1953
1954         dissect_tcap_len(asn1, subtree, &def_len, &len);
1955
1956         saved_offset = asn1->offset;
1957         ti =
1958             proto_tree_add_bytes(subtree, hf_tcap_bytes, asn1->tvb, saved_offset, len,
1959                 (guchar*)(tvb_get_ptr(asn1->tvb, saved_offset, len)));
1960
1961         asn1->offset += len;
1962     }
1963
1964     saved_offset = asn1->offset;
1965     ret = asn1_id_decode1(asn1, &tag);
1966
1967     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb,
1968         saved_offset, asn1->offset - saved_offset, tag,
1969         "Single-ASN.1-type Tag");
1970
1971     dissect_tcap_len(asn1, subtree, &def_len, &len);
1972
1973     proto_item_set_len(dlg_item, asn1->offset - dlg_start);
1974
1975     /* dialogue PDU */
1976     saved_offset = asn1->offset;
1977     ret = asn1_id_decode1(asn1, &tag);
1978     asn1->offset = saved_offset;
1979
1980     switch(tag)
1981     {
1982     case TC_DLG_REQ:
1983         dissect_tcap_dlg_req(asn1, subtree);
1984         break;
1985     case TC_DLG_RSP:
1986         dissect_tcap_dlg_rsp(asn1, subtree);
1987         break;
1988     case TC_DLG_ABRT:
1989         dissect_tcap_dlg_abrt(asn1, subtree);
1990         break;
1991     default:
1992         break;
1993     }
1994
1995     /* decode end of sequence */
1996
1997     if (!def_len)
1998     {
1999         dissect_tcap_eoc(asn1, subtree);
2000     }
2001
2002     if (!ext_tag_def_len)
2003     {
2004         dissect_tcap_eoc(asn1, subtree);
2005     }
2006
2007     if (!portion_def_len)
2008     {
2009         dissect_tcap_eoc(asn1, subtree);
2010     }
2011
2012     proto_item_set_len(dlg_item, asn1->offset - dlg_start);
2013
2014     return TC_DS_OK;
2015 }
2016
2017 /* dissect reason */
2018 static int
2019 dissect_tcap_abort_reason(ASN1_SCK *asn1, proto_tree *tcap_tree)
2020 {
2021     guint saved_offset = 0;
2022     guint tag, len;
2023     proto_tree *subtree;
2024     proto_item *item;
2025     gint32 value;
2026     gchar *str = NULL;
2027     gboolean def_len;
2028
2029 #define TC_PABRT_REASON_TAG 0x4a
2030     tag = TC_PABRT_REASON_TAG;
2031     if (check_tcap_tag(asn1, tag))
2032     {
2033         saved_offset = asn1->offset;
2034         item =
2035             proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb,
2036                 saved_offset, -1, "PAbort Cause");
2037
2038         subtree = proto_item_add_subtree(item, ett_reason);
2039
2040         tag = -1;
2041         dissect_tcap_tag(asn1, subtree, &tag, "PAbort Cause Tag");
2042         dissect_tcap_len(asn1, subtree, &def_len, &len);
2043
2044         proto_item_set_len(item, (asn1->offset - saved_offset) + len);
2045
2046         saved_offset = asn1->offset;
2047         asn1_int32_value_decode(asn1, len, &value);
2048
2049         switch (value)
2050         {
2051         case 0x00: str = "Unrecognized Message Type"; break;
2052         case 0x01: str = "Unrecognized Transaction ID"; break;
2053         case 0x02: str = "Badly Formatted Transaction Portion"; break;
2054         case 0x03: str = "Incorrect Transaction Portion"; break;
2055         case 0x04: str = "Resource Limitation"; break;
2056         default:
2057             str = "Undefined";
2058             break;
2059         }
2060
2061         proto_tree_add_none_format(subtree, hf_tcap_none, asn1->tvb,
2062             saved_offset, asn1->offset - saved_offset, "Cause Value %s (%d)",
2063             str, value);
2064     }
2065
2066     return TC_DS_OK;
2067 }
2068
2069 /* dissect each type of message */
2070
2071 static void
2072 dissect_tcap_unidirectional(ASN1_SCK *asn1, proto_tree *tcap_tree)
2073 {
2074
2075     dissect_tcap_dialog_portion(asn1, tcap_tree, NULL);
2076
2077     dissect_tcap_components(asn1, tcap_tree);
2078 }
2079
2080 static void
2081 dissect_tcap_begin(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2082 {
2083
2084     dissect_tcap_tid(asn1, tcap_tree, ti, ST_TID_SOURCE);
2085
2086     dissect_tcap_dialog_portion(asn1, tcap_tree, NULL);
2087
2088     dissect_tcap_components(asn1, tcap_tree);
2089 }
2090
2091 static void
2092 dissect_tcap_continue(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2093 {
2094
2095     dissect_tcap_tid(asn1, tcap_tree, ti, ST_TID_SOURCE);
2096
2097     dissect_tcap_tid(asn1, tcap_tree, ti, ST_TID_DEST);
2098
2099     dissect_tcap_dialog_portion(asn1, tcap_tree, NULL);
2100
2101     dissect_tcap_components(asn1, tcap_tree);
2102
2103 }
2104
2105 static void
2106 dissect_tcap_end(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2107 {
2108
2109     dissect_tcap_tid(asn1, tcap_tree, ti, ST_TID_DEST);
2110
2111     dissect_tcap_dialog_portion(asn1, tcap_tree, NULL);
2112
2113     dissect_tcap_components(asn1, tcap_tree);
2114 }
2115
2116 static void
2117 dissect_tcap_abort(ASN1_SCK *asn1, proto_tree *tree, proto_item *ti)
2118 {
2119
2120     dissect_tcap_tid(asn1, tree, ti, ST_TID_DEST);
2121
2122     dissect_tcap_abort_reason(asn1, tree);
2123
2124     dissect_tcap_dialog_portion(asn1, tree, NULL);
2125 }
2126
2127 /* Samuel */
2128 static void
2129 dissect_tcap_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tcap_tree)
2130 {
2131     ASN1_SCK asn1;
2132     guint msg_type_tag;
2133     proto_item *ti;
2134     guint offset = 0;
2135     guint saved_offset = 0;
2136     guint len;
2137     gchar *str = NULL;
2138
2139     asn1_open(&asn1, tvb, offset);
2140
2141     asn1_id_decode1(&asn1, &msg_type_tag);
2142
2143     str = match_strval(msg_type_tag, msg_type_strings);
2144
2145     if (str == NULL)
2146     {
2147         proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1.tvb, offset, -1, "Unknown message type, ignoring");
2148         return;
2149     }
2150
2151     if (check_col(pinfo->cinfo, COL_INFO))
2152     {
2153         col_set_str(pinfo->cinfo, COL_INFO, str);
2154         col_append_str(pinfo->cinfo, COL_INFO, " ");
2155     }
2156
2157     proto_tree_add_uint_hidden(tcap_tree, hf_tcap_ssn, asn1.tvb, offset,
2158                              0, pinfo->match_port); /* len -1 is unacceptable */
2159
2160     ti = proto_tree_add_uint(tcap_tree, hf_tcap_message_type, asn1.tvb, offset, asn1.offset - saved_offset,
2161             msg_type_tag);
2162
2163     dissect_tcap_len(&asn1, tcap_tree, &g_tcap_ends_def_len, &len);
2164
2165     switch(msg_type_tag)
2166     {
2167     case ST_MSG_TYP_UNI:
2168         dissect_tcap_unidirectional(&asn1, tcap_tree);
2169         break;
2170     case ST_MSG_TYP_BGN:
2171         dissect_tcap_begin(&asn1, tcap_tree, ti);
2172         break;
2173     case ST_MSG_TYP_CNT:
2174         dissect_tcap_continue(&asn1, tcap_tree, ti);
2175         break;
2176     case ST_MSG_TYP_END:
2177         dissect_tcap_end(&asn1, tcap_tree, ti);
2178         break;
2179     case ST_MSG_TYP_PABT:
2180         dissect_tcap_abort(&asn1, tcap_tree, ti);
2181         break;
2182     default:
2183         proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1.tvb, offset, -1,
2184             "Message type not handled, ignoring");
2185         break;
2186     }
2187
2188     if (!g_tcap_ends_def_len)
2189     {
2190         dissect_tcap_eoc(&asn1, tcap_tree);
2191     }
2192
2193     asn1_close(&asn1, &saved_offset);
2194 }
2195
2196 static int
2197 dissect_ansi_tcap_components(ASN1_SCK *asn1, proto_tree *tcap_tree)
2198 {
2199     proto_tree *subtree;
2200     guint saved_offset = 0;
2201     guint len;
2202     guint tag;
2203     int ret;
2204     proto_item *cmp_item;
2205     guint cmp_start = asn1->offset;
2206     gboolean def_len;
2207
2208     saved_offset = asn1->offset;
2209     ret = asn1_id_decode1(asn1, &tag);
2210
2211     if (ST_ANSI_CMP_TAG != tag)
2212     {
2213             asn1->offset = saved_offset;
2214             return TC_DS_FAIL;
2215     }
2216
2217     cmp_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Components Portion");
2218
2219     subtree = proto_item_add_subtree(cmp_item, ett_cmp_portion);
2220
2221     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2222         "Component Sequence Identifier");
2223
2224     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2225
2226     /* call next dissector */
2227
2228     dissect_ansi_tcap_next_tvb(asn1, len, subtree);
2229
2230     proto_item_set_len(cmp_item, asn1->offset - cmp_start);
2231
2232     return TC_DS_OK;
2233 }
2234
2235 static int
2236 dissect_ansi_tcap_unidirectional(ASN1_SCK *asn1, proto_tree *tcap_tree)
2237 {
2238     guint saved_offset = 0;
2239     guint len;
2240     guint tag;
2241     int ret;
2242     proto_item *trans_item;
2243     guint trans_start = asn1->offset;
2244     gboolean def_len;
2245
2246     saved_offset = asn1->offset;
2247     ret = asn1_id_decode1(asn1, &tag);
2248
2249     if (ST_ANSI_TID_TAG != tag)
2250     {
2251         asn1->offset = saved_offset;
2252         return TC_DS_FAIL;
2253     }
2254
2255     trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Transaction Portion");
2256
2257     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2258
2259     if (len != 0)
2260     {
2261         return TC_DS_FAIL;
2262     }
2263
2264     proto_item_set_len(trans_item, asn1->offset - trans_start);
2265
2266     dissect_ansi_tcap_components(asn1, tcap_tree);
2267
2268     return TC_DS_OK;
2269 }
2270
2271 static int
2272 dissect_ansi_tcap_qwp_qwop(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2273 {
2274     proto_tree *subtree;
2275     guint saved_offset = 0;
2276     guint len;
2277     guint tag;
2278     int ret;
2279     proto_item *trans_item;
2280     guint trans_start = asn1->offset;
2281     guchar *poctets;
2282     guint32 val;
2283     gboolean def_len;
2284
2285     saved_offset = asn1->offset;
2286     ret = asn1_id_decode1(asn1, &tag);
2287
2288     if (ST_ANSI_TID_TAG != tag)
2289     {
2290         asn1->offset = saved_offset;
2291         return TC_DS_FAIL;
2292     }
2293
2294     trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Transaction Portion");
2295     subtree = proto_item_add_subtree(trans_item, ett_dlg_portion);
2296
2297     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2298
2299     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2300         "Originating Transaction ID Identifier");
2301
2302     if (len != 4)
2303     {
2304         return TC_DS_FAIL;
2305     }
2306
2307     saved_offset = asn1->offset;
2308     ret = asn1_string_value_decode(asn1, len, &poctets);
2309     val = 0;
2310     memcpy(&val, poctets, len);
2311     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
2312     g_free(poctets);
2313
2314     if (check_col(g_pinfo->cinfo, COL_INFO))
2315         col_append_fstr(g_pinfo->cinfo, COL_INFO, "otid(%x) ", val);
2316
2317     proto_item_set_len(trans_item, asn1->offset - trans_start);
2318
2319     dissect_ansi_tcap_components(asn1, tcap_tree);
2320
2321     return TC_DS_OK;
2322 }
2323
2324 static int
2325 dissect_ansi_tcap_abort(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2326 {
2327     proto_tree *subtree;
2328     guint saved_offset = 0;
2329     guint len;
2330     guint tag;
2331     int ret;
2332     proto_item *trans_item;
2333     guint trans_start = asn1->offset;
2334     guchar *poctets;
2335     guint32 val;
2336     gboolean def_len;
2337
2338     saved_offset = asn1->offset;
2339     ret = asn1_id_decode1(asn1, &tag);
2340
2341     if (ST_ANSI_TID_TAG != tag)
2342     {
2343         asn1->offset = saved_offset;
2344         return TC_DS_FAIL;
2345     }
2346
2347     trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Transaction Portion");
2348     subtree = proto_item_add_subtree(trans_item, ett_dlg_portion);
2349
2350     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2351         "Responding Transaction ID Identifier");
2352
2353     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2354
2355     if (len != 4)
2356     {
2357         return TC_DS_FAIL;
2358     }
2359
2360     saved_offset = asn1->offset;
2361     ret = asn1_string_value_decode(asn1, len, &poctets);
2362     val = 0;
2363     memcpy(&val, poctets, len);
2364     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
2365     g_free(poctets);
2366
2367     if (check_col(g_pinfo->cinfo, COL_INFO))
2368         col_append_fstr(g_pinfo->cinfo, COL_INFO, "rtid(%x) ", val);
2369
2370     proto_item_set_len(trans_item, asn1->offset - trans_start);
2371
2372     saved_offset = asn1->offset;
2373     ret = asn1_id_decode1(asn1, &tag);
2374
2375 #define ANSI_TC_PABRT_CAUSE_TAG 0xd7
2376     if (tag == ANSI_TC_PABRT_CAUSE_TAG)
2377     {
2378         trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "P-Abort Portion");
2379 /*
2380         subtree = proto_item_add_subtree(trans_item, ett_dlg_abrt);
2381
2382         proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2383             "Responding Transaction ID Identifier");
2384 */
2385
2386         dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2387         dissect_tcap_integer(asn1, tcap_tree, len, "P-Abort Cause:");
2388     }
2389 #define ANSI_TC_UABRT_INFO_TAG 0xd8
2390     else if (tag == ANSI_TC_UABRT_INFO_TAG)
2391     {
2392         trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "U-Abort Portion");
2393
2394         dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2395         if (len > 0)
2396         {
2397             dissect_tcap_integer(asn1, tcap_tree, len, "User Abort Information:");
2398         }
2399     }
2400
2401     return TC_DS_OK;
2402 }
2403
2404 static int
2405 dissect_ansi_tcap_rsp(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2406 {
2407     proto_tree *subtree;
2408     guint saved_offset = 0;
2409     guint len;
2410     guint tag;
2411     int ret;
2412     proto_item *trans_item;
2413     guint trans_start = asn1->offset;
2414     guchar *poctets;
2415     guint32 val;
2416     gboolean def_len;
2417
2418     saved_offset = asn1->offset;
2419     ret = asn1_id_decode1(asn1, &tag);
2420
2421     if (ST_ANSI_TID_TAG != tag)
2422     {
2423         asn1->offset = saved_offset;
2424         return TC_DS_FAIL;
2425     }
2426
2427     trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Transaction Portion");
2428     subtree = proto_item_add_subtree(trans_item, ett_dlg_portion);
2429
2430     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2431         "Responding Transaction ID Identifier");
2432
2433     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2434
2435     if (len != 4)
2436     {
2437         return TC_DS_FAIL;
2438     }
2439
2440     saved_offset = asn1->offset;
2441     ret = asn1_string_value_decode(asn1, len, &poctets);
2442     val = 0;
2443     memcpy(&val, poctets, len);
2444     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
2445     g_free(poctets);
2446
2447     if (check_col(g_pinfo->cinfo, COL_INFO))
2448         col_append_fstr(g_pinfo->cinfo, COL_INFO, "rtid(%x) ", val);
2449
2450     proto_item_set_len(trans_item, asn1->offset - trans_start);
2451
2452     dissect_ansi_tcap_components(asn1, tcap_tree);
2453
2454     return TC_DS_OK;
2455 }
2456
2457 static int
2458 dissect_ansi_tcap_cwp_cwop(ASN1_SCK *asn1, proto_tree *tcap_tree, proto_item *ti)
2459 {
2460     proto_tree *subtree;
2461     guint saved_offset = 0;
2462     guint len;
2463     guint tag;
2464     int ret;
2465     proto_item *trans_item;
2466     guint trans_start = asn1->offset;
2467     guchar *poctets;
2468     guint32 val;
2469     gboolean def_len;
2470
2471     saved_offset = asn1->offset;
2472     ret = asn1_id_decode1(asn1, &tag);
2473
2474     if (ST_ANSI_TID_TAG != tag)
2475     {
2476         asn1->offset = saved_offset;
2477         return TC_DS_FAIL;
2478     }
2479
2480     trans_item = proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1->tvb, saved_offset, -1, "Transaction Portion");
2481     subtree = proto_item_add_subtree(trans_item, ett_dlg_portion);
2482
2483     proto_tree_add_uint_format(subtree, hf_tcap_tag, asn1->tvb, saved_offset, asn1->offset - saved_offset, tag,
2484         "Transaction ID Identifier");
2485
2486     dissect_tcap_len(asn1, tcap_tree, &def_len, &len);
2487
2488     if (len != 8)
2489     {
2490         return TC_DS_FAIL;
2491     }
2492
2493     saved_offset = asn1->offset;
2494     ret = asn1_string_value_decode(asn1, 4, &poctets);
2495     val = 0;
2496     memcpy(&val, poctets, 4);
2497     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
2498     g_free(poctets);
2499
2500     if (check_col(g_pinfo->cinfo, COL_INFO))
2501         col_append_fstr(g_pinfo->cinfo, COL_INFO, "otid(%x) ", val);
2502
2503     saved_offset = asn1->offset;
2504     ret = asn1_string_value_decode(asn1, 4, &poctets);
2505     val = 0;
2506     memcpy(&val, poctets, 4);
2507     ti = proto_tree_add_uint(subtree, hf_tcap_id, asn1->tvb, saved_offset, asn1->offset - saved_offset, val);
2508     g_free(poctets);
2509
2510     if (check_col(g_pinfo->cinfo, COL_INFO))
2511         col_append_fstr(g_pinfo->cinfo, COL_INFO, "rtid(%x) ", val);
2512
2513     proto_item_set_len(trans_item, asn1->offset - trans_start);
2514
2515     dissect_ansi_tcap_components(asn1, tcap_tree);
2516
2517     return TC_DS_OK;
2518 }
2519
2520 static void
2521 dissect_ansi_tcap_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tcap_tree)
2522 {
2523     ASN1_SCK asn1;
2524     guint msg_type_tag;
2525     proto_item *ti;
2526     guint offset = 0;
2527     guint saved_offset = 0;
2528     guint len;
2529     gchar *str = NULL;
2530     gboolean def_len;
2531
2532     asn1_open(&asn1, tvb, offset);
2533
2534     asn1_id_decode1(&asn1, &msg_type_tag);
2535
2536     str = match_strval(msg_type_tag, ansi_msg_type_strings);
2537
2538     if (str == NULL)
2539     {
2540         proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1.tvb, offset, -1, "Unknown message type, ignoring");
2541         return;
2542     }
2543
2544     if (check_col(pinfo->cinfo, COL_INFO))
2545     {
2546         col_set_str(pinfo->cinfo, COL_INFO, str);
2547         col_append_str(pinfo->cinfo, COL_INFO, " ");
2548     }
2549
2550     proto_tree_add_uint_hidden(tcap_tree, hf_tcap_ssn, asn1.tvb, offset,
2551                              0, pinfo->match_port); /* len -1 is unacceptable */
2552
2553     ti = proto_tree_add_uint(tcap_tree, hf_ansi_tcap_message_type, asn1.tvb, offset, asn1.offset - saved_offset,
2554             msg_type_tag);
2555
2556     dissect_tcap_len(&asn1, tcap_tree, &def_len, &len);
2557
2558     switch(msg_type_tag)
2559     {
2560     case ANSI_ST_MSG_TYP_UNI:
2561             dissect_ansi_tcap_unidirectional(&asn1, tcap_tree);
2562             break;
2563     case ANSI_ST_MSG_TYP_QWP:
2564             dissect_ansi_tcap_qwp_qwop(&asn1, tcap_tree, ti);
2565             break;
2566     case ANSI_ST_MSG_TYP_QWOP:
2567             dissect_ansi_tcap_qwp_qwop(&asn1, tcap_tree, ti);
2568             break;
2569     case ANSI_ST_MSG_TYP_RSP:
2570             dissect_ansi_tcap_rsp(&asn1, tcap_tree, ti);
2571             break;
2572     case ANSI_ST_MSG_TYP_CWP:
2573             dissect_ansi_tcap_cwp_cwop(&asn1, tcap_tree, ti);
2574             break;
2575     case ANSI_ST_MSG_TYP_CWOP:
2576             dissect_ansi_tcap_cwp_cwop(&asn1, tcap_tree, ti);
2577             break;
2578     case ANSI_ST_MSG_TYP_PABT:
2579             dissect_ansi_tcap_abort(&asn1, tcap_tree, ti);
2580             break;
2581     default:
2582             proto_tree_add_none_format(tcap_tree, hf_tcap_none, asn1.tvb, offset, -1,
2583                 "Message type not handled, ignoring");
2584             break;
2585     }
2586
2587     asn1_close(&asn1, &saved_offset);
2588 }
2589
2590 /* Code to actually dissect the packets */
2591 static void
2592 dissect_tcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2593 {
2594     proto_item *ti;
2595     proto_tree *tcap_tree;
2596
2597     g_pinfo = pinfo;
2598
2599     if (check_col(pinfo->cinfo, COL_PROTOCOL))
2600         col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCAP");
2601
2602     /* In the interest of speed, if "tree" is NULL, don't do any
2603      * work not necessary to generate protocol tree items.
2604      */
2605     if (tree)
2606     {
2607         ti = proto_tree_add_item(tree, proto_tcap, tvb, 0, -1, FALSE);
2608         tcap_tree = proto_item_add_subtree(ti, ett_tcap);
2609         g_tcap_tree = tree;
2610
2611         if (tcap_standard == ITU_TCAP_STANDARD)
2612         {
2613             dissect_tcap_message(tvb, pinfo, tcap_tree);
2614         }
2615         else
2616         {
2617             dissect_ansi_tcap_message(tvb, pinfo, tcap_tree);
2618         }
2619     }
2620 }
2621
2622
2623 /* Register the protocol with Ethereal */
2624
2625 /* this format is require because a script is used to build the C function
2626    that calls all the protocol registration.
2627 */
2628 void
2629 proto_register_tcap(void)
2630 {
2631
2632 /* Setup list of header fields  See Section 1.6.1 for details*/
2633         static hf_register_info hf[] = {
2634                 /*{ &hf_tcap_FIELDABBREV,
2635                         { "FIELDNAME",           "PROTOABBREV.FIELDABBREV",
2636                         FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
2637                         "FIELDDESCR" }
2638                 },*/
2639                 { &hf_tcap_tag,
2640                         { "Tag",           "tcap.msgtype",
2641                         FT_UINT8, BASE_HEX, NULL, 0,
2642                         "", HFILL }
2643                 },
2644                 { &hf_tcap_length,
2645                         { "Length", "tcap.len",
2646                         FT_UINT8, BASE_HEX, NULL, 0,
2647                         "", HFILL }
2648                 },
2649                 { &hf_tcap_id,
2650                         { "Value", "tcap.id",
2651                         FT_UINT8, BASE_HEX, NULL, 0,
2652                         "", HFILL }
2653                 },
2654                 { &hf_tcap_message_type,
2655                         { "Message Type", "tcap.msgtype",
2656                         FT_UINT8, BASE_HEX, VALS(msg_type_strings), 0,
2657                         "", HFILL }
2658                 },
2659                 { &hf_ansi_tcap_message_type,
2660                         { "Message Type", "tcap.msgtype",
2661                         FT_UINT8, BASE_HEX, VALS(ansi_msg_type_strings), 0,
2662                         "", HFILL }
2663                 },
2664                 { &hf_tcap_none,
2665                         { "Sub tree", "tcap.none",
2666                         FT_NONE, 0, 0, 0,
2667                         "", HFILL }
2668                 },
2669                 { &hf_tcap_tid,
2670                         { "Transaction Id", "tcap.tid",
2671                         FT_UINT32, BASE_DEC, VALS(tid_strings), 0,
2672                         "", HFILL }
2673                 },
2674                 { &hf_tcap_ssn,
2675                         { "Called or Calling SubSystem Number", "tcap.ssn",
2676                         FT_UINT8, BASE_DEC, 0x0, 0x0,
2677                         "", HFILL }
2678                 },
2679                 { &hf_tcap_cmp_type,
2680                         { "Component Type", "tcap.cmptype",
2681                         FT_UINT8, BASE_HEX, VALS(cmp_type_strings), 0,
2682                         "", HFILL }
2683                 },
2684                 { &hf_ansi_tcap_cmp_type,
2685                         { "Component Type", "tcap.cmptype",
2686                         FT_UINT8, BASE_HEX, VALS(ansi_cmp_type_strings), 0,
2687                         "", HFILL }
2688                 },
2689                 { &hf_tcap_dlg_type,
2690                         { "Dialogue Type", "tcap.dlgtype",
2691                         FT_UINT8, BASE_HEX, VALS(dlg_type_strings), 0,
2692                         "", HFILL }
2693                 },
2694                 { &hf_tcap_app_con_name,
2695                         { "Application Context Name", "tcap.dlg.appconname",
2696                         FT_BYTES, BASE_HEX, 0, 0,
2697                         "", HFILL }
2698                 },
2699                 { &hf_tcap_bytes,
2700                         { "Binary Data", "tcap.data",
2701                         FT_BYTES, BASE_HEX, 0, 0,
2702                         "", HFILL }
2703                 },
2704                 { &hf_tcap_int,
2705                         { "Integer Data", "tcap.data",
2706                         FT_INT32, BASE_DEC, 0, 0,
2707                         "", HFILL }
2708                 },
2709         };
2710
2711 /* Setup protocol subtree array */
2712         static gint *ett[] = {
2713                 &ett_tcap,
2714                 &ett_otid,
2715                 &ett_dtid,
2716                 &ett_dlg_portion,
2717                 &ett_cmp_portion,
2718                 &ett_reason,
2719                 &ett_dlg_req,
2720                 &ett_dlg_rsp,
2721                 &ett_dlg_abrt,
2722                 &ett_component,
2723                 &ett_error,
2724                 &ett_problem,
2725                 &ett_params,
2726                 &ett_param,
2727         };
2728
2729         static enum_val_t tcap_options[] = {
2730             { "ITU",  ITU_TCAP_STANDARD },
2731             { "ANSI", ANSI_TCAP_STANDARD },
2732             { NULL, 0 }
2733         };
2734
2735         module_t *tcap_module;
2736
2737 /* Register the protocol name and description */
2738         proto_tcap = proto_register_protocol("Transaction Capabilities Application Part",
2739             "TCAP", "tcap");
2740
2741 /* Required function calls to register the header fields and subtrees used */
2742         proto_register_field_array(proto_tcap, hf, array_length(hf));
2743         proto_register_subtree_array(ett, array_length(ett));
2744
2745         tcap_module = prefs_register_protocol(proto_tcap, proto_reg_handoff_tcap);
2746
2747         prefs_register_enum_preference(tcap_module, "standard", "TCAP standard",
2748                                  "The SS7 standard used in TCAP packets",
2749                                  (gint *)&tcap_standard, tcap_options, FALSE);
2750
2751         prefs_register_bool_preference(tcap_module, "lock_info_col", "Lock Info column",
2752             "Always show TCAP in Info column",
2753             &lock_info_col);
2754
2755         /* we will fake a ssn subfield which has the same value obtained from sccp */
2756         tcap_itu_ssn_dissector_table = register_dissector_table("tcap.itu_ssn", "ITU TCAP SSN", FT_UINT8, BASE_DEC);
2757         tcap_ansi_ssn_dissector_table = register_dissector_table("tcap.ansi_ssn", "ANSI TCAP SSN", FT_UINT8, BASE_DEC);
2758 }
2759
2760
2761 /* If this dissector uses sub-dissector registration add a registration routine.
2762    This format is required because a script is used to find these routines and
2763    create the code that calls these routines.
2764 */
2765 void
2766 proto_reg_handoff_tcap(void)
2767 {
2768     static gboolean tcap_prefs_initialized = FALSE;
2769     dissector_handle_t tcap_handle;
2770
2771     if (!tcap_prefs_initialized)
2772     {
2773         tcap_handle = create_dissector_handle(dissect_tcap,
2774             proto_tcap);
2775
2776         dissector_add("sccp.ssn", 5, tcap_handle); /* MAP*/
2777         dissector_add("sccp.ssn", 6, tcap_handle); /* HLR*/
2778         dissector_add("sccp.ssn", 7, tcap_handle); /* VLR */
2779         dissector_add("sccp.ssn", 8, tcap_handle); /* MSC */
2780         dissector_add("sccp.ssn", 9, tcap_handle); /* EIR */
2781         dissector_add("sccp.ssn", 10, tcap_handle); /* EIR */
2782         dissector_add("sccp.ssn", 11, tcap_handle); /* SMS/MC */
2783         dissector_add("sccp.ssn", 12, tcap_handle); /* IS41 OTAF */
2784
2785         tcap_prefs_initialized = TRUE;
2786     }
2787
2788     data_handle = find_dissector("data");
2789 }