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