make sure that colifo gets set and put some other useful info there
[obnox/wireshark/wip.git] / epan / dissectors / packet-alcap.c
1 /* packet-alcap.c
2  * Routines for ALCAP (Q.2630.1) dissection
3  * AAL type 2 signalling protocol - Capability set 1
4  * 12/1999
5  *
6  * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
7  * In association with Telos Technology Inc.
8  *
9  * $Id$
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <gmodule.h>
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45
46 #include <string.h>
47
48 #include "epan/packet.h"
49
50
51 #define ALCAP_MSG_HEADER_LEN    6
52 #define ALCAP_PARM_HEADER_LEN   3
53
54 #define ALCAP_SI                12
55
56 #define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
57     if ((edc_len) > (edc_max_len)) \
58     { \
59         proto_tree_add_none_format(tree, hf_alcap_none, tvb, \
60             curr_offset, (edc_len) - (edc_max_len), "Extraneous Data"); \
61     }
62
63 #define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
64     if ((sdc_len) < (sdc_min_len)) \
65     { \
66         proto_tree_add_none_format(tree, hf_alcap_none, tvb, \
67             curr_offset, (sdc_len), "Short Data (?)"); \
68         return; \
69     }
70
71 #define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
72     if ((edc_len) != (edc_eq_len)) \
73     { \
74         proto_tree_add_none_format(tree, hf_alcap_none, tvb, \
75             curr_offset, (edc_len), "Unexpected Data Length"); \
76         return; \
77     }
78
79 static const value_string msg_parm_strings[] = {
80     { 1,        "Cause (CAU)" },
81     { 2,        "Connection element identifier (CEID)" },
82     { 3,        "Destination E.164 service endpoint address (ESEA)" },
83     { 4,        "Destination NSAP service endpoint address (NSEA)" },
84     { 5,        "Link characteristics (ALC)" },
85     { 6,        "Originating signalling association identifier (OSAID)" },
86     { 7,        "Served user generated reference (SUGR)" },
87     { 8,        "Served user transport (SUT)" },
88     { 9,        "Service specific information (audio) (SSIA)" },
89     { 10,       "Service specific information (multirate) (SSIM)" },
90     { 11,       "Service specific information (SAR-assured) (SSISA)" },
91     { 12,       "Service specific information (SAR-unassured) (SSISU)" },
92     { 13,       "Test connection identifier (TCI)" },
93     { 0, NULL },
94 };
95 #define NUM_PARMS (sizeof(msg_parm_strings)/sizeof(value_string))
96
97 static char *alcap_proto_name = "AAL type 2 signalling protocol - Capability set 1 (Q.2630.1)";
98 static char *alcap_proto_name_short = "ALCAP";
99
100 /* Initialize the subtree pointers */
101 static gint ett_alcap = -1;
102 static gint ett_parm = -1;
103
104 /* Initialize the protocol and registered fields */
105 static int proto_alcap = -1;
106 static int hf_alcap_msg_type = -1;
107 static int hf_alcap_length = -1;
108 static int hf_alcap_parm_id = -1;
109 static int hf_alcap_none = -1;
110 static int hf_alcap_dsaid = -1;
111 static int hf_alcap_osaid = -1;
112 static int hf_alcap_aal2_path_id = -1;
113 static int hf_alcap_channel_id = -1;
114 static int hf_alcap_organizational_unique_id = -1;
115 static int hf_alcap_served_user_gen_ref = -1;
116 static int hf_alcap_nsap_address = -1;
117
118 static char bigbuf[1024];
119 static char bigbuf2[1024];
120 static dissector_handle_t data_handle;
121 static packet_info *g_pinfo;
122 static proto_tree *g_tree;
123
124 #define FIELD_COMPATIBILITY             0
125 #define FIELD_SIGNALLING_ASSOC_ID       1
126 #define FIELD_AAL2_PATH_ID              2
127 #define FIELD_CHANNEL_ID                3
128 #define FIELD_ORGANIZATIONAL_UNIQUE_ID  4
129 #define FIELD_AUDIO_SERVICE             5
130 #define FIELD_MULTIRATE_SERVICE         6
131 #define FIELD_SEG_REASSEMBLY_ASS        7
132 #define FIELD_SEG_REASSEMBLY_UNASS      8
133 #define FIELD_SERVED_USER_GEN_REF       9
134 #define FIELD_MAX_CPS_SDU_BIT_RATE      10
135 #define FIELD_AVG_CPS_SDU_BIT_RATE      11
136 #define FIELD_MAX_CPS_SDU_SIZE          12
137 #define FIELD_AVG_CPS_SDU_SIZE          13
138 #define FIELD_NATURE_OF_ADDRESS         14
139 #define FIELD_E164_ADDRESS              15
140 #define FIELD_NSAP_ADDRESS              16
141 #define FIELD_CAUSE_VALUE               17
142 #define FIELD_DIAGNOSTICS               18
143 #define FIELD_SERVED_USER_TRANSPORT     19
144 static const char * field_strings[] = {
145     "Compatibility",
146     "Signalling association identifier",
147     "AAL type 2 path identifier",
148     "Channel identifier (CID)",
149     "Organizational unique identifier (OUI)",
150     "Audio service",
151     "Multirate service",
152     "Segmentation and reassembly (assured data transfer)",
153     "Segmentation and reassembly (unassured data transfer)",
154     "Served user generated reference",
155     "Maximum CPS-SDU bit rate",
156     "Average CPS-SDU bit rate",
157     "Maximum CPS-SDU size",
158     "Average CPS-SDU size",
159     "Nature of address",
160     "E.164 address",
161     "NSAP address",
162     "Cause value",
163     "Diagnostics",
164     "Served user transport"
165 };
166 #define NUM_FIELDS (sizeof(field_strings)/sizeof(char *))
167 static gint ett_fields[NUM_FIELDS];
168
169 static const value_string msg_type_strings[] = {
170     { 1,        "Block confirm (BLC)" },
171     { 2,        "Block request (BLO)" },
172     { 3,        "Confusion (CFN)" },
173     { 4,        "Establish confirm (ECF)" },
174     { 5,        "Establish request (ERQ)" },
175     { 6,        "Release confirm (RLC)" },
176     { 7,        "Release request (REL)" },
177     { 8,        "Reset confirm (RSC)" },
178     { 9,        "Reset request (RES)" },
179     { 10,       "Unblock confirm (UBC)" },
180     { 11,       "Unblock request (UBL)" },
181     { 0, NULL },
182 };
183
184 /* FUNCTIONS */
185
186 static gchar *
187 my_match_strval(guint32 val, const value_string *vs, gint *idx)
188 {
189     gint i = 0;
190
191     while (vs[i].strptr) {
192         if (vs[i].value == val)
193         {
194             *idx = i;
195             return(vs[i].strptr);
196         }
197
198         i++;
199     }
200
201     *idx = -1;
202     return(NULL);
203 }
204
205 /*
206  * Ref. ITU-T Q.2630.1 (12/1999)
207  * Section 7.4.1
208  */
209 static void
210 dis_field_compatibility(tvbuff_t *tvb, proto_tree *tree, guint32 *offset, gboolean message)
211 {
212     guint32     curr_offset;
213     guint8      compat;
214     proto_item  *item;
215     proto_tree  *subtree;
216     gchar       *str = NULL;
217
218     curr_offset = *offset;
219
220     item =
221         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
222             curr_offset, 1, "%s %s",
223             message ? "Message" : "Parameter",
224             field_strings[FIELD_COMPATIBILITY]);
225
226     subtree = proto_item_add_subtree(item, ett_fields[FIELD_COMPATIBILITY]);
227
228     compat = tvb_get_guint8(tvb, curr_offset);
229
230     other_decode_bitfield_value(bigbuf, compat, 0x80, 8);
231     proto_tree_add_text(subtree, tvb,
232         curr_offset, 1,
233         "%s :  Reserved",
234         bigbuf);
235
236     other_decode_bitfield_value(bigbuf, compat, 0x40, 8);
237     proto_tree_add_text(subtree, tvb,
238         curr_offset, 1,
239         "%s :  Pass-on not possible - %s",
240         bigbuf,
241         (compat & 0x40) ? "Send notification" : "Do not send notification");
242
243     switch ((compat & 0x30) >> 4)
244     {
245     case 0x00:
246         str = "Pass on message or parameter (Release connection)";
247         break;
248
249     case 0x01:
250         if (message)
251         {
252             str = "Discard parameter (Discard message)";
253         }
254         else
255         {
256             str = "Discard parameter";
257         }
258         break;
259
260     case 0x02:
261         str = "Discard message";
262         break;
263
264     case 0x03:
265         str = "Release connection";
266         break;
267     }
268
269     other_decode_bitfield_value(bigbuf, compat, 0x30, 8);
270     proto_tree_add_text(subtree, tvb,
271         curr_offset, 1,
272         "%s :  Pass-on not possible, instruction - %s",
273         bigbuf,
274         str);
275
276     other_decode_bitfield_value(bigbuf, compat, 0x08, 8);
277     proto_tree_add_text(subtree, tvb,
278         curr_offset, 1,
279         "%s :  Reserved",
280         bigbuf);
281
282     other_decode_bitfield_value(bigbuf, compat, 0x04, 8);
283     proto_tree_add_text(subtree, tvb,
284         curr_offset, 1,
285         "%s :  General action - %s",
286         bigbuf,
287         (compat & 0x04) ? "Send notification" : "Do not send notification");
288
289     switch (compat & 0x03)
290     {
291     case 0x00:
292         str = "Pass on message or parameter";
293         break;
294
295     case 0x01:
296         if (message)
297         {
298             str = "Discard parameter (Discard message)";
299         }
300         else
301         {
302             str = "Discard parameter";
303         }
304         break;
305
306     case 0x02:
307         str = "Discard message";
308         break;
309
310     case 0x03:
311         str = "Release connection";
312         break;
313     }
314
315     other_decode_bitfield_value(bigbuf, compat, 0x03, 8);
316     proto_tree_add_text(subtree, tvb,
317         curr_offset, 1,
318         "%s :  General action, instruction - %s",
319         bigbuf,
320         str);
321
322     *offset += 1;
323 }
324
325 /*
326  * Ref. ITU-T Q.2630.1 (12/1999)
327  * Section 7.4.2
328  */
329 static void
330 dis_field_signalling_assoc_id(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset, gboolean destination)
331 {
332     guint32     curr_offset;
333     guint32     value;
334
335     curr_offset = *offset;
336
337 #define FIELD_SIGNALLING_ASSOC_ID_LEN   4
338
339     SHORT_DATA_CHECK(*len, FIELD_SIGNALLING_ASSOC_ID_LEN);
340
341     value = tvb_get_ntohl(tvb, curr_offset);
342
343         if (value && check_col(g_pinfo->cinfo, COL_INFO))
344                 col_append_fstr(g_pinfo->cinfo, COL_INFO, " SA: %u", value);
345
346         if (destination)
347     {
348         proto_tree_add_uint_format(tree, hf_alcap_dsaid, tvb,
349             curr_offset, FIELD_SIGNALLING_ASSOC_ID_LEN, value,
350             "Destination signalling association identifier: %u%s",
351             value,
352             value ? "" : " (unknown)");
353     }
354     else
355     {
356         proto_tree_add_uint(tree, hf_alcap_osaid, tvb,
357             curr_offset, FIELD_SIGNALLING_ASSOC_ID_LEN, value);
358     }
359
360     curr_offset += FIELD_SIGNALLING_ASSOC_ID_LEN;
361
362     *len -= (curr_offset - *offset);
363     *offset = curr_offset;
364 }
365
366 /*
367  * Ref. ITU-T Q.2630.1 (12/1999)
368  * Section 7.4.3
369  */
370 static void
371 dis_field_aal2_path_id(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
372 {
373     guint32     curr_offset;
374     guint32     value;
375
376     curr_offset = *offset;
377
378 #define FIELD_AAL2_PATH_ID_LEN  4
379
380     SHORT_DATA_CHECK(*len, FIELD_AAL2_PATH_ID_LEN);
381
382     value = tvb_get_ntohl(tvb, curr_offset);
383
384         if (value && check_col(g_pinfo->cinfo, COL_INFO))
385                 col_append_fstr(g_pinfo->cinfo, COL_INFO, " PathId: %u", value);
386
387     proto_tree_add_uint_format(tree, hf_alcap_aal2_path_id, tvb,
388         curr_offset, FIELD_AAL2_PATH_ID_LEN, value,
389         "AAL2 path identifier: %d%s",
390         value,
391         value ? "" : " (Null)");
392
393     curr_offset += FIELD_AAL2_PATH_ID_LEN;
394
395     *len -= (curr_offset - *offset);
396     *offset = curr_offset;
397 }
398
399 /*
400  * Ref. ITU-T Q.2630.1 (12/1999)
401  * Section 7.4.4
402  */
403 static void
404 dis_field_channel_id(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
405 {
406     guint32     curr_offset;
407     guint8      oct;
408
409     curr_offset = *offset;
410
411     SHORT_DATA_CHECK(*len, 1);
412
413     oct = tvb_get_guint8(tvb, curr_offset);
414
415         if (oct && check_col(g_pinfo->cinfo, COL_INFO))
416                 col_append_fstr(g_pinfo->cinfo, COL_INFO, " CID: %u", oct);
417
418     proto_tree_add_uint_format(tree, hf_alcap_channel_id, tvb,
419         curr_offset, 1, oct,
420         "Channel identifier (CID): %d%s",
421         oct,
422         oct ? "" : " (Null)");
423
424     curr_offset++;
425
426     *len -= (curr_offset - *offset);
427     *offset = curr_offset;
428 }
429
430 /*
431  * Ref. ITU-T Q.2630.1 (12/1999)
432  * Section 7.4.5
433  */
434 static void
435 dis_field_organizational_unique_id(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
436 {
437     guint32     curr_offset;
438     guint32     octs;
439
440     curr_offset = *offset;
441
442 #define FIELD_ORGANIZATIONAL_UNIQUE_ID_LEN      3
443
444     SHORT_DATA_CHECK(*len, FIELD_ORGANIZATIONAL_UNIQUE_ID_LEN);
445
446     octs = tvb_get_ntoh24(tvb, curr_offset);
447
448     proto_tree_add_uint(tree, hf_alcap_organizational_unique_id, tvb,
449         curr_offset, FIELD_ORGANIZATIONAL_UNIQUE_ID_LEN, octs);
450
451     curr_offset += FIELD_ORGANIZATIONAL_UNIQUE_ID_LEN;
452
453     *len -= (curr_offset - *offset);
454     *offset = curr_offset;
455 }
456
457 /*
458  * Ref. ITU-T Q.2630.1 (12/1999)
459  * Section 7.4.6
460  */
461 static void
462 dis_field_audio_service(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
463 {
464     guint32     curr_offset;
465     guint32     value;
466     guint8      oct;
467     proto_item  *item;
468     proto_tree  *subtree;
469     gchar       *str = NULL;
470
471     curr_offset = *offset;
472
473 #define FIELD_AUDIO_SERVICE_LEN 5
474
475     SHORT_DATA_CHECK(*len, FIELD_AUDIO_SERVICE_LEN);
476
477     item =
478         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
479             curr_offset, FIELD_AUDIO_SERVICE_LEN, field_strings[FIELD_AUDIO_SERVICE]);
480
481     subtree = proto_item_add_subtree(item, ett_fields[FIELD_AUDIO_SERVICE]);
482
483     oct = tvb_get_guint8(tvb, curr_offset);
484
485     switch ((oct & 0xc0) >> 6)
486     {
487     case 0x00: str = "Designates a profile specified by ITU-T Rec. I.366.2; ignore organizational unique identifier"; break;
488     case 0x01: str = "Designates a profile specified by organizational unique identifier"; break;
489     case 0x02: str = "Designates a custom profile; ignore organizational unique identifier"; break;
490     case 0x03: str = "Reserved"; break;
491     }
492
493     other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
494     proto_tree_add_text(subtree, tvb,
495         curr_offset, 1,
496         "%s :  Profile type, %s",
497         bigbuf, str);
498
499     other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
500     proto_tree_add_text(subtree, tvb,
501         curr_offset, 1,
502         "%s :  Reserved",
503         bigbuf);
504
505     curr_offset++;
506
507     oct = tvb_get_guint8(tvb, curr_offset);
508
509     proto_tree_add_text(subtree, tvb,
510         curr_offset, 1,
511         "Profile identifier (%d)",
512         oct);
513
514     curr_offset++;
515
516     oct = tvb_get_guint8(tvb, curr_offset);
517
518     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
519     proto_tree_add_text(subtree, tvb,
520         curr_offset, 1,
521         "%s :  FRM, transport of frame mode data %s",
522         bigbuf,
523         (oct & 0x80) ? "enabled" : "disabled");
524
525     other_decode_bitfield_value(bigbuf, oct, 0x40, 8);
526     proto_tree_add_text(subtree, tvb,
527         curr_offset, 1,
528         "%s :  CMD, transport of circuit mode data (64 kbit/s) %s",
529         bigbuf,
530         (oct & 0x40) ? "enabled" : "disabled");
531
532     other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
533     proto_tree_add_text(subtree, tvb,
534         curr_offset, 1,
535         "%s :  MF-R2, transport of multi-frequency R2 dialled digits %s",
536         bigbuf,
537         (oct & 0x20) ? "enabled" : "disabled");
538
539     other_decode_bitfield_value(bigbuf, oct, 0x10, 8);
540     proto_tree_add_text(subtree, tvb,
541         curr_offset, 1,
542         "%s :  MF-R1, transport of multi-frequency R1 dialled digits %s",
543         bigbuf,
544         (oct & 0x10) ? "enabled" : "disabled");
545
546     other_decode_bitfield_value(bigbuf, oct, 0x08, 8);
547     proto_tree_add_text(subtree, tvb,
548         curr_offset, 1,
549         "%s :  DTMF, transport of dual tone multi-frequency dialled digits %s",
550         bigbuf,
551         (oct & 0x08) ? "enabled" : "disabled");
552
553     other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
554     proto_tree_add_text(subtree, tvb,
555         curr_offset, 1,
556         "%s :  CAS, transport of channel associated signalling %s",
557         bigbuf,
558         (oct & 0x04) ? "enabled" : "disabled");
559
560     other_decode_bitfield_value(bigbuf, oct, 0x02, 8);
561     proto_tree_add_text(subtree, tvb,
562         curr_offset, 1,
563         "%s :  FAX, transport of demodulated facsimile data %s",
564         bigbuf,
565         (oct & 0x02) ? "enabled" : "disabled");
566
567     other_decode_bitfield_value(bigbuf, oct, 0x01, 8);
568     proto_tree_add_text(subtree, tvb,
569         curr_offset, 1,
570         "%s :  A/mu-law, interpretation of generic PCM coding: %s-law",
571         bigbuf,
572         (oct & 0x01) ? "mu" : "A");
573
574     curr_offset++;
575
576     value = tvb_get_ntohs(tvb, curr_offset);
577
578     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
579         curr_offset, 2,
580         "Maximum length of frame mode data (%d)",
581         value);
582
583     curr_offset += 2;
584
585     *len -= (curr_offset - *offset);
586     *offset = curr_offset;
587 }
588
589 /*
590  * Ref. ITU-T Q.2630.1 (12/1999)
591  * Section 7.4.7
592  */
593 static void
594 dis_field_multirate_service(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
595 {
596     guint32     curr_offset;
597     guint32     value;
598     guint8      oct;
599     proto_item  *item;
600     proto_tree  *subtree;
601
602     curr_offset = *offset;
603
604 #define FIELD_MULTIRATE_SERVICE_LEN     3
605
606     SHORT_DATA_CHECK(*len, FIELD_MULTIRATE_SERVICE_LEN);
607
608     item =
609         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
610             curr_offset, FIELD_MULTIRATE_SERVICE_LEN, field_strings[FIELD_MULTIRATE_SERVICE]);
611
612     subtree = proto_item_add_subtree(item, ett_fields[FIELD_MULTIRATE_SERVICE]);
613
614     oct = tvb_get_guint8(tvb, curr_offset);
615
616     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
617     proto_tree_add_text(subtree, tvb,
618         curr_offset, 1,
619         "%s :  FRM, transport of frame mode data %s",
620         bigbuf,
621         (oct & 0x80) ? "enabled" : "disabled");
622
623     other_decode_bitfield_value(bigbuf, oct, 0x60, 8);
624     proto_tree_add_text(subtree, tvb,
625         curr_offset, 1,
626         "%s :  Reserved",
627         bigbuf);
628
629     other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
630     proto_tree_add_text(subtree, tvb,
631         curr_offset, 1,
632         "%s :  Multiplier (%d) for n x 64 kbit/s",
633         bigbuf,
634         oct & 0x1f);
635
636     curr_offset++;
637
638     value = tvb_get_ntohs(tvb, curr_offset);
639
640     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
641         curr_offset, 2,
642         "Maximum length of frame mode data (%d)",
643         value);
644
645     curr_offset += 2;
646
647     *len -= (curr_offset - *offset);
648     *offset = curr_offset;
649 }
650
651 /*
652  * Ref. ITU-T Q.2630.1 (12/1999)
653  * Section 7.4.8
654  */
655 static void
656 dis_field_seg_reassembly_ass(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
657 {
658     guint32     curr_offset;
659     guint32     value;
660     proto_item  *item;
661     proto_tree  *subtree;
662
663     curr_offset = *offset;
664
665 #define FIELD_SEG_REASSEMBLY_ASS_LEN    14
666
667     SHORT_DATA_CHECK(*len, FIELD_SEG_REASSEMBLY_ASS_LEN);
668
669     item =
670         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
671             curr_offset, FIELD_SEG_REASSEMBLY_ASS_LEN, field_strings[FIELD_SEG_REASSEMBLY_ASS]);
672
673     subtree = proto_item_add_subtree(item, ett_fields[FIELD_SEG_REASSEMBLY_ASS]);
674
675     value = tvb_get_ntoh24(tvb, curr_offset);
676
677     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
678         curr_offset, 3,
679         "Maximum length of SSSAR-SDU in the forward direction (%d)",
680         value);
681
682     curr_offset += 3;
683
684     value = tvb_get_ntoh24(tvb, curr_offset);
685
686     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
687         curr_offset, 3,
688         "Maximum length of SSSAR-SDU in the backward direction (%d)",
689         value);
690
691     curr_offset += 3;
692
693     value = tvb_get_ntohs(tvb, curr_offset);
694
695     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
696         curr_offset, 2,
697         "Maximum length of SSCOP-SDU in the forward direction (%d)",
698         value);
699
700     curr_offset += 2;
701
702     value = tvb_get_ntohs(tvb, curr_offset);
703
704     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
705         curr_offset, 2,
706         "Maximum length of SSCOP-SDU in the backward direction (%d)",
707         value);
708
709     curr_offset += 2;
710
711     value = tvb_get_ntohs(tvb, curr_offset);
712
713     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
714         curr_offset, 2,
715         "Maximum length of SSCOP-UU in the forward direction (%d)",
716         value);
717
718     curr_offset += 2;
719
720     value = tvb_get_ntohs(tvb, curr_offset);
721
722     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
723         curr_offset, 2,
724         "Maximum length of SSCOP-UU in the backward direction (%d)",
725         value);
726
727     curr_offset += 2;
728
729     *len -= (curr_offset - *offset);
730     *offset = curr_offset;
731 }
732
733 /*
734  * Ref. ITU-T Q.2630.1 (12/1999)
735  * Section 7.4.9
736  */
737 static void
738 dis_field_seg_reassembly_unass(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
739 {
740     guint32     curr_offset;
741     guint32     value;
742     guint8      oct;
743     proto_item  *item;
744     proto_tree  *subtree;
745
746     curr_offset = *offset;
747
748 #define FIELD_SEG_REASSEMBLY_UNASS_LEN  7
749
750     SHORT_DATA_CHECK(*len, FIELD_SEG_REASSEMBLY_UNASS_LEN);
751
752     item =
753         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
754             curr_offset, FIELD_SEG_REASSEMBLY_UNASS_LEN, field_strings[FIELD_SEG_REASSEMBLY_UNASS]);
755
756     subtree = proto_item_add_subtree(item, ett_fields[FIELD_SEG_REASSEMBLY_UNASS]);
757
758     value = tvb_get_ntoh24(tvb, curr_offset);
759
760     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
761         curr_offset, 3,
762         "Maximum length of SSSAR-SDU in the forward direction (%d)",
763         value);
764
765     curr_offset += 3;
766
767     value = tvb_get_ntoh24(tvb, curr_offset);
768
769     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
770         curr_offset, 3,
771         "Maximum length of SSSAR-SDU in the backward direction (%d)",
772         value);
773
774     curr_offset += 3;
775
776     oct = tvb_get_guint8(tvb, curr_offset);
777
778     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
779     proto_tree_add_text(subtree, tvb,
780         curr_offset, 1,
781         "%s :  TED, transmission error detection %s",
782         bigbuf,
783         oct & 0x80 ? "enabled" : "disabled");
784
785     other_decode_bitfield_value(bigbuf, oct, 0x7f, 8);
786     proto_tree_add_text(subtree, tvb,
787         curr_offset, 1,
788         "%s :  Reserved",
789         bigbuf);
790
791     curr_offset++;
792
793     *len -= (curr_offset - *offset);
794     *offset = curr_offset;
795 }
796
797 /*
798  * Ref. ITU-T Q.2630.1 (12/1999)
799  * Section 7.4.10
800  */
801 static void
802 dis_field_served_user_gen_ref(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
803 {
804     guint32     curr_offset;
805     guint32     value;
806
807     curr_offset = *offset;
808
809 #define FIELD_SERVED_USER_GEN_REF_LEN   4
810
811     SHORT_DATA_CHECK(*len, FIELD_SERVED_USER_GEN_REF_LEN);
812
813     value = tvb_get_ntohl(tvb, curr_offset);
814
815         if (value && check_col(g_pinfo->cinfo, COL_INFO))
816                 col_append_fstr(g_pinfo->cinfo, COL_INFO, " SUGR: %u", value);
817
818     proto_tree_add_uint(tree, hf_alcap_served_user_gen_ref, tvb,
819         curr_offset, FIELD_SERVED_USER_GEN_REF_LEN, value);
820
821     curr_offset += FIELD_SERVED_USER_GEN_REF_LEN;
822
823     *len -= (curr_offset - *offset);
824     *offset = curr_offset;
825 }
826
827 /*
828  * Ref. ITU-T Q.2630.1 (12/1999)
829  * Section 7.4.11
830  */
831 static void
832 dis_field_cps_sdu_bit_rate(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset, gboolean maximum)
833 {
834     guint32     curr_offset;
835     guint32     value;
836     proto_item  *item;
837     proto_tree  *subtree;
838
839     curr_offset = *offset;
840
841 #define FIELD_CPS_SDU_BIT_RATE_LEN      4
842
843     SHORT_DATA_CHECK(*len, FIELD_CPS_SDU_BIT_RATE_LEN);
844
845     item =
846         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
847             curr_offset, FIELD_CPS_SDU_BIT_RATE_LEN, field_strings[FIELD_MAX_CPS_SDU_BIT_RATE + (maximum ? 0 : 1)]);
848
849     subtree = proto_item_add_subtree(item, ett_fields[FIELD_MAX_CPS_SDU_BIT_RATE + (maximum ? 0 : 1)]);
850
851     value = tvb_get_ntohs(tvb, curr_offset);
852
853     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
854         curr_offset, 2,
855         "CPS-SDU bit rate in the forward direction (%d)",
856         value);
857
858     curr_offset += 2;
859
860     value = tvb_get_ntohs(tvb, curr_offset);
861
862     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
863         curr_offset, 2,
864         "CPS-SDU bit rate in the backward direction (%d)",
865         value);
866
867     curr_offset += 2;
868
869     *len -= (curr_offset - *offset);
870     *offset = curr_offset;
871 }
872
873 /*
874  * Ref. ITU-T Q.2630.1 (12/1999)
875  * Section 7.4.12
876  */
877 static void
878 dis_field_cps_sdu_size(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset, gboolean maximum)
879 {
880     guint32     curr_offset;
881     guint8      oct;
882     proto_item  *item;
883     proto_tree  *subtree;
884
885     curr_offset = *offset;
886
887 #define FIELD_CPS_SDU_SIZE_LEN  2
888
889     SHORT_DATA_CHECK(*len, FIELD_CPS_SDU_SIZE_LEN);
890
891     item =
892         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
893             curr_offset, FIELD_CPS_SDU_SIZE_LEN, field_strings[FIELD_MAX_CPS_SDU_SIZE + (maximum ? 0 : 1)]);
894
895     subtree = proto_item_add_subtree(item, ett_fields[FIELD_MAX_CPS_SDU_SIZE + (maximum ? 0 : 1)]);
896
897     oct = tvb_get_guint8(tvb, curr_offset);
898
899     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
900         curr_offset, 1,
901         "CPS-SDU size in the forward direction (%d)",
902         oct);
903
904     curr_offset++;
905
906     oct = tvb_get_guint8(tvb, curr_offset);
907
908     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
909         curr_offset, 1,
910         "CPS-SDU size in the backward direction (%d)",
911         oct);
912
913     curr_offset++;
914
915     *len -= (curr_offset - *offset);
916     *offset = curr_offset;
917 }
918
919 /*
920  * Ref. ITU-T Q.2630.1 (12/1999)
921  * Section 7.4.13
922  */
923 static void
924 dis_field_nature_of_address(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
925 {
926     guint32     curr_offset;
927     guint32     value;
928     guint8      oct;
929     proto_item  *item;
930     proto_tree  *subtree;
931     gchar       *str = NULL;
932
933     curr_offset = *offset;
934
935 #define FIELD_NATURE_OF_ADDRESS_LEN     1
936
937     SHORT_DATA_CHECK(*len, FIELD_NATURE_OF_ADDRESS_LEN);
938
939     item =
940         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
941             curr_offset, FIELD_NATURE_OF_ADDRESS_LEN, field_strings[FIELD_NATURE_OF_ADDRESS]);
942
943     subtree = proto_item_add_subtree(item, ett_fields[FIELD_NATURE_OF_ADDRESS]);
944
945     oct = tvb_get_guint8(tvb, curr_offset);
946
947     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
948     proto_tree_add_text(subtree, tvb,
949         curr_offset, 1,
950         "%s :  Reserved",
951         bigbuf);
952
953     value = oct & 0x7f;
954
955     switch (value)
956     {
957     case 0x00: str = "spare"; break;
958     case 0x01: str = "subscriber number (national use)"; break;
959     case 0x02: str = "unknown (national use)"; break;
960     case 0x03: str = "national (significant) number"; break;
961     case 0x04: str = "international number"; break;
962     case 0x05: str = "network-specific number (national use)"; break;
963     default:
964         if ((value >= 0x06) && (value <= 0x6f)) { str = "spare"; break; }
965         else if ((value >= 0x70) && (value <= 0xfe)) { str = "reserved for national use"; break; }
966         else { str = "not given in spec. ???"; break; }
967     }
968
969     other_decode_bitfield_value(bigbuf, oct, 0x7f, 8);
970     proto_tree_add_text(subtree, tvb,
971         curr_offset, 1,
972         "%s :  Nature of address code, %s (%d)",
973         bigbuf,
974         str,
975         value);
976
977     curr_offset++;
978
979     *len -= (curr_offset - *offset);
980     *offset = curr_offset;
981 }
982
983 /*
984  * Ref. ITU-T Q.2630.1 (12/1999)
985  * Section 7.4.14
986  */
987 static void
988 dis_field_e164_address(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
989 {
990     guint32     curr_offset;
991     proto_item  *item;
992     proto_tree  *subtree;
993     guint8      parm_len;
994     guint8      oct;
995     guint8      i;
996
997     curr_offset = *offset;
998
999     SHORT_DATA_CHECK(*len, 1);
1000
1001     item =
1002         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
1003             curr_offset, -1, field_strings[FIELD_E164_ADDRESS]);
1004
1005     subtree = proto_item_add_subtree(item, ett_fields[FIELD_E164_ADDRESS]);
1006
1007     parm_len = tvb_get_guint8(tvb, curr_offset);
1008
1009     proto_item_set_len(item, parm_len + 1);
1010
1011     proto_tree_add_uint(subtree, hf_alcap_length, tvb, curr_offset, 1, parm_len);
1012
1013     curr_offset++;
1014
1015     if (parm_len > 0)
1016     {
1017         i=0;
1018         while (i < parm_len)
1019         {
1020             oct = tvb_get_guint8(tvb, curr_offset);
1021
1022             other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
1023             proto_tree_add_text(subtree, tvb,
1024                 curr_offset, 1,
1025                 "%s :  Reserved",
1026                 bigbuf);
1027
1028             bigbuf2[i] = (oct & 0x0f) + 0x30;
1029
1030             other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
1031             proto_tree_add_text(subtree, tvb,
1032                 curr_offset, 1,
1033                 "%s :  Digit %d of address (%d)",
1034                 bigbuf,
1035                 i+1,
1036                 oct & 0x0f);
1037
1038             curr_offset++;
1039             i++;
1040         }
1041
1042         bigbuf2[i] = '\0';
1043
1044         if (check_col(g_pinfo->cinfo, COL_INFO))
1045                 col_append_fstr(g_pinfo->cinfo, COL_INFO, " E164: %s", bigbuf2);
1046
1047         proto_item_append_text(item, " (%s)", bigbuf2);
1048     }
1049
1050     *len -= (curr_offset - *offset);
1051     *offset = curr_offset;
1052 }
1053
1054 /*
1055  * Ref. ITU-T Q.2630.1 (12/1999)
1056  * Section 7.4.15
1057  */
1058 static void
1059 dis_field_nsap_address(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
1060 {
1061     guint32     curr_offset;
1062         
1063     curr_offset = *offset;
1064
1065 #define FIELD_NSAP_ADDRESS_LEN  20
1066
1067     SHORT_DATA_CHECK(*len, FIELD_NSAP_ADDRESS_LEN);
1068
1069     proto_tree_add_item(tree, hf_alcap_nsap_address, tvb,
1070                                                 curr_offset, FIELD_NSAP_ADDRESS_LEN,FALSE);
1071
1072     curr_offset += FIELD_NSAP_ADDRESS_LEN;
1073
1074     *len -= (curr_offset - *offset);
1075     *offset = curr_offset;
1076 }
1077
1078 /*
1079  * Ref. ITU-T Q.2630.1 (12/1999)
1080  * Section 7.4.16
1081  */
1082 static void
1083 dis_field_cause_value(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset, gboolean *compat)
1084 {
1085     guint32     curr_offset;
1086     guint8      oct;
1087     proto_item  *item;
1088     proto_tree  *subtree;
1089     gchar       *str = NULL;
1090
1091     *compat = FALSE;
1092     curr_offset = *offset;
1093
1094 #define FIELD_CAUSE_VALUE_LEN   2
1095
1096     SHORT_DATA_CHECK(*len, FIELD_CAUSE_VALUE_LEN);
1097
1098     item =
1099         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
1100             curr_offset, FIELD_CAUSE_VALUE_LEN, field_strings[FIELD_CAUSE_VALUE]);
1101
1102     subtree = proto_item_add_subtree(item, ett_fields[FIELD_CAUSE_VALUE]);
1103
1104     oct = tvb_get_guint8(tvb, curr_offset);
1105
1106     other_decode_bitfield_value(bigbuf, oct, 0xfc, 8);
1107     proto_tree_add_text(subtree, tvb,
1108         curr_offset, 1,
1109         "%s :  Reserved",
1110         bigbuf);
1111
1112     switch (oct & 0x3)
1113     {
1114     case 0x00: str = "ITU-T standardized coding as described in ITU-T Rec. Q.850 and Q.2610"; break;
1115     case 0x01: str = "ISO/IEC standard"; break;
1116     case 0x02: str = "national standard"; break;
1117     case 0x03: str = "standard defined for the network (either public or private) present on the network side of the interface"; break;
1118     }
1119
1120     other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
1121     proto_tree_add_text(subtree, tvb,
1122         curr_offset, 1,
1123         "%s :  Coding standard, %s",
1124         bigbuf,
1125         str);
1126
1127     curr_offset++;
1128
1129     oct = tvb_get_guint8(tvb, curr_offset);
1130
1131     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
1132     proto_tree_add_text(subtree, tvb,
1133         curr_offset, 1,
1134         "%s :  Reserved",
1135         bigbuf);
1136
1137     switch (oct & 0x7f)
1138     {
1139     case 1: str = "Unallocated (unassigned) number"; break;
1140     case 3: str = "No route to destination"; break;
1141     case 31: str = "Normal, unspecified"; break;
1142     case 34: str = "No circuit/channel available"; break;
1143     case 38: str = "Network out of order"; break;
1144     case 41: str = "Temporary failure"; break;
1145     case 42: str = "Switching equipment congestion"; break;
1146     case 44: str = "Requested circuit/channel not available"; break;
1147     case 47: str = "Resource unavailable, unspecified"; break;
1148     case 93: str = "AAL parameters cannot be supported"; break;
1149     case 95: str = "Invalid message, unspecified"; break;
1150     case 96: str = "Mandatory information element is missing"; break;
1151     case 97: str = "Message type non-existent or not implemented"; *compat = TRUE; break;
1152     case 99: str = "Information element/parameter non-existent or not implemented"; *compat = TRUE; break;
1153     case 100: str = "Invalid information element contents"; break;
1154     case 102: str = "Recovery on timer expiry"; break;
1155     case 110: str = "Message with unrecognized parameter, discarded"; *compat = TRUE; break;
1156     default: str = "Unknown"; break;
1157     }
1158
1159     other_decode_bitfield_value(bigbuf, oct, 0x7f, 8);
1160     proto_tree_add_text(subtree, tvb,
1161         curr_offset, 1,
1162         "%s :  Cause (%d), %s",
1163         bigbuf,
1164         oct & 0x7f,
1165         str);
1166
1167     curr_offset++;
1168
1169     *len -= (curr_offset - *offset);
1170     *offset = curr_offset;
1171 }
1172
1173 /*
1174  * Ref. ITU-T Q.2630.1 (12/1999)
1175  * Section 7.4.17
1176  */
1177 static void
1178 dis_field_diagnostics(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset, gboolean compat)
1179 {
1180     guint32     curr_offset;
1181     guint8      oct;
1182     proto_item  *item;
1183     proto_tree  *subtree;
1184     guint8      parm_len;
1185     gchar       *str = NULL;
1186     gint        idx;
1187     guint8      i;
1188
1189     curr_offset = *offset;
1190
1191     SHORT_DATA_CHECK(*len, 1);
1192
1193     item =
1194         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
1195             curr_offset, -1, field_strings[FIELD_DIAGNOSTICS]);
1196
1197     subtree = proto_item_add_subtree(item, ett_fields[FIELD_DIAGNOSTICS]);
1198
1199     parm_len = tvb_get_guint8(tvb, curr_offset);
1200
1201     proto_item_set_len(item, parm_len + 1);
1202
1203     proto_tree_add_uint(subtree, hf_alcap_length, tvb, curr_offset, 1, parm_len);
1204
1205     curr_offset++;
1206
1207     if (parm_len > 0)
1208     {
1209         if (compat)
1210         {
1211             /*
1212              * compatibility diagnostics
1213              */
1214             oct = tvb_get_guint8(tvb, curr_offset);
1215
1216             str = my_match_strval(oct, msg_type_strings, &idx);
1217
1218             proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1219                 curr_offset, 1, (str == NULL) ? "Unknown message identifier" : str);
1220
1221             curr_offset++;
1222
1223             i=1;
1224             while ((i+2) <= parm_len)
1225             {
1226                 oct = tvb_get_guint8(tvb, curr_offset);
1227
1228                 str = my_match_strval(oct, msg_parm_strings, &idx);
1229
1230                 proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1231                     curr_offset, 1, (str == NULL) ? "Unknown parameter" : str);
1232
1233                 curr_offset++;
1234
1235                 oct = tvb_get_guint8(tvb, curr_offset);
1236
1237                 if (oct == 0)
1238                 {
1239                     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1240                         curr_offset, 1, "Whole parameter");
1241                 }
1242                 else
1243                 {
1244                     proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1245                         curr_offset, 1, "Field number %d", oct);
1246                 }
1247
1248                 curr_offset++;
1249                 i += 2;
1250             }
1251
1252             if (i != parm_len)
1253             {
1254                 proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1255                     curr_offset, parm_len - i, "Extraneous Data ???");
1256
1257                 curr_offset += (parm_len - i);
1258             }
1259         }
1260         else
1261         {
1262             proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1263                 curr_offset, parm_len, "Coded as per ITU-T Rec. Q.2610");
1264
1265             curr_offset += parm_len;
1266         }
1267     }
1268
1269     *len -= (curr_offset - *offset);
1270     *offset = curr_offset;
1271 }
1272
1273 /*
1274  * Ref. ITU-T Q.2630.1 (12/1999)
1275  * Section 7.4.18
1276  */
1277 static void
1278 dis_field_served_user_transport(tvbuff_t *tvb, proto_tree *tree, guint *len, guint32 *offset)
1279 {
1280     guint32     curr_offset;
1281     proto_item  *item;
1282     proto_tree  *subtree;
1283     guint8      parm_len;
1284
1285     curr_offset = *offset;
1286
1287     SHORT_DATA_CHECK(*len, 1);
1288
1289     item =
1290         proto_tree_add_none_format(tree, hf_alcap_none, tvb,
1291             curr_offset, -1, field_strings[FIELD_SERVED_USER_TRANSPORT]);
1292
1293     subtree = proto_item_add_subtree(item, ett_fields[FIELD_SERVED_USER_TRANSPORT]);
1294
1295     parm_len = tvb_get_guint8(tvb, curr_offset);
1296
1297     proto_item_set_len(item, parm_len + 1);
1298
1299     proto_tree_add_uint(subtree, hf_alcap_length, tvb, curr_offset, 1, parm_len);
1300
1301     curr_offset++;
1302
1303     if (parm_len > 0)
1304     {
1305         proto_tree_add_none_format(subtree, hf_alcap_none, tvb,
1306             curr_offset, parm_len, "Value");
1307
1308         curr_offset += parm_len;
1309     }
1310
1311     *len -= (curr_offset - *offset);
1312     *offset = curr_offset;
1313 }
1314
1315 /*
1316  * Ref. ITU-T Q.2630.1 (12/1999)
1317  * Section 7.3.1
1318  */
1319 static void
1320 dis_parm_cause(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1321 {
1322     gboolean    compat;
1323
1324     dis_field_cause_value(tvb, tree, &len, &curr_offset, &compat);
1325
1326     dis_field_diagnostics(tvb, tree, &len, &curr_offset, compat);
1327
1328     EXTRANEOUS_DATA_CHECK(len, 0);
1329 }
1330
1331 /*
1332  * Ref. ITU-T Q.2630.1 (12/1999)
1333  * Section 7.3.2
1334  */
1335 static void
1336 dis_parm_conn_element_id(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1337 {
1338
1339     dis_field_aal2_path_id(tvb, tree, &len, &curr_offset);
1340
1341     dis_field_channel_id(tvb, tree, &len, &curr_offset);
1342
1343     EXTRANEOUS_DATA_CHECK(len, 0);
1344 }
1345
1346 /*
1347  * Ref. ITU-T Q.2630.1 (12/1999)
1348  * Section 7.3.3
1349  */
1350 static void
1351 dis_parm_dest_e164_sea(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1352 {
1353
1354     dis_field_nature_of_address(tvb, tree, &len, &curr_offset);
1355
1356     dis_field_e164_address(tvb, tree, &len, &curr_offset);
1357
1358     EXTRANEOUS_DATA_CHECK(len, 0);
1359 }
1360
1361 /*
1362  * Ref. ITU-T Q.2630.1 (12/1999)
1363  * Section 7.3.4
1364  */
1365 static void
1366 dis_parm_dest_nsap_sea(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1367 {
1368
1369     dis_field_nsap_address(tvb, tree, &len, &curr_offset);
1370
1371     EXTRANEOUS_DATA_CHECK(len, 0);
1372 }
1373
1374 /*
1375  * Ref. ITU-T Q.2630.1 (12/1999)
1376  * Section 7.3.5
1377  */
1378 static void
1379 dis_parm_link_characteristics(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1380 {
1381
1382     dis_field_cps_sdu_bit_rate(tvb, tree, &len, &curr_offset, TRUE);
1383
1384     dis_field_cps_sdu_bit_rate(tvb, tree, &len, &curr_offset, FALSE);
1385
1386     dis_field_cps_sdu_size(tvb, tree, &len, &curr_offset, TRUE);
1387
1388     dis_field_cps_sdu_size(tvb, tree, &len, &curr_offset, FALSE);
1389
1390     EXTRANEOUS_DATA_CHECK(len, 0);
1391 }
1392
1393 /*
1394  * Ref. ITU-T Q.2630.1 (12/1999)
1395  * Section 7.3.6
1396  */
1397 static void
1398 dis_parm_osai(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1399 {
1400
1401     dis_field_signalling_assoc_id(tvb, tree, &len, &curr_offset, FALSE);
1402
1403     EXTRANEOUS_DATA_CHECK(len, 0);
1404 }
1405
1406 /*
1407  * Ref. ITU-T Q.2630.1 (12/1999)
1408  * Section 7.3.7
1409  */
1410 static void
1411 dis_parm_served_user_gen_ref(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1412 {
1413
1414     dis_field_served_user_gen_ref(tvb, tree, &len, &curr_offset);
1415
1416     EXTRANEOUS_DATA_CHECK(len, 0);
1417 }
1418
1419 /*
1420  * Ref. ITU-T Q.2630.1 (12/1999)
1421  * Section 7.3.8
1422  */
1423 static void
1424 dis_parm_served_user_transport(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1425 {
1426
1427     dis_field_served_user_transport(tvb, tree, &len, &curr_offset);
1428
1429     EXTRANEOUS_DATA_CHECK(len, 0);
1430 }
1431
1432 /*
1433  * Ref. ITU-T Q.2630.1 (12/1999)
1434  * Section 7.3.9
1435  */
1436 static void
1437 dis_parm_service_specific_info_audio(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1438 {
1439
1440     dis_field_audio_service(tvb, tree, &len, &curr_offset);
1441
1442     dis_field_organizational_unique_id(tvb, tree, &len, &curr_offset);
1443
1444     EXTRANEOUS_DATA_CHECK(len, 0);
1445 }
1446
1447 /*
1448  * Ref. ITU-T Q.2630.1 (12/1999)
1449  * Section 7.3.10
1450  */
1451 static void
1452 dis_parm_service_specific_info_multirate(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1453 {
1454
1455     dis_field_multirate_service(tvb, tree, &len, &curr_offset);
1456
1457     EXTRANEOUS_DATA_CHECK(len, 0);
1458 }
1459
1460 /*
1461  * Ref. ITU-T Q.2630.1 (12/1999)
1462  * Section 7.3.11
1463  */
1464 static void
1465 dis_parm_service_specific_info_ass(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1466 {
1467
1468     dis_field_seg_reassembly_ass(tvb, tree, &len, &curr_offset);
1469
1470     EXTRANEOUS_DATA_CHECK(len, 0);
1471 }
1472
1473 /*
1474  * Ref. ITU-T Q.2630.1 (12/1999)
1475  * Section 7.3.12
1476  */
1477 static void
1478 dis_parm_service_specific_info_unass(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 curr_offset)
1479 {
1480
1481     dis_field_seg_reassembly_unass(tvb, tree, &len, &curr_offset);
1482
1483     EXTRANEOUS_DATA_CHECK(len, 0);
1484 }
1485
1486 static gint ett_parms[NUM_PARMS];
1487 static void (*alcap_parm_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
1488     dis_parm_cause,                             /* Cause */
1489     dis_parm_conn_element_id,                           /* Connection element identifier */
1490     dis_parm_dest_e164_sea,                     /* Destination E.164 service endpoint address */
1491     dis_parm_dest_nsap_sea,                     /* Destination NSAP service endpoint address */
1492     dis_parm_link_characteristics,              /* Link characteristics */
1493     dis_parm_osai,                              /* Originating signalling association identifier */
1494     dis_parm_served_user_gen_ref,               /* Served user generated reference */
1495     dis_parm_served_user_transport,             /* Served user transport */
1496     dis_parm_service_specific_info_audio,       /* Service specific information (audio) */
1497     dis_parm_service_specific_info_multirate,   /* Service specific information (multirate) */
1498     dis_parm_service_specific_info_ass,         /* Service specific information (SAR-assured) */
1499     dis_parm_service_specific_info_unass,       /* Service specific information (SAR-unassured) */
1500     NULL /* no parms */,                        /* Test connection identifier */
1501     NULL,       /* NONE */
1502 };
1503
1504 /* GENERIC ALCAP DISSECTOR FUNCTIONS */
1505
1506 static void
1507 dissect_alcap_parms(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 len)
1508 {
1509     void (*parm_fcn)(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = NULL;
1510     guint8      parm;
1511     guint8      parm_len;
1512     guint32     curr_offset, saved_offset;
1513     gint        idx;
1514     gchar       *str = NULL;
1515     proto_item  *item;
1516     proto_tree  *subtree;
1517     gint        ett_parm_idx;
1518
1519
1520     curr_offset = offset;
1521
1522     while (len >= ALCAP_PARM_HEADER_LEN)
1523     {
1524                 saved_offset = curr_offset;
1525                 
1526                 parm = tvb_get_guint8(tvb, curr_offset);
1527                 
1528                 str = my_match_strval(parm, msg_parm_strings, &idx);
1529                 
1530                 if (str == NULL)
1531                 {
1532                         ett_parm_idx = ett_parm;
1533                         parm_fcn = NULL;
1534                 }
1535                 else
1536                 {
1537                         ett_parm_idx = ett_parms[idx];
1538                         parm_fcn = alcap_parm_fcn[idx];
1539                 }
1540                 
1541                 item = proto_tree_add_none_format(tree, hf_alcap_none, tvb,
1542                                                                                   curr_offset, -1,
1543                                                                                   (str == NULL) ? "Unknown parameter" : str);
1544                 
1545                 subtree = proto_item_add_subtree(item, ett_parm_idx);
1546                 
1547                 proto_tree_add_uint(subtree, hf_alcap_parm_id, tvb,
1548                                                         curr_offset, 1, parm);
1549                 
1550                 curr_offset++;
1551                 
1552                 dis_field_compatibility(tvb, subtree, &curr_offset, FALSE);
1553                 
1554                 parm_len = tvb_get_guint8(tvb, curr_offset);
1555                 
1556                 proto_tree_add_uint(subtree, hf_alcap_length, tvb, curr_offset, 1, parm_len);
1557                 
1558                 curr_offset++;
1559                 
1560                 proto_item_set_len(item, (curr_offset - saved_offset) + parm_len);
1561                 
1562                 if (parm_len > 0)
1563                 {
1564                         if (parm_fcn == NULL)
1565                         {
1566                                 proto_tree_add_none_format(subtree, hf_alcap_none,
1567                                                                                    tvb, curr_offset, parm_len, "Parameter data");
1568                         }
1569                         else
1570                         {
1571                                 (*parm_fcn)(tvb, subtree, parm_len, curr_offset);
1572                         }
1573                 }
1574                 
1575                 len -= (ALCAP_PARM_HEADER_LEN + parm_len);
1576                 curr_offset += parm_len;
1577     }
1578
1579     EXTRANEOUS_DATA_CHECK(len, 0);
1580 }
1581
1582 static void
1583 dissect_alcap_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *alcap_tree)
1584 {
1585     guint32     temp_len;
1586     guint32     len;
1587     guint32     offset;
1588     guint8      msg_type;
1589     gint        idx;
1590     gchar       *str = NULL;
1591
1592     offset = 0;
1593
1594     len = tvb_length(tvb);
1595     temp_len = len;
1596
1597     if (len < ALCAP_MSG_HEADER_LEN)
1598     {
1599         proto_tree_add_none_format(alcap_tree, hf_alcap_none, tvb,
1600             offset, len, "Message header too short");
1601
1602         return;
1603     }
1604
1605     dis_field_signalling_assoc_id(tvb, alcap_tree, &temp_len, &offset, TRUE);
1606
1607     msg_type = tvb_get_guint8(tvb, offset);
1608
1609     str = my_match_strval(msg_type, msg_type_strings, &idx);
1610
1611     if (str == NULL)
1612     {
1613         proto_tree_add_none_format(alcap_tree, hf_alcap_none, tvb,
1614             offset, 1, "Unknown message identifier");
1615
1616         return;
1617     }
1618
1619     if (check_col(pinfo->cinfo, COL_INFO))
1620     {
1621         col_set_str(pinfo->cinfo, COL_INFO, str);
1622     }
1623
1624     proto_tree_add_uint(alcap_tree, hf_alcap_msg_type, tvb,
1625         offset, 1, msg_type);
1626
1627     offset++;
1628
1629     dis_field_compatibility(tvb, alcap_tree, &offset, TRUE);
1630
1631     if (len > ALCAP_MSG_HEADER_LEN)
1632     {
1633         dissect_alcap_parms(tvb, alcap_tree, offset, len - ALCAP_MSG_HEADER_LEN);
1634     }
1635 }
1636
1637 static void
1638 dissect_alcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1639 {
1640     proto_item  *alcap_item;
1641     proto_tree  *alcap_tree = NULL;
1642
1643     g_pinfo = pinfo;
1644
1645     /*
1646      * Don't change the Protocol column on summary display
1647      */
1648     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1649     {
1650         col_set_str(pinfo->cinfo, COL_PROTOCOL, alcap_proto_name_short);
1651     }
1652
1653     /* In the interest of speed, if "tree" is NULL, don't do any work not
1654      * necessary to generate protocol tree items.
1655      */
1656     if (tree)
1657     {
1658         g_tree = tree;
1659
1660         /*
1661          * create the ALCAP protocol tree
1662          */
1663         alcap_item =
1664             proto_tree_add_protocol_format(tree, proto_alcap, tvb, 0, -1,
1665                 alcap_proto_name);
1666
1667         alcap_tree =
1668             proto_item_add_subtree(alcap_item, ett_alcap);
1669
1670     }
1671         
1672         dissect_alcap_message(tvb, pinfo, alcap_tree);
1673
1674 }
1675
1676
1677 /* Register the protocol with Ethereal */
1678 void
1679 proto_register_alcap(void)
1680 {
1681     guint               i;
1682
1683     /* Setup list of header fields */
1684     static hf_register_info hf[] =
1685     {
1686         { &hf_alcap_msg_type,
1687           { "Message Type",
1688             "alcap.msg_type",
1689             FT_UINT8, BASE_DEC, VALS(msg_type_strings), 0,
1690             "", HFILL }},
1691         { &hf_alcap_dsaid,
1692           { "Destination signalling association identifier",
1693             "alcap.dsai",
1694             FT_UINT32, BASE_DEC, NULL, 0,
1695             "", HFILL }
1696         },
1697         { &hf_alcap_osaid,
1698           { "Originating signalling association identifier",
1699             "alcap.osai",
1700             FT_UINT32, BASE_DEC, NULL, 0,
1701             "", HFILL }
1702         },
1703         { &hf_alcap_aal2_path_id,
1704           { "AAL2 path identifier",
1705             "alcap.path_id",
1706             FT_UINT32, BASE_DEC, NULL, 0,
1707             "", HFILL }
1708         },
1709         { &hf_alcap_channel_id,
1710           { "Channel identifier (CID)",
1711             "alcap.cid",
1712             FT_UINT32, BASE_DEC, NULL, 0,
1713             "", HFILL }
1714         },
1715         { &hf_alcap_organizational_unique_id,
1716           { "Organizational unique identifier (OUI)",
1717             "alcap.oui",
1718             FT_UINT24, BASE_DEC, NULL, 0,
1719             "", HFILL }
1720         },
1721         { &hf_alcap_served_user_gen_ref,
1722           { "Served user generated reference",
1723             "alcap.sugr",
1724             FT_UINT32, BASE_DEC, NULL, 0,
1725             "", HFILL }
1726         },
1727         { &hf_alcap_nsap_address,
1728           { "NSAP address",
1729             "alcap.nsap",
1730             FT_BYTES, BASE_NONE, NULL, 0,
1731             "", HFILL }
1732         },
1733         { &hf_alcap_parm_id,
1734           { "Parameter identifier",
1735             "alcap.param_id",
1736             FT_UINT8, BASE_DEC, NULL, 0,
1737             "", HFILL }},
1738         { &hf_alcap_length,
1739             { "Length",         "alcap.len",
1740             FT_UINT8, BASE_DEC, NULL, 0,
1741             "", HFILL }
1742         },
1743         { &hf_alcap_none,
1744             { "Subtree",        "alcap.none",
1745             FT_NONE, 0, 0, 0,
1746             "", HFILL }
1747         },
1748     };
1749
1750     /* Setup protocol subtree array */
1751 #define NUM_INDIVIDUAL_PARMS    2
1752     static gint *ett[NUM_INDIVIDUAL_PARMS+NUM_PARMS+NUM_FIELDS];
1753
1754     memset((void *) ett, 0, sizeof(ett));
1755
1756     ett[0] = &ett_alcap;
1757     ett[1] = &ett_parm;
1758
1759     for (i=0; i < NUM_PARMS; i++)
1760     {
1761         ett_parms[i] = -1;
1762         ett[NUM_INDIVIDUAL_PARMS+i] = &ett_parms[i];
1763     }
1764
1765     for (i=0; i < NUM_FIELDS; i++)
1766     {
1767         ett_fields[i] = -1;
1768         ett[NUM_INDIVIDUAL_PARMS+NUM_PARMS+i] = &ett_fields[i];
1769     }
1770
1771     /* Register the protocol name and description */
1772     proto_alcap =
1773         proto_register_protocol(alcap_proto_name, alcap_proto_name_short, "alcap");
1774
1775         register_dissector("alcap", dissect_alcap, proto_alcap);
1776         
1777     /* Required function calls to register the header fields and subtrees used */
1778     proto_register_field_array(proto_alcap, hf, array_length(hf));
1779     proto_register_subtree_array(ett, array_length(ett));
1780 }
1781
1782
1783 void
1784 proto_reg_handoff_alcap(void)
1785 {
1786     dissector_handle_t  alcap_handle;
1787
1788     alcap_handle = create_dissector_handle(dissect_alcap, proto_alcap);
1789
1790     dissector_add("mtp3.service_indicator", ALCAP_SI, alcap_handle);
1791
1792     data_handle = find_dissector("data");
1793 }