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