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