add details for doxygen
[obnox/wireshark/wip.git] / packet-clnp.c
1 /* packet-clnp.c
2  * Routines for ISO/OSI network and transport protocol packet disassembly
3  *
4  * $Id: packet-clnp.c,v 1.85 2004/05/24 02:25:18 guy Exp $
5  * Laurent Deniel <laurent.deniel@free.fr>
6  * Ralf Schneider <Ralf.Schneider@t-online.de>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <glib.h>
34 #include "prefs.h"
35 #include <epan/packet.h>
36 #include "reassemble.h"
37 #include "packet-osi.h"
38 #include "packet-osi-options.h"
39 #include "packet-isis.h"
40 #include "packet-esis.h"
41 #include "nlpid.h"
42 #include "ipproto.h"
43
44 /* protocols and fields */
45
46 static int  proto_clnp         = -1;
47 static gint ett_clnp           = -1;
48 static gint ett_clnp_type      = -1;
49 static gint ett_clnp_segments  = -1;
50 static gint ett_clnp_segment   = -1;
51 static gint ett_clnp_disc_pdu  = -1;
52
53 static int hf_clnp_id          = -1;
54 static int hf_clnp_length      = -1;
55 static int hf_clnp_version     = -1;
56 static int hf_clnp_ttl         = -1;
57 static int hf_clnp_type        = -1;
58 static int hf_clnp_pdu_length  = -1;
59 static int hf_clnp_checksum    = -1;
60 static int hf_clnp_dest_length = -1;
61 static int hf_clnp_dest        = -1;
62 static int hf_clnp_src_length  = -1;
63 static int hf_clnp_src         = -1;
64 static int hf_clnp_segments    = -1;
65 static int hf_clnp_segment     = -1;
66 static int hf_clnp_segment_overlap = -1;
67 static int hf_clnp_segment_overlap_conflict = -1;
68 static int hf_clnp_segment_multiple_tails = -1;
69 static int hf_clnp_segment_too_long_segment = -1;
70 static int hf_clnp_segment_error = -1;
71 static int hf_clnp_reassembled_in = -1;
72
73 static int  proto_cotp         = -1;
74 static gint ett_cotp           = -1;
75 static gint ett_cotp_segments  = -1;
76 static gint ett_cotp_segment   = -1;
77
78 static int hf_cotp_srcref      = -1;
79 static int hf_cotp_destref     = -1;
80 static int hf_cotp_type        = -1;
81 static int hf_cotp_segments    = -1;
82 static int hf_cotp_segment     = -1;
83 static int hf_cotp_segment_overlap = -1;
84 static int hf_cotp_segment_overlap_conflict = -1;
85 static int hf_cotp_segment_multiple_tails = -1;
86 static int hf_cotp_segment_too_long_segment = -1;
87 static int hf_cotp_segment_error = -1;
88 static int hf_cotp_reassembled_in = -1;
89
90 static int  proto_cltp         = -1;
91 static gint ett_cltp           = -1;
92
93 static int hf_cltp_type = -1;
94
95 static const fragment_items clnp_frag_items = {
96         &ett_clnp_segment,
97         &ett_clnp_segments,
98         &hf_clnp_segments,
99         &hf_clnp_segment,
100         &hf_clnp_segment_overlap,
101         &hf_clnp_segment_overlap_conflict,
102         &hf_clnp_segment_multiple_tails,
103         &hf_clnp_segment_too_long_segment,
104         &hf_clnp_segment_error,
105         &hf_clnp_reassembled_in,
106         "segments"
107 };
108
109 static const fragment_items cotp_frag_items = {
110         &ett_cotp_segment,
111         &ett_cotp_segments,
112         &hf_cotp_segments,
113         &hf_cotp_segment,
114         &hf_cotp_segment_overlap,
115         &hf_cotp_segment_overlap_conflict,
116         &hf_cotp_segment_multiple_tails,
117         &hf_cotp_segment_too_long_segment,
118         &hf_cotp_segment_error,
119         &hf_cotp_reassembled_in,
120         "segments"
121 };
122
123 static dissector_handle_t clnp_handle;
124 static dissector_handle_t data_handle;
125
126 /*
127  * ISO 8473 OSI CLNP definition (see RFC994)
128  *
129  *            _________________________________
130  *           |           Fixed Part            |
131  *           |_________________________________|
132  *           |          Address Part           |
133  *           |_________________________________|
134  *           |   Segmentation Part (optional)  |
135  *           |_________________________________|
136  *           |     Options Part (optional)     |
137  *           |_________________________________|
138  *           |         Data (optional)         |
139  *           |_________________________________|
140  */
141
142 #define ISO8473_V1  0x01    /* CLNP version 1 */
143
144 /* Fixed part */
145
146 #define CNF_TYPE                0x1f
147 #define CNF_ERR_OK              0x20
148 #define CNF_MORE_SEGS           0x40
149 #define CNF_SEG_OK              0x80
150
151 #define DT_NPDU                 0x1C
152 #define MD_NPDU                 0x1D
153 #define ER_NPDU                 0x01
154 #define ERQ_NPDU                0x1E
155 #define ERP_NPDU                0x1F
156
157 static const value_string npdu_type_abbrev_vals[] = {
158   { DT_NPDU,    "DT" },
159   { MD_NPDU,    "MD" },
160   { ER_NPDU,    "ER" },
161   { ERQ_NPDU,   "ERQ" },
162   { ERP_NPDU,   "ERP" },
163   { 0,          NULL }
164 };
165
166 static const value_string npdu_type_vals[] = {
167   { DT_NPDU,    "Data" },
168   { MD_NPDU,    "Multicast Data" },
169   { ER_NPDU,    "Error Report" },
170   { ERQ_NPDU,   "Echo Request" },
171   { ERP_NPDU,   "Echo Response" },
172   { 0,          NULL }
173 };
174
175 /* field position */
176
177 #define P_CLNP_PROTO_ID         0
178 #define P_CLNP_HDR_LEN          1
179 #define P_CLNP_VERS             2
180 #define P_CLNP_TTL              3
181 #define P_CLNP_TYPE             4
182 #define P_CLNP_SEGLEN           5
183 #define P_CLNP_CKSUM            7
184 #define P_CLNP_ADDRESS_PART     9
185
186 /* Segmentation part */
187
188 struct clnp_segment {
189   gushort       cng_id;         /* data unit identifier */
190   gushort       cng_off;        /* segment offset */
191   gushort       cng_tot_len;    /* total length */
192 };
193
194 /* NSAP selector */
195
196 #define NSEL_NET                0x00
197 #define NSEL_NP                 0x20
198 #define NSEL_TP                 0x21
199
200 /*
201  * ISO8073 OSI COTP definition (see RFC905)
202  */
203
204 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
205
206 /* TPDU definition */
207
208 #define ED_TPDU                 0x1     /* COTP */
209 #define EA_TPDU                 0x2     /* COTP */
210 #define UD_TPDU                 0x4     /* CLTP */
211 #define RJ_TPDU                 0x5     /* COTP */
212 #define AK_TPDU                 0x6     /* COTP */
213 #define ER_TPDU                 0x7     /* COTP */
214 #define DR_TPDU                 0x8     /* COTP */
215 #define DC_TPDU                 0xC     /* COTP */
216 #define CC_TPDU                 0xD     /* COTP */
217 #define CR_TPDU                 0xE     /* COTP */
218 #define DT_TPDU                 0xF     /* COTP */
219
220 static const value_string cotp_tpdu_type_abbrev_vals[] = {
221   { ED_TPDU,    "ED" },
222   { EA_TPDU,    "EA" },
223   { RJ_TPDU,    "RJ" },
224   { AK_TPDU,    "AK" },
225   { ER_TPDU,    "ER" },
226   { DR_TPDU,    "DR" },
227   { DC_TPDU,    "DC" },
228   { CC_TPDU,    "CC" },
229   { CR_TPDU,    "CR" },
230   { DT_TPDU,    "DT" },
231   { 0,          NULL }
232 };
233
234 static const value_string cltp_tpdu_type_abbrev_vals[] = {
235   { UD_TPDU,    "UD" },
236   { 0,          NULL }
237 };
238
239 /* field position */
240
241 #define P_LI                    0
242 #define P_TPDU                  1
243 #define P_CDT                   1
244 #define P_DST_REF               2
245 #define P_SRC_REF               4
246 #define P_TPDU_NR_0_1           2
247 #define P_TPDU_NR_234           4
248 #define P_VAR_PART_NDT          5
249 #define P_VAR_PART_EDT          8
250 #define P_VAR_PART_DC           6
251 #define P_CDT_IN_AK             8
252 #define P_CDT_IN_RJ             8
253 #define P_REJECT_ER             4
254 #define P_REASON_IN_DR          6
255 #define P_CLASS_OPTION          6
256
257 /* TPDU length indicator */
258
259 #define LI_NORMAL_DT_CLASS_01            2
260 #define LI_NORMAL_DT_WITH_CHECKSUM       8
261 #define LI_NORMAL_DT_WITHOUT_CHECKSUM    4
262 #define LI_EXTENDED_DT_WITH_CHECKSUM     11
263 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM  7
264 #define LI_NORMAL_EA_WITH_CHECKSUM       8
265 #define LI_NORMAL_EA_WITHOUT_CHECKSUM    4
266 #define LI_EXTENDED_EA_WITH_CHECKSUM     11
267 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM  7
268 #define LI_NORMAL_RJ                     4
269 #define LI_EXTENDED_RJ                   9
270 #define LI_MIN_DR                        6
271 #define LI_MAX_DC                        9
272 #define LI_MAX_AK                        27
273 #define LI_MAX_EA                        11
274 #define LI_MAX_ER                        8
275 /* XXX - can we always decide this based on whether the length
276    indicator is odd or not?  What if the variable part has an odd
277    number of octets? */
278 #define is_LI_NORMAL_AK(p)               ( ( p & 0x01 ) == 0 )
279
280 /* variant part */
281
282 #define VP_ACK_TIME             0x85
283 #define VP_RES_ERROR            0x86
284 #define VP_PRIORITY             0x87
285 #define VP_TRANSIT_DEL          0x88
286 #define VP_THROUGHPUT           0x89
287 #define VP_SEQ_NR               0x8A         /* in AK */
288 #define VP_REASSIGNMENT         0x8B
289 #define VP_FLOW_CNTL            0x8C         /* in AK */
290 #define VP_TPDU_SIZE            0xC0
291 #define VP_SRC_TSAP             0xC1         /* in CR/CC */
292 #define VP_DST_TSAP             0xC2
293 #define VP_CHECKSUM             0xC3
294 #define VP_VERSION_NR           0xC4
295 #define VP_PROTECTION           0xC5
296 #define VP_OPT_SEL              0xC6
297 #define VP_PROTO_CLASS          0xC7
298 #define VP_PREF_MAX_TPDU_SIZE   0xF0
299 #define VP_INACTIVITY_TIMER     0xF2
300
301 static const value_string tp_vpart_type_vals[] = {
302   { VP_ACK_TIME,                "ack time" },
303   { VP_RES_ERROR,               "res error" },
304   { VP_PRIORITY,                "priority" },
305   { VP_TRANSIT_DEL,             "transit delay" },
306   { VP_THROUGHPUT,              "throughput" },
307   { VP_SEQ_NR,                  "seq number" },
308   { VP_REASSIGNMENT,            "reassignment" },
309   { VP_FLOW_CNTL,               "flow control" },
310   { VP_TPDU_SIZE,               "tpdu-size" },
311   { VP_SRC_TSAP,                "src-tsap" },
312   { VP_DST_TSAP,                "dst-tsap" },
313   { VP_CHECKSUM,                "checksum" },
314   { VP_VERSION_NR,              "version" },
315   { VP_PROTECTION,              "protection" },
316   { VP_OPT_SEL,                 "options" },
317   { VP_PROTO_CLASS,             "proto class" },
318   { VP_PREF_MAX_TPDU_SIZE,      "preferred max TPDU size" },
319   { 0,                          NULL }
320 };
321
322 static int hf_cotp_vp_src_tsap = -1; 
323 static int hf_cotp_vp_dst_tsap = -1;
324 static int hf_cotp_vp_src_tsap_bytes = -1; 
325 static int hf_cotp_vp_dst_tsap_bytes = -1;
326
327
328 /* misc */
329
330 #define EXTRACT_SHORT(p)        pntohs(p)
331 #define EXTRACT_LONG(p)         pntohl(p)
332
333 /* global variables */
334
335 /* List of dissectors to call for COTP packets put atop the Inactive
336    Subset of CLNP. */
337 static heur_dissector_list_t cotp_is_heur_subdissector_list;
338 /* List of dissectors to call for COTP packets put atop CLNP */
339 static heur_dissector_list_t cotp_heur_subdissector_list;
340 /* List of dissectors to call for CLNP packets */
341 static heur_dissector_list_t clnp_heur_subdissector_list;
342
343 /*
344  * Reassembly of CLNP.
345  */
346 static GHashTable *clnp_segment_table = NULL;
347 static GHashTable *clnp_reassembled_table = NULL;
348
349 /*
350  * Reassembly of COTP.
351  */
352 static GHashTable *cotp_segment_table = NULL;
353 static GHashTable *cotp_reassembled_table = NULL;
354
355 #define TSAP_DISPLAY_AUTO       0
356 #define TSAP_DISPLAY_STRING     1
357 #define TSAP_DISPLAY_BYTES      2
358
359
360 /* options */
361 static guint tp_nsap_selector = NSEL_TP;
362 static gboolean always_decode_transport = FALSE;
363 static gboolean clnp_reassemble = FALSE;
364 static gboolean cotp_reassemble = FALSE;
365 static gint32   tsap_display = TSAP_DISPLAY_AUTO;
366
367 const enum_val_t tsap_display_options[] = {
368   {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
369   {"string", "As strings", TSAP_DISPLAY_STRING},
370   {"bytes", "As bytes", TSAP_DISPLAY_BYTES},
371   {NULL, NULL, -1}
372 };
373
374
375 /* function definitions */
376
377 #define MAX_TSAP_LEN    32
378 static gboolean is_all_printable(const guchar *stringtocheck, int length)
379 {
380   gboolean allprintable;
381   int i;
382
383   allprintable=TRUE;
384   for (i=0;i<length;i++) {
385     if (!(isascii(stringtocheck[i]) && isprint(stringtocheck[i]))) {
386       allprintable=FALSE;
387       break;
388     }
389   }
390   return allprintable; 
391 } /* is_all_printable */
392
393
394 static gchar *print_tsap(const guchar *tsap, int length)
395 {
396
397   static gchar  str[3][MAX_TSAP_LEN * 2 + 3];   /* TSAP in hex + '0x' + NULL */
398   static gchar *cur;
399   gchar tmp[3];
400   gboolean allprintable;
401
402   if (cur == &str[0][0]) {
403     cur = &str[1][0];
404   } else if (cur == &str[1][0]) {
405     cur = &str[2][0];
406   } else {
407     cur = &str[0][0];
408   }
409
410
411   cur[0] = '\0';
412   if (length <= 0 || length > MAX_TSAP_LEN)
413     sprintf(cur, "<unsupported TSAP length>");
414   else {
415     allprintable = is_all_printable(tsap,length);
416     if (!allprintable)
417       strcat(cur,"0x");
418     while (length != 0) {
419       if (allprintable)
420         sprintf(tmp, "%c", *tsap ++);
421       else
422         sprintf(tmp, "%02x", *tsap ++);
423       strcat(cur, tmp);
424       length --;
425     }
426   }
427   return cur;
428
429 } /* print_tsap */
430
431 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
432                                       int vp_length, int class_option,
433                                       proto_tree *tree)
434 {
435   guint8  code, length;
436   guint8  c1;
437   guint16 s, s1,s2,s3,s4;
438   guint32 t1, t2, t3, t4;
439   guint32 pref_max_tpdu_size;
440
441   while (vp_length != 0) {
442     code = tvb_get_guint8(tvb, offset);
443     proto_tree_add_text(tree, tvb, offset, 1,
444                 "Parameter code:   0x%02x (%s)",
445                             code,
446                             val_to_str(code, tp_vpart_type_vals, "Unknown"));
447     offset += 1;
448     vp_length -= 1;
449
450     if (vp_length == 0)
451       break;
452     length = tvb_get_guint8(tvb, offset);
453     proto_tree_add_text(tree, tvb, offset, 1,
454                 "Parameter length: %u", length);
455     offset += 1;
456     vp_length -= 1;
457
458     switch (code) {
459
460     case VP_ACK_TIME:
461       s = tvb_get_ntohs(tvb, offset);
462       proto_tree_add_text(tree, tvb, offset, length,
463                               "Ack time (ms): %u", s);
464       offset += length;
465       vp_length -= length;
466       break;
467
468     case VP_RES_ERROR:
469       proto_tree_add_text(tree, tvb, offset, 1,
470                 "Residual error rate, target value: 10^%u",
471                 tvb_get_guint8(tvb, offset));
472       offset += 1;
473       length -= 1;
474       vp_length -= 1;
475
476       proto_tree_add_text(tree, tvb, offset, 1,
477                 "Residual error rate, minimum acceptable: 10^%u",
478                 tvb_get_guint8(tvb, offset));
479       offset += 1;
480       length -= 1;
481       vp_length -= 1;
482
483
484       proto_tree_add_text(tree, tvb, offset, 1,
485                 "Residual error rate, TSDU size of interest: %u",
486                 1<<tvb_get_guint8(tvb, offset));
487       offset += 1;
488       length -= 1;
489       vp_length -= 1;
490
491       break;
492
493     case VP_PRIORITY:
494       s = tvb_get_ntohs(tvb, offset);
495       proto_tree_add_text(tree, tvb, offset, length,
496                 "Priority: %u", s);
497       offset += length;
498       vp_length -= length;
499       break;
500
501     case VP_TRANSIT_DEL:
502       s1 = tvb_get_ntohs(tvb, offset);
503       proto_tree_add_text(tree, tvb, offset, 2,
504                 "Transit delay, target value, calling-called: %u ms", s1);
505       offset += 2;
506       length -= 2;
507       vp_length -= 2;
508
509       s2 = tvb_get_ntohs(tvb, offset);
510       proto_tree_add_text(tree, tvb, offset, 2,
511                 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
512       offset += 2;
513       length -= 2;
514       vp_length -= 2;
515
516       s3 = tvb_get_ntohs(tvb, offset);
517       proto_tree_add_text(tree, tvb, offset, 2,
518                 "Transit delay, target value, called-calling: %u ms", s3);
519       offset += 2;
520       length -= 2;
521       vp_length -= 2;
522
523       s4 = tvb_get_ntohs(tvb, offset);
524       proto_tree_add_text(tree, tvb, offset, 2,
525                 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
526       offset += 2;
527       length -= 2;
528       vp_length -= 2;
529       break;
530
531     case VP_THROUGHPUT:
532       t1 = tvb_get_ntoh24(tvb, offset);
533       proto_tree_add_text(tree, tvb, offset, 3,
534                 "Maximum throughput, target value, calling-called:       %u o/s", t1);
535       offset += 3;
536       length -= 3;
537       vp_length -= 3;
538
539       t2 = tvb_get_ntoh24(tvb, offset);
540       proto_tree_add_text(tree, tvb, offset, 3,
541                 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
542       offset += 3;
543       length -= 3;
544       vp_length -= 3;
545
546       t3 = tvb_get_ntoh24(tvb, offset);
547       proto_tree_add_text(tree, tvb, offset, 3,
548                 "Maximum throughput, target value, called-calling:       %u o/s", t3);
549       offset += 3;
550       length -= 3;
551       vp_length -= 3;
552
553       t4 = tvb_get_ntoh24(tvb, offset);
554       proto_tree_add_text(tree, tvb, offset, 3,
555                 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
556       offset += 3;
557       length -= 3;
558       vp_length -= 3;
559
560       if (length != 0) {        /* XXX - should be 0 or 12 */
561         t1 = tvb_get_ntoh24(tvb, offset);
562         proto_tree_add_text(tree, tvb, offset, 3,
563                 "Average throughput, target value, calling-called:       %u o/s", t1);
564         offset += 3;
565         length -= 3;
566         vp_length -= 3;
567
568         t2 = tvb_get_ntoh24(tvb, offset);
569         proto_tree_add_text(tree, tvb, offset, 3,
570                 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
571         offset += 3;
572         length -= 3;
573         vp_length -= 3;
574
575         t3 = tvb_get_ntoh24(tvb, offset);
576         proto_tree_add_text(tree, tvb, offset, 3,
577                 "Average throughput, target value, called-calling:       %u o/s", t3);
578         offset += 3;
579         length -= 3;
580         vp_length -= 3;
581
582         t4 = tvb_get_ntoh24(tvb, offset);
583         proto_tree_add_text(tree, tvb, offset, 3,
584                 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
585         offset += 3;
586         length -= 3;
587         vp_length -= 3;
588       }
589       break;
590
591     case VP_SEQ_NR:
592       proto_tree_add_text(tree, tvb, offset, 2,
593                 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
594       offset += length;
595       vp_length -= length;
596       break;
597
598     case VP_REASSIGNMENT:
599       proto_tree_add_text(tree, tvb, offset, 2,
600                 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
601       offset += length;
602       vp_length -= length;
603       break;
604
605     case VP_FLOW_CNTL:
606       proto_tree_add_text(tree, tvb, offset, 4,
607                 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
608       offset += 4;
609       length -= 4;
610       vp_length -= 4;
611
612       proto_tree_add_text(tree, tvb, offset, 2,
613                 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
614       offset += 2;
615       length -= 2;
616       vp_length -= 2;
617
618       proto_tree_add_text(tree, tvb, offset, 2,
619                 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
620       offset += 2;
621       length -= 2;
622       vp_length -= 2;
623
624       break;
625
626     case VP_TPDU_SIZE:
627       c1 = tvb_get_guint8(tvb, offset) & 0x0F;
628       proto_tree_add_text(tree, tvb, offset, length,
629                 "TPDU size: %u", 1 << c1);
630       offset += length;
631       vp_length -= length;
632       break;
633
634     case VP_SRC_TSAP:
635       /* if our preference is set to STRING or the  
636          TSAP is not printable, add as bytes and hidden as string;
637          otherwise vice-versa */
638       if (tsap_display==TSAP_DISPLAY_STRING ||
639          (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
640         proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length, 
641                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
642         proto_tree_add_item_hidden(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, TRUE);
643       } else {
644         proto_tree_add_string_hidden(tree, hf_cotp_vp_src_tsap, tvb, offset, length, 
645                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
646         proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, TRUE);
647       }
648       offset += length;
649       vp_length -= length;
650       break;
651
652     case VP_DST_TSAP:
653       /* if our preference is set to STRING or the  
654          TSAP is not printable, add as bytes and hidden as string;
655          otherwise vice-versa */      
656       if (tsap_display==TSAP_DISPLAY_STRING ||
657          (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
658         proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length, 
659                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
660         proto_tree_add_item_hidden(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, TRUE);
661       } else {
662         proto_tree_add_string_hidden(tree, hf_cotp_vp_dst_tsap, tvb, offset, length, 
663                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
664         proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, TRUE);
665       }
666       offset += length;
667       vp_length -= length;
668       break;
669
670     case VP_CHECKSUM:
671       proto_tree_add_text(tree, tvb, offset, length,
672                 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
673       offset += length;
674       vp_length -= length;
675       break;
676
677     case VP_VERSION_NR:
678       c1 = tvb_get_guint8(tvb, offset);
679       proto_tree_add_text(tree, tvb, offset, length,
680                 "Version: %u", c1);
681       offset += length;
682       vp_length -= length;
683       break;
684
685     case VP_OPT_SEL:
686       c1 = tvb_get_guint8(tvb, offset) & 0x0F;
687       switch (class_option) {
688
689       case 1:
690         if (c1 & 0x8)
691           proto_tree_add_text(tree, tvb, offset, 1,
692                                   "Use of network expedited data");
693         else
694           proto_tree_add_text(tree, tvb, offset, 1,
695                                   "Non use of network expedited data");
696         if (c1 & 0x4)
697           proto_tree_add_text(tree, tvb, offset, 1,
698                                   "Use of Receipt confirmation");
699         else
700           proto_tree_add_text(tree, tvb, offset, 1,
701                                   "Use of explicit AK variant");
702         break;
703
704       case 4:
705         if (c1 & 0x2)
706           proto_tree_add_text(tree, tvb, offset, 1,
707                                   "Non-use 16 bit checksum in class 4");
708         else
709           proto_tree_add_text(tree, tvb, offset, 1,
710                                   "Use 16 bit checksum ");
711         break;
712       }
713       if (c1 & 0x1)
714         proto_tree_add_text(tree, tvb, offset, 1,
715                                 "Use of transport expedited data transfer");
716       else
717         proto_tree_add_text(tree, tvb, offset, 1,
718                                 "Non-use of transport expedited data transfer");
719       offset += length;
720       vp_length -= length;
721       break;
722
723     case VP_PREF_MAX_TPDU_SIZE:
724       switch (length) {
725
726       case 1:
727         pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
728         break;
729
730       case 2:
731         pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
732         break;
733
734       case 3:
735         pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
736         break;
737
738       case 4:
739         pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
740         break;
741
742       default:
743         proto_tree_add_text(tree, tvb, offset, length,
744                 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
745                 length);
746         return FALSE;
747       }
748       proto_tree_add_text(tree, tvb, offset, length,
749                 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
750       offset += length;
751       vp_length -= length;
752       break;
753
754     case VP_INACTIVITY_TIMER:
755       proto_tree_add_text(tree, tvb, offset, length,
756                 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
757       offset += length;
758       vp_length -= length;
759       break;
760
761     case VP_PROTECTION:           /* user-defined */
762     case VP_PROTO_CLASS:          /* todo */
763     default:                      /* unknown, no decoding */
764       proto_tree_add_text(tree, tvb, offset, length,
765                               "Parameter value: <not shown>");
766       offset += length;
767       vp_length -= length;
768       break;
769     }
770   } /* while */
771
772   return TRUE;
773 }
774
775 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
776                          packet_info *pinfo, proto_tree *tree)
777 {
778   proto_tree *cotp_tree;
779   proto_item *ti;
780   guint16 dst_ref, src_ref;
781   guchar  reason;
782   char *str;
783
784   if (li < LI_MIN_DR)
785     return -1;
786
787   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
788
789   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
790
791   reason  = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
792
793   /* the settings of the TCP srcport and destport are currently disables,
794    * for the following reasons:
795    * a) only used for ISO conversation handling (which currently doesn't work)
796    * b) will prevent "ISO on TCP" (RFC1006) packets from using "follow TCP stream" correctly
797    *
798    * A future conversation handling might be able to handle different kinds of conversations
799    * (TCP, ISO, TCP on TCP, ...), but in that case this has to be fixed in any case.
800    */
801   /*pinfo->srcport = src_ref;*/
802   /*pinfo->destport = dst_ref;*/
803   switch(reason) {
804     case (128+0): str = "Normal Disconnect"; break;
805     case (128+1): str = "Remote transport entity congestion"; break;
806     case (128+2): str = "Connection negotiation failed"; break;
807     case (128+3): str = "Duplicate source reference"; break;
808     case (128+4): str = "Mismatched references"; break;
809     case (128+5): str = "Protocol error"; break;
810     case (128+7): str = "Reference overflow"; break;
811     case (128+8): str = "Connection requestion refused"; break;
812     case (128+10):str = "Header or parameter length invalid"; break;
813     case (0):     str = "Reason not specified"; break;
814     case (1):     str = "Congestion at TSAP"; break;
815     case (2):     str = "Session entity not attached to TSAP"; break;
816     case (3):     str = "Address unknown"; break;
817     default:      return -1;
818       /*NOTREACHED*/
819       break;
820   }
821
822   if (check_col(pinfo->cinfo, COL_INFO))
823     col_append_fstr(pinfo->cinfo, COL_INFO,
824                 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
825                  src_ref, dst_ref);
826
827   if (tree) {
828     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
829     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
830     proto_tree_add_text(cotp_tree, tvb, offset,      1,
831                         "Length indicator: %u", li);
832     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu,
833                                "TPDU code: 0x%x (DR)", tpdu);
834     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
835     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset +  4, 2, src_ref);
836     proto_tree_add_text(cotp_tree, tvb, offset +  6, 1,
837                         "Cause: %s", str);
838   }
839
840   offset += li + 1;
841
842   /* User data */
843   call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
844   offset += tvb_length_remaining(tvb, offset);
845      /* we dissected all of the containing PDU */
846
847   return offset;
848
849 } /* ositp_decode_DR */
850
851 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
852                          packet_info *pinfo, proto_tree *tree,
853                          gboolean uses_inactive_subset,
854                          gboolean *subdissector_found)
855 {
856   proto_tree *cotp_tree = NULL;
857   proto_item *ti;
858   gboolean is_extended;
859   gboolean is_class_234;
860   guint16  dst_ref;
861   guint    tpdu_nr;
862   guint    fragment = 0;
863   guint32  fragment_length = 0;
864   tvbuff_t *next_tvb;
865   tvbuff_t *reassembled_tvb = NULL;
866   fragment_data *fd_head;
867
868   /* VP_CHECKSUM is the only parameter allowed in the variable part.
869      (This means we may misdissect this if the packet is bad and
870      contains other parameters.) */
871   switch (li) {
872
873     case LI_NORMAL_DT_WITH_CHECKSUM      :
874       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
875         return -1;
876       /* FALLTHROUGH */
877
878     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
879       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
880       if ( tpdu_nr & 0x80 )
881         tpdu_nr = tpdu_nr & 0x7F;
882       else
883         fragment = 1;
884       is_extended = FALSE;
885       is_class_234 = TRUE;
886       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
887       break;
888
889     case LI_EXTENDED_DT_WITH_CHECKSUM    :
890       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
891         return -1;
892       /* FALLTHROUGH */
893
894     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
895       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
896       if ( tpdu_nr & 0x80000000 )
897         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
898       else
899         fragment = 1;
900       is_extended = TRUE;
901       is_class_234 = TRUE;
902       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
903       break;
904
905     case LI_NORMAL_DT_CLASS_01           :
906       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
907       if ( tpdu_nr & 0x80 )
908         tpdu_nr = tpdu_nr & 0x7F;
909       else
910         fragment = 1;
911       is_extended = FALSE;
912       is_class_234 = FALSE;
913       dst_ref = 0;
914       break;
915
916     default : /* bad TPDU */
917       return -1;
918       /*NOTREACHED*/
919       break;
920   }
921
922   /* pinfo->destport = dst_ref; */
923   /* pinfo->srcport = 0; */
924   pinfo->fragmented = fragment;
925   if (check_col(pinfo->cinfo, COL_INFO)) {
926     if (is_class_234) {
927       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
928                  tpdu_nr,
929                  dst_ref,
930                  (fragment)? "(fragment)" : "");
931     } else {
932       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) %s",
933                  tpdu_nr,
934                  (fragment)? "(fragment)" : "");
935     }
936   }
937
938   if (tree) {
939     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
940     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
941     proto_tree_add_text(cotp_tree, tvb, offset, 1,
942                         "Length indicator: %u", li);
943   }
944   offset += 1;
945
946   if (tree) {
947     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
948                         "TPDU code: 0x%x (DT)", tpdu);
949   }
950   offset += 1;
951   li -= 1;
952
953   if (is_class_234) {
954     if (tree)
955       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
956     offset += 2;
957     li -= 2;
958   }
959
960   if (is_extended) {
961     if (tree) {
962       proto_tree_add_text(cotp_tree, tvb, offset, 4,
963                             "TPDU number: 0x%08x (%s)",
964                             tpdu_nr,
965                             (fragment)? "fragment":"complete");
966     }
967     offset += 4;
968     li -= 4;
969   } else {
970     if (tree) {
971       proto_tree_add_text(cotp_tree, tvb, offset, 1,
972                             "TPDU number: 0x%02x (%s)",
973                             tpdu_nr,
974                             (fragment)? "fragment":"complete");
975     }
976     offset += 1;
977     li -= 1;
978   }
979
980   if (tree)
981     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
982   offset += li;
983
984   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
985   if (cotp_reassemble) {
986     fragment_length = tvb_length(next_tvb);
987     /*
988      * XXX - these sequence numbers are connection sequence number,
989      * not segment sequence numbers - the first segment of a
990      * segmented packet doesn't have a specific sequence number (e.g., 0
991      * or 1), it has whatever the appropriate sequence number is for
992      * it in the connection.
993      */
994     fd_head = fragment_add_seq_check(next_tvb, 0, pinfo, dst_ref,
995                                      cotp_segment_table, 
996                                      cotp_reassembled_table,
997                                      tpdu_nr, 
998                                      fragment_length, fragment);
999     if (fd_head) {
1000       if (fd_head->next) {
1001         /* This is the last packet */
1002         reassembled_tvb = tvb_new_real_data(fd_head->data,
1003                                             fd_head->len,
1004                                             fd_head->len);
1005         tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
1006         add_new_data_source(pinfo, reassembled_tvb, "Reassembled COTP");
1007         
1008         show_fragment_seq_tree(fd_head,
1009                                &cotp_frag_items,
1010                                cotp_tree,
1011                                pinfo, reassembled_tvb);
1012         pinfo->fragmented = fragment;
1013         next_tvb = reassembled_tvb;
1014       }
1015     }
1016     if (fragment && reassembled_tvb == NULL) {
1017       proto_tree_add_text(cotp_tree, tvb, offset, -1,
1018                           "User data (%u byte%s)", fragment_length,
1019                           plurality(fragment_length, "", "s"));
1020     } 
1021
1022   } 
1023
1024   if (uses_inactive_subset) {
1025     if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
1026                                 pinfo, tree)) {
1027       *subdissector_found = TRUE;
1028     } else {
1029       /* Fill in other Dissectors using inactive subset here */
1030       call_dissector(data_handle,next_tvb, pinfo, tree);
1031     }
1032   } else {
1033     /*
1034      * We dissect payload if one of the following is TRUE: 
1035      *
1036      * - Reassembly option for COTP in preferences is unchecked 
1037      * - Reassembly option is checked and this packet is the last fragment
1038      */
1039     if ( (!cotp_reassemble) ||
1040          ((cotp_reassemble) && (!fragment))) {
1041       if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1042                                   pinfo, tree)) {
1043         *subdissector_found = TRUE;
1044       } else {
1045         call_dissector(data_handle,next_tvb, pinfo, tree);
1046       }
1047     }
1048   }   
1049
1050   offset += tvb_length_remaining(tvb, offset);
1051      /* we dissected all of the containing PDU */
1052
1053   return offset;
1054
1055 } /* ositp_decode_DT */
1056
1057 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1058                          packet_info *pinfo, proto_tree *tree)
1059 {
1060   proto_tree *cotp_tree = NULL;
1061   proto_item *ti;
1062   gboolean is_extended;
1063   guint16  dst_ref;
1064   guint    tpdu_nr;
1065   tvbuff_t *next_tvb;
1066
1067   /* ED TPDUs are never fragmented */
1068
1069   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1070      (This means we may misdissect this if the packet is bad and
1071      contains other parameters.) */
1072   switch (li) {
1073
1074     case LI_NORMAL_DT_WITH_CHECKSUM      :
1075       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1076         return -1;
1077       /* FALLTHROUGH */
1078
1079     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
1080       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1081       if ( tpdu_nr & 0x80 )
1082         tpdu_nr = tpdu_nr & 0x7F;
1083       else
1084         return -1;
1085       is_extended = FALSE;
1086       break;
1087
1088     case LI_EXTENDED_DT_WITH_CHECKSUM    :
1089       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1090         return -1;
1091       /* FALLTHROUGH */
1092
1093     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1094       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1095       if ( tpdu_nr & 0x80000000 )
1096         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1097       else
1098         return -1;
1099       is_extended = TRUE;
1100       break;
1101
1102     default : /* bad TPDU */
1103       return -1;
1104       /*NOTREACHED*/
1105       break;
1106   } /* li */
1107
1108   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1109
1110   /* pinfo->destport = dst_ref; */
1111   /* pinfo->srcport = 0; */
1112   if (check_col(pinfo->cinfo, COL_INFO))
1113     col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1114                  tpdu_nr, dst_ref);
1115
1116   if (tree) {
1117     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1118     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1119     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1120                         "Length indicator: %u", li);
1121   }
1122   offset += 1;
1123
1124   if (tree) {
1125     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1126                         "TPDU code: 0x%x (ED)", tpdu);
1127   }
1128   offset += 1;
1129   li -= 1;
1130
1131   if (tree)
1132     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1133   offset += 2;
1134   li -= 2;
1135
1136   if (is_extended) {
1137     if (tree) {
1138       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1139                             "TPDU number: 0x%02x", tpdu_nr);
1140     }
1141     offset += 4;
1142     li -= 4;
1143   } else {
1144     if (tree) {
1145       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1146                             "TPDU number: 0x%02x", tpdu_nr);
1147     }
1148     offset += 1;
1149     li -= 1;
1150   }
1151
1152   if (tree)
1153     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1154   offset += li;
1155
1156   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1157   call_dissector(data_handle,next_tvb, pinfo, tree);
1158
1159   offset += tvb_length_remaining(tvb, offset);
1160      /* we dissected all of the containing PDU */
1161
1162   return offset;
1163
1164 } /* ositp_decode_ED */
1165
1166 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1167                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1168 {
1169   proto_tree *cotp_tree;
1170   proto_item *ti;
1171   guint16  dst_ref;
1172   guint    tpdu_nr;
1173   gushort  credit = 0;
1174
1175   switch(li) {
1176     case LI_NORMAL_RJ   :
1177       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1178       break;
1179     case LI_EXTENDED_RJ :
1180       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1181       credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1182       break;
1183     default :
1184       return -1;
1185       /*NOTREACHED*/
1186       break;
1187   }
1188
1189   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1190
1191   /* pinfo->destport = dst_ref; */
1192   /* pinfo->srcport = 0; */
1193   if (check_col(pinfo->cinfo, COL_INFO))
1194     col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1195                  tpdu_nr, dst_ref);
1196
1197   if (tree) {
1198     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1199     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1200     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1201                         "Length indicator: %u", li);
1202     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu,
1203                         "TPDU code: 0x%x (RJ)", tpdu);
1204     if (li == LI_NORMAL_RJ)
1205       proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1206                           "Credit: %u", cdt);
1207     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1208     if (li == LI_NORMAL_RJ)
1209       proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1210                           "Your TPDU number: 0x%02x", tpdu_nr);
1211     else {
1212       proto_tree_add_text(cotp_tree, tvb, offset +  4, 4,
1213                           "Your TPDU number: 0x%02x", tpdu_nr);
1214       proto_tree_add_text(cotp_tree, tvb, offset +  8, 2,
1215                           "Credit: 0x%02x", credit);
1216     }
1217   }
1218
1219   offset += li + 1;
1220
1221   return offset;
1222
1223 } /* ositp_decode_RJ */
1224
1225 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1226                          packet_info *pinfo, proto_tree *tree,
1227                          gboolean uses_inactive_subset,
1228                          gboolean *subdissector_found)
1229 {
1230
1231   /* CC & CR decoding in the same function */
1232
1233   proto_tree *cotp_tree = NULL;
1234   proto_item *ti;
1235   guint16 dst_ref, src_ref;
1236   guchar  class_option;
1237   tvbuff_t *next_tvb;
1238
1239   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1240   
1241   class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1242   if (class_option > 4)
1243     return -1;
1244
1245   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1246   /* pinfo->srcport = src_ref; */
1247   /* pinfo->destport = dst_ref; */
1248   if (check_col(pinfo->cinfo, COL_INFO))
1249     col_append_fstr(pinfo->cinfo, COL_INFO,
1250                  "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1251                  (tpdu == CR_TPDU) ? "CR" : "CC",
1252                  src_ref,
1253                  dst_ref);
1254
1255   if (tree) {
1256     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1257     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1258     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1259                         "Length indicator: %u", li);
1260   }
1261   offset += 1;
1262
1263   if (tree) {
1264     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1265                         "TPDU code: 0x%x (%s)", tpdu,
1266                         (tpdu == CR_TPDU) ? "CR" : "CC");
1267   }
1268   offset += 1;
1269   li -= 1;
1270
1271   if (tree)
1272     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1273   offset += 2;
1274   li -= 2;
1275
1276   if (tree)
1277     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1278   offset += 2;
1279   li -= 2;
1280
1281   if (tree) {
1282     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1283                         "Class option: 0x%02x", class_option);
1284   }
1285   offset += 1;
1286   li -= 1;
1287
1288   if (tree)
1289     ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1290   offset += li;
1291
1292   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1293   if (!uses_inactive_subset){
1294     if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1295                                 pinfo, tree)) {
1296       *subdissector_found = TRUE;
1297     } else {
1298       call_dissector(data_handle,next_tvb, pinfo, tree);
1299     }
1300   }
1301   else
1302     call_dissector(data_handle, next_tvb, pinfo, tree);
1303   offset += tvb_length_remaining(tvb, offset);
1304      /* we dissected all of the containing PDU */
1305
1306   return offset;
1307
1308 } /* ositp_decode_CC */
1309
1310 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1311                          packet_info *pinfo, proto_tree *tree)
1312 {
1313   proto_tree *cotp_tree = NULL;
1314   proto_item *ti;
1315   guint16 dst_ref, src_ref;
1316
1317   if (li > LI_MAX_DC)
1318     return -1;
1319
1320   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1321   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1322
1323   /* pinfo->srcport = src_ref; */
1324   /* pinfo->destport = dst_ref; */
1325   if (check_col(pinfo->cinfo, COL_INFO))
1326     col_append_fstr(pinfo->cinfo, COL_INFO,
1327                  "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1328                  src_ref,
1329                  dst_ref);
1330
1331   if (tree) {
1332     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1333     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1334     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1335                         "Length indicator: %u", li);
1336   }
1337   offset += 1;
1338
1339   if (tree) {
1340     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1341                         "TPDU code: 0x%x (DC)", tpdu);
1342   }
1343   offset += 1;
1344   li -= 1;
1345
1346   if (tree)
1347     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1348   offset += 2;
1349   li -= 2;
1350
1351   if (tree)
1352     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1353   offset += 2;
1354   li -= 2;
1355
1356   if (tree)
1357     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1358   offset += li;
1359
1360   return offset;
1361
1362 } /* ositp_decode_DC */
1363
1364 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1365                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1366 {
1367   proto_tree *cotp_tree = NULL;
1368   proto_item *ti;
1369   guint16    dst_ref;
1370   guint      tpdu_nr;
1371   gushort    cdt_in_ak;
1372
1373   if (li > LI_MAX_AK)
1374     return -1;
1375
1376   if (is_LI_NORMAL_AK(li)) {
1377
1378     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1379     tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1380
1381     /* pinfo->srcport = 0; */
1382     /* pinfo->destport = dst_ref; */
1383     if (check_col(pinfo->cinfo, COL_INFO))
1384       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1385                    tpdu_nr, dst_ref);
1386
1387     if (tree) {
1388       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1389       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1390       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1391                           "Length indicator: %u", li);
1392     }
1393     offset += 1;
1394
1395     if (tree) {
1396       proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1397                           "TPDU code: 0x%x (AK)", tpdu);
1398       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1399                           "Credit: %u", cdt);
1400     }
1401     offset += 1;
1402     li -= 1;
1403
1404     if (tree)
1405       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1406     offset += 2;
1407     li -= 2;
1408
1409     if (tree) {
1410       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1411                           "Your TPDU number: 0x%02x", tpdu_nr);
1412     }
1413     offset += 1;
1414     li -= 1;
1415
1416     if (tree)
1417       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1418     offset += li;
1419
1420   } else { /* extended format */
1421
1422     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1423     tpdu_nr   = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1424     cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1425
1426     if (check_col(pinfo->cinfo, COL_INFO))
1427       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1428                    tpdu_nr, dst_ref);
1429
1430     if (tree) {
1431       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1432       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1433       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1434                           "Length indicator: %u", li);
1435     }
1436     offset += 1;
1437
1438     if (tree) {
1439       proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1440                           "TPDU code: 0x%x (AK)", tpdu);
1441     }
1442     offset += 1;
1443     li -= 1;
1444
1445     if (tree)
1446       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1447     offset += 2;
1448     li -= 2;
1449
1450     if (tree) {
1451       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1452                           "Your TPDU number: 0x%08x", tpdu_nr);
1453     }
1454     offset += 4;
1455     li -= 4;
1456
1457     if (tree) {
1458       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1459                           "Credit: 0x%04x", cdt_in_ak);
1460     }
1461     offset += 2;
1462     li -= 2;
1463
1464     if (tree)
1465       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1466     offset += li;
1467
1468   } /* is_LI_NORMAL_AK */
1469
1470   return offset;
1471
1472 } /* ositp_decode_AK */
1473
1474 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1475                          packet_info *pinfo, proto_tree *tree)
1476 {
1477   proto_tree *cotp_tree = NULL;
1478   proto_item *ti;
1479   gboolean is_extended;
1480   guint16  dst_ref;
1481   guint    tpdu_nr;
1482
1483   if (li > LI_MAX_EA)
1484     return -1;
1485
1486   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1487      (This means we may misdissect this if the packet is bad and
1488      contains other parameters.) */
1489   switch (li) {
1490
1491     case LI_NORMAL_EA_WITH_CHECKSUM      :
1492       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1493                 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1494         return -1;
1495       /* FALLTHROUGH */
1496
1497     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1498       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1499       is_extended = FALSE;
1500       break;
1501
1502     case LI_EXTENDED_EA_WITH_CHECKSUM    :
1503       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1504                 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1505         return -1;
1506       /* FALLTHROUGH */
1507
1508     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1509       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1510       is_extended = TRUE;
1511       break;
1512
1513     default : /* bad TPDU */
1514       return -1;
1515       /*NOTREACHED*/
1516       break;
1517   } /* li */
1518
1519   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1520   /* pinfo->srcport = 0; */
1521   /* pinfo->destport = dst_ref; */
1522   if (check_col(pinfo->cinfo, COL_INFO))
1523     col_append_fstr(pinfo->cinfo, COL_INFO,
1524                  "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1525
1526   if (tree) {
1527     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1528     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1529     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1530                         "Length indicator: %u", li);
1531   }
1532   offset += 1;
1533
1534   if (tree) {
1535     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1536                         "TPDU code: 0x%x (EA)", tpdu);
1537   }
1538   offset += 1;
1539   li -= 1;
1540
1541   if (tree)
1542     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1543   offset += 2;
1544   li -= 2;
1545
1546   if (is_extended) {
1547     if (tree) {
1548       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1549                             "Your TPDU number: 0x%08x", tpdu_nr);
1550     }
1551     offset += 4;
1552     li -= 4;
1553   } else {
1554     if (tree) {
1555       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1556                             "Your TPDU number: 0x%02x", tpdu_nr);
1557     }
1558     offset += 1;
1559     li -= 1;
1560   }
1561
1562   if (tree)
1563     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1564   offset += li;
1565
1566   return offset;
1567
1568 } /* ositp_decode_EA */
1569
1570 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1571                          packet_info *pinfo, proto_tree *tree)
1572 {
1573   proto_tree *cotp_tree;
1574   proto_item *ti;
1575   guchar *str;
1576   guint16 dst_ref;
1577
1578   if (li > LI_MAX_ER)
1579     return -1;
1580
1581   switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1582     case 0 :
1583       str = "Reason not specified";
1584       break;
1585     case 1 :
1586       str = "Invalid parameter code";
1587       break;
1588     case 2 :
1589       str = "Invalid TPDU type";
1590       break;
1591     case 3 :
1592       str = "Invalid parameter value";
1593       break;
1594     default:
1595       return -1;
1596       /*NOTREACHED*/
1597       break;
1598   }
1599
1600   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1601   /* pinfo->srcport = 0; */
1602   /* pinfo->destport = dst_ref; */
1603   if (check_col(pinfo->cinfo, COL_INFO))
1604     col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1605
1606   if (tree) {
1607     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1608     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1609     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1610                         "Length indicator: %u", li);
1611     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu,
1612                         "TPDU code: 0x%x (ER)", tpdu);
1613     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1614     proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1615                         "Reject cause: %s", str);
1616   }
1617
1618   offset += li + 1;
1619
1620   return offset;
1621
1622 } /* ositp_decode_ER */
1623
1624 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1625                          packet_info *pinfo, proto_tree *tree)
1626 {
1627   proto_item *ti;
1628   proto_tree *cltp_tree = NULL;
1629   tvbuff_t   *next_tvb;
1630
1631   if (check_col(pinfo->cinfo, COL_INFO))
1632     col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1633
1634   if (tree) {
1635     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1636     cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1637     proto_tree_add_text(cltp_tree, tvb, offset, 1,
1638                         "Length indicator: %u", li);
1639   }
1640   offset += 1;
1641
1642   if (tree) {
1643     proto_tree_add_uint_format(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu, 
1644                         "TPDU code: 0x%x (UD)", tpdu);
1645   }
1646   offset += 1;
1647   li -= 1;
1648
1649   if (tree)
1650     ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1651   offset += li;
1652
1653   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1654   call_dissector(data_handle,next_tvb, pinfo, tree);
1655   offset += tvb_length_remaining(tvb, offset);
1656      /* we dissected all of the containing PDU */
1657
1658   return offset;
1659
1660 } /* ositp_decode_UD */
1661
1662 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1663    otherwise.
1664
1665    There doesn't seem to be any way in which the OSI network layer protocol
1666    distinguishes between COTP and CLTP, but the first two octets of both
1667    protocols' headers mean the same thing - length and PDU type - and the
1668    only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1669    both of them here. */
1670 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1671                   proto_tree *tree, gboolean uses_inactive_subset)
1672 {
1673   int offset = 0;
1674   guint8 li, tpdu, cdt;
1675   gboolean first_tpdu = TRUE;
1676   int new_offset;
1677   gboolean found_ositp = FALSE;
1678   gboolean is_cltp = FALSE;
1679   gboolean subdissector_found = FALSE;
1680
1681   if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1682     return FALSE;       /* COTP has been disabled */
1683   /* XXX - what about CLTP? */
1684
1685   pinfo->current_proto = "COTP";
1686
1687   /* Initialize the COL_INFO field; each of the TPDUs will have its
1688      information appended. */
1689   if (check_col(pinfo->cinfo, COL_INFO))
1690     col_add_str(pinfo->cinfo, COL_INFO, "");
1691
1692   while (tvb_offset_exists(tvb, offset)) {
1693     if (!first_tpdu) {
1694       if (check_col(pinfo->cinfo, COL_INFO))
1695         col_append_str(pinfo->cinfo, COL_INFO, ", ");
1696     }
1697     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1698       if (check_col(pinfo->cinfo, COL_INFO))
1699         col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1700       if (!first_tpdu)
1701         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1702                        pinfo, tree);
1703       return found_ositp;
1704     }
1705
1706     tpdu    = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1707     if (tpdu == UD_TPDU)
1708       pinfo->current_proto = "CLTP";    /* connectionless transport */
1709     cdt     = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1710
1711     switch (tpdu) {
1712       case CC_TPDU :
1713       case CR_TPDU :
1714         new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1715                                      uses_inactive_subset, &subdissector_found);
1716         break;
1717       case DR_TPDU :
1718         new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1719         break;
1720       case DT_TPDU :
1721         new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1722                                    uses_inactive_subset, &subdissector_found);
1723         break;
1724       case ED_TPDU :
1725         new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1726         break;
1727       case RJ_TPDU :
1728         new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1729         break;
1730       case DC_TPDU :
1731         new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1732         break;
1733       case AK_TPDU :
1734         new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1735         break;
1736       case EA_TPDU :
1737         new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1738         break;
1739       case ER_TPDU :
1740         new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1741         break;
1742       case UD_TPDU :
1743         new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1744         is_cltp = TRUE;
1745         break;
1746       default      :
1747         if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1748           col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1749         new_offset = -1;        /* bad PDU type */
1750         break;
1751     }
1752
1753     if (new_offset == -1) { /* incorrect TPDU */
1754       if (!first_tpdu)
1755         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1756                        pinfo, tree);
1757       break;
1758     }
1759
1760     if (first_tpdu) {
1761       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1762          is either COTP or CLTP. */
1763       if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1764         col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1765       found_ositp = TRUE;
1766     }
1767
1768     offset = new_offset;
1769     first_tpdu = FALSE;
1770   }
1771   return found_ositp;
1772 } /* dissect_ositp_internal */
1773
1774 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1775 {
1776   if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1777     call_dissector(data_handle,tvb, pinfo, tree);
1778 }
1779
1780 /*
1781  *  CLNP part / main entry point
1782 */
1783
1784 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1785 {
1786   proto_tree *clnp_tree = NULL;
1787   proto_item *ti;
1788   guint8      cnf_proto_id;
1789   guint8      cnf_hdr_len;
1790   guint8      cnf_vers;
1791   guint8      cnf_ttl;
1792   guint8      cnf_type;
1793   char        flag_string[6+1];
1794   char       *pdu_type_string;
1795   proto_tree *type_tree;
1796   guint16     segment_length;
1797   guint16     du_id = 0;
1798   guint16     segment_offset = 0;
1799   guint16     cnf_cksum;
1800   cksum_status_t cksum_status;
1801   int         offset;
1802   guchar      src_len, dst_len, nsel, opt_len = 0;
1803   const guint8     *dst_addr, *src_addr;
1804   gint        len;
1805   guint       next_length;
1806   proto_tree *discpdu_tree;
1807   gboolean    save_in_error_pkt;
1808   fragment_data *fd_head;
1809   tvbuff_t   *next_tvb;
1810   gboolean    update_col_info = TRUE;
1811   gboolean    save_fragmented;
1812
1813   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1814     col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1815   if (check_col(pinfo->cinfo, COL_INFO))
1816     col_clear(pinfo->cinfo, COL_INFO);
1817
1818   cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1819   if (cnf_proto_id == NLPID_NULL) {
1820     if (check_col(pinfo->cinfo, COL_INFO))
1821       col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1822     if (tree) {
1823       ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1824       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1825       proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1826                                  cnf_proto_id,
1827                                  "Inactive subset");
1828     }
1829     next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1830     dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1831     return;
1832   }
1833
1834   /* return if version not known */
1835   cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1836   if (cnf_vers != ISO8473_V1) {
1837     call_dissector(data_handle,tvb, pinfo, tree);
1838     return;
1839   }
1840
1841   /* fixed part decoding */
1842   cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1843   opt_len = cnf_hdr_len;
1844
1845   if (tree) {
1846     ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1847     clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1848     proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1849                                cnf_proto_id);
1850     proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1851                         cnf_hdr_len);
1852     proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1853                         cnf_vers);
1854     cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1855     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1856                                cnf_ttl,
1857                                "Holding Time : %u (%u.%u secs)",
1858                                cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1859   }
1860
1861   cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1862   pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1863                                 "Unknown (0x%02x)");
1864   flag_string[0] = '\0';
1865   if (cnf_type & CNF_SEG_OK)
1866     strcat(flag_string, "S ");
1867   if (cnf_type & CNF_MORE_SEGS)
1868     strcat(flag_string, "M ");
1869   if (cnf_type & CNF_ERR_OK)
1870     strcat(flag_string, "E ");
1871   if (tree) {
1872     ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1873                                cnf_type,
1874                                "PDU Type     : 0x%02x (%s%s)",
1875                                cnf_type,
1876                                flag_string,
1877                                pdu_type_string);
1878     type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1879     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1880                         decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1881                                       "Segmentation permitted",
1882                                       "Segmentation not permitted"));
1883     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1884                         decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1885                                       "More segments",
1886                                       "Last segment"));
1887     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1888                         decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1889                                       "Report error if PDU discarded",
1890                                       "Don't report error if PDU discarded"));
1891     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1892                         decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1893                                       npdu_type_vals, "%s"));
1894   }
1895
1896   /* If we don't have the full header - i.e., not enough to see the
1897      segmentation part and determine whether this datagram is segmented
1898      or not - set the Info column now; we'll get an exception before
1899      we set it otherwise. */
1900
1901   if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1902     if (check_col(pinfo->cinfo, COL_INFO))
1903       col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1904   }
1905
1906   segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1907   cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1908   cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1909   if (tree) {
1910     proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1911                         segment_length);
1912     switch (cksum_status) {
1913
1914     default:
1915         /*
1916          * No checksum present, or not enough of the header present to
1917          * checksum it.
1918          */
1919         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1920                                P_CLNP_CKSUM, 2,
1921                                cnf_cksum,
1922                                "Checksum     : 0x%04x",
1923                                cnf_cksum);
1924         break;
1925
1926     case CKSUM_OK:
1927         /*
1928          * Checksum is correct.
1929          */
1930         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1931                                P_CLNP_CKSUM, 2,
1932                                cnf_cksum,
1933                                "Checksum     : 0x%04x (correct)",
1934                                cnf_cksum);
1935         break;
1936
1937     case CKSUM_NOT_OK:
1938         /*
1939          * Checksum is not correct.
1940          */
1941         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1942                                P_CLNP_CKSUM, 2,
1943                                cnf_cksum,
1944                                "Checksum     : 0x%04x (incorrect)",
1945                                cnf_cksum);
1946         break;
1947     }
1948     opt_len -= 9; /* Fixed part of Hesder */
1949   } /* tree */
1950
1951   /* address part */
1952
1953   offset = P_CLNP_ADDRESS_PART;
1954   dst_len  = tvb_get_guint8(tvb, offset);
1955   dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1956   nsel     = tvb_get_guint8(tvb, offset + dst_len);
1957   src_len  = tvb_get_guint8(tvb, offset + dst_len + 1);
1958   src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1959
1960   if (tree) {
1961     proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1962                         dst_len);
1963     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1964                                dst_addr,
1965                                " DA : %s",
1966                                print_nsap_net(dst_addr, dst_len));
1967     proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1968                         offset + 1 + dst_len, 1, src_len);
1969     proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1970                                offset + dst_len + 2, src_len,
1971                                src_addr,
1972                                " SA : %s",
1973                                print_nsap_net(src_addr, src_len));
1974
1975     opt_len -= dst_len + src_len +2;
1976   }
1977
1978   SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1979   SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1980   SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1981   SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1982
1983   /* Segmentation Part */
1984
1985   offset += dst_len + src_len + 2;
1986
1987   if (cnf_type & CNF_SEG_OK) {
1988     struct clnp_segment seg;                    /* XXX - not used */
1989     tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg));       /* XXX - not used */
1990
1991     segment_offset = tvb_get_ntohs(tvb, offset + 2);
1992     du_id = tvb_get_ntohs(tvb, offset);
1993     if (tree) {
1994       proto_tree_add_text(clnp_tree, tvb, offset, 2,
1995                         "Data unit identifier: %06u",
1996                         du_id);
1997       proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1998                         "Segment offset      : %6u",
1999                         segment_offset);
2000       proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
2001                         "Total length        : %6u",
2002                         tvb_get_ntohs(tvb, offset + 4));
2003     }
2004
2005     offset  += 6;
2006     opt_len -= 6;
2007   }
2008
2009   if (tree) {
2010     /* To do : decode options  */
2011 /*
2012     proto_tree_add_text(clnp_tree, tvb, offset,
2013                         cnf_hdr_len - offset,
2014                         "Options/Data: <not shown>");
2015 */
2016 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
2017
2018     dissect_osi_options( opt_len,
2019                          tvb, offset, clnp_tree );
2020   }
2021
2022   /* Length of CLNP datagram plus headers above it. */
2023   len = segment_length;
2024
2025   offset = cnf_hdr_len;
2026
2027   /* If clnp_reassemble is on, this is a segment, we have all the
2028    * data in the segment, and the checksum is valid, then just add the
2029    * segment to the hashtable.
2030    */
2031   save_fragmented = pinfo->fragmented;
2032   if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
2033         ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
2034         tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
2035         cksum_status != CKSUM_NOT_OK) {
2036     fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table,
2037                            clnp_reassembled_table, segment_offset,
2038                            segment_length - cnf_hdr_len,
2039                            cnf_type & CNF_MORE_SEGS);
2040
2041     next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
2042         fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
2043   } else {
2044     /* If this is the first segment, dissect its contents, otherwise
2045        just show it as a segment.
2046
2047        XXX - if we eventually don't save the reassembled contents of all
2048        segmented datagrams, we may want to always reassemble. */
2049     if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
2050       /* Not the first segment - don't dissect it. */
2051       next_tvb = NULL;
2052     } else {
2053       /* First segment, or not segmented.  Dissect what we have here. */
2054
2055       /* Get a tvbuff for the payload. */
2056       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
2057
2058       /*
2059        * If this is the first segment, but not the only segment,
2060        * tell the next protocol that.
2061        */
2062       if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
2063         pinfo->fragmented = TRUE;
2064       else
2065         pinfo->fragmented = FALSE;
2066     }
2067   }
2068
2069   if (next_tvb == NULL) {
2070     /* Just show this as a segment. */
2071     if (check_col(pinfo->cinfo, COL_INFO))
2072       col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
2073                 pdu_type_string, flag_string, segment_offset);
2074
2075     /* As we haven't reassembled anything, we haven't changed "pi", so
2076        we don't have to restore it. */
2077     call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
2078                    tree);
2079     pinfo->fragmented = save_fragmented;
2080     return;
2081   }
2082
2083   if (tvb_offset_exists(tvb, offset)) {
2084     switch (cnf_type & CNF_TYPE) {
2085
2086     case DT_NPDU:
2087     case MD_NPDU:
2088       /* Continue with COTP if any data.
2089          XXX - if this isn't the first Derived PDU of a segmented Initial
2090          PDU, skip that? */
2091
2092       if (nsel == (char)tp_nsap_selector || always_decode_transport) {
2093         if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
2094           pinfo->fragmented = save_fragmented;
2095           return;       /* yes, it appears to be COTP or CLTP */
2096         }
2097       }
2098       if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
2099                                   pinfo, tree)) {
2100           pinfo->fragmented = save_fragmented;
2101           return;       /* yes, it appears to be COTP or CLTP */
2102       }
2103         
2104       break;
2105
2106     case ER_NPDU:
2107       /* The payload is the header and "none, some, or all of the data
2108          part of the discarded PDU", i.e. it's like an ICMP error;
2109          dissect it as a CLNP PDU. */
2110       if (check_col(pinfo->cinfo, COL_INFO))
2111         col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2112       if (tree) {
2113         next_length = tvb_length_remaining(tvb, offset);
2114         if (next_length != 0) {
2115           /* We have payload; dissect it. */
2116           ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2117             "Discarded PDU");
2118           discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2119
2120           /* Save the current value of the "we're inside an error packet"
2121              flag, and set that flag; subdissectors may treat packets
2122              that are the payload of error packets differently from
2123              "real" packets. */
2124           save_in_error_pkt = pinfo->in_error_pkt;
2125           pinfo->in_error_pkt = TRUE;
2126
2127           call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
2128
2129           /* Restore the "we're inside an error packet" flag. */
2130           pinfo->in_error_pkt = save_in_error_pkt;
2131         }
2132       }
2133       pinfo->fragmented = save_fragmented;
2134       return;   /* we're done with this PDU */
2135
2136     case ERQ_NPDU:
2137     case ERP_NPDU:
2138       /* XXX - dissect this */
2139       break;
2140     }
2141   }
2142   if (check_col(pinfo->cinfo, COL_INFO))
2143     col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2144   call_dissector(data_handle,next_tvb, pinfo, tree);
2145   pinfo->fragmented = save_fragmented;
2146 } /* dissect_clnp */
2147
2148 static void
2149 clnp_reassemble_init(void)
2150 {
2151   fragment_table_init(&clnp_segment_table);
2152   reassembled_table_init(&clnp_reassembled_table);
2153 }
2154
2155 static void
2156 cotp_reassemble_init(void)
2157 {
2158   fragment_table_init(&cotp_segment_table);
2159   reassembled_table_init(&cotp_reassembled_table);
2160 }
2161
2162 void proto_register_clnp(void)
2163 {
2164   static hf_register_info hf[] = {
2165     { &hf_clnp_id,
2166       { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2167         VALS(nlpid_vals), 0x0, "", HFILL }},
2168
2169     { &hf_clnp_length,
2170       { "HDR Length   ", "clnp.len",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2171
2172     { &hf_clnp_version,
2173       { "Version      ", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2174
2175     { &hf_clnp_ttl,
2176       { "Holding Time ", "clnp.ttl",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2177
2178     { &hf_clnp_type,
2179       { "PDU Type     ", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2180
2181     { &hf_clnp_pdu_length,
2182       { "PDU length   ", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2183
2184     { &hf_clnp_checksum,
2185       { "Checksum     ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2186
2187     { &hf_clnp_dest_length,
2188       { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2189
2190     { &hf_clnp_dest,
2191       { " DA ", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2192
2193     { &hf_clnp_src_length,
2194       { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2195
2196     { &hf_clnp_src,
2197       { " SA ", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2198
2199     { &hf_clnp_segment_overlap,
2200       { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2201         "Segment overlaps with other segments", HFILL }},
2202
2203     { &hf_clnp_segment_overlap_conflict,
2204       { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2205         "Overlapping segments contained conflicting data", HFILL }},
2206
2207     { &hf_clnp_segment_multiple_tails,
2208       { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2209         "Several tails were found when reassembling the packet", HFILL }},
2210
2211     { &hf_clnp_segment_too_long_segment,
2212       { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2213         "Segment contained data past end of packet", HFILL }},
2214
2215     { &hf_clnp_segment_error,
2216       { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2217         "Reassembly error due to illegal segments", HFILL }},
2218
2219     { &hf_clnp_segment,
2220       { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2221         "CLNP Segment", HFILL }},
2222
2223     { &hf_clnp_segments,
2224       { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2225         "CLNP Segments", HFILL }},
2226
2227     { &hf_clnp_reassembled_in,
2228       { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2229         "This CLNP packet is reassembled in this frame", HFILL }}
2230   };
2231   static gint *ett[] = {
2232     &ett_clnp,
2233     &ett_clnp_type,
2234     &ett_clnp_segments,
2235     &ett_clnp_segment,
2236     &ett_clnp_disc_pdu,
2237   };
2238
2239   module_t *clnp_module;
2240
2241   proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2242   proto_register_field_array(proto_clnp, hf, array_length(hf));
2243   proto_register_subtree_array(ett, array_length(ett));
2244   register_dissector("clnp", dissect_clnp, proto_clnp);
2245   register_heur_dissector_list("clnp", &clnp_heur_subdissector_list);  
2246   register_init_routine(clnp_reassemble_init);
2247   register_init_routine(cotp_reassemble_init);
2248
2249   clnp_module = prefs_register_protocol(proto_clnp, NULL);
2250   prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2251         "NSAP selector for Transport Protocol (last byte in hex)",
2252         "NSAP selector for Transport Protocol (last byte in hex)",
2253         16, &tp_nsap_selector);
2254   prefs_register_bool_preference(clnp_module, "always_decode_transport",
2255         "Always try to decode NSDU as transport PDUs",
2256         "Always try to decode NSDU as transport PDUs",
2257         &always_decode_transport);
2258   prefs_register_bool_preference(clnp_module, "reassemble",
2259         "Reassemble segmented CLNP datagrams",
2260         "Whether segmented CLNP datagrams should be reassembled",
2261         &clnp_reassemble);
2262 }
2263
2264 void
2265 proto_reg_handoff_clnp(void)
2266 {
2267   data_handle = find_dissector("data");
2268
2269   clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2270   dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2271   dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2272   dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2273 }
2274
2275 void proto_register_cotp(void)
2276 {
2277   static hf_register_info hf[] = {
2278     { &hf_cotp_srcref,
2279       { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
2280         "Source address reference", HFILL}},
2281     { &hf_cotp_destref,
2282       { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
2283         "Destination address reference", HFILL}}, 
2284     { &hf_cotp_type,
2285       { "COTP PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2286         "COTP PDU Type", HFILL}},
2287     { &hf_cotp_segment_overlap,
2288       { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2289         "Segment overlaps with other segments", HFILL }},
2290     { &hf_cotp_segment_overlap_conflict,
2291       { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2292         "Overlapping segments contained conflicting data", HFILL }},
2293     { &hf_cotp_segment_multiple_tails,
2294       { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2295         "Several tails were found when reassembling the packet", HFILL }},
2296     { &hf_cotp_segment_too_long_segment,
2297       { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2298         "Segment contained data past end of packet", HFILL }},
2299     { &hf_cotp_segment_error,
2300       { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2301         "Reassembly error due to illegal segments", HFILL }},
2302     { &hf_cotp_segment,
2303       { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2304         "COTP Segment", HFILL }},
2305     { &hf_cotp_segments,
2306       { "COTP Segments", "cotp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2307         "COTP Segments", HFILL }},
2308     { &hf_cotp_reassembled_in,
2309       { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2310         "This COTP packet is reassembled in this frame", HFILL }},
2311 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
2312    identifiers of unspecified type and length.
2313    Some implementations of COTP use printable strings, others use raw bytes.
2314    We always add both representations to the tree; one will always be hidden
2315    depending on the tsap display preference */
2316     { &hf_cotp_vp_src_tsap,
2317       { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2318         "Calling TSAP", HFILL }},
2319     { &hf_cotp_vp_src_tsap_bytes,
2320       { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2321         "Calling TSAP (bytes representation)", HFILL }},
2322     { &hf_cotp_vp_dst_tsap,
2323       { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2324         "Called TSAP", HFILL }},
2325     { &hf_cotp_vp_dst_tsap_bytes,
2326       { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2327         "Called TSAP (bytes representation)", HFILL }},
2328
2329   };
2330   static gint *ett[] = {
2331         &ett_cotp,
2332         &ett_cotp_segment,
2333         &ett_cotp_segments,
2334   };
2335
2336   module_t *cotp_module;
2337
2338   proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2339   proto_register_field_array(proto_cotp, hf, array_length(hf));
2340   proto_register_subtree_array(ett, array_length(ett));
2341   cotp_module = prefs_register_protocol(proto_cotp, NULL);
2342
2343   prefs_register_bool_preference(cotp_module, "reassemble",
2344          "Reassemble segmented COTP datagrams",
2345          "Whether segmented COTP datagrams should be reassembled",
2346         &cotp_reassemble);
2347
2348   prefs_register_enum_preference(cotp_module, "tsap_display",
2349          "Display TSAPs as strings or bytes",
2350          "How TSAPs should be displayed",
2351         &tsap_display,
2352         tsap_display_options,
2353         FALSE);
2354
2355   /* subdissector code in inactive subset */
2356   register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2357
2358   /* other COTP/ISO 8473 subdissectors */
2359   register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2360
2361   /* XXX - what about CLTP and proto_cltp? */
2362   register_dissector("ositp", dissect_ositp, proto_cotp);
2363 }
2364
2365 void
2366 proto_reg_handoff_cotp(void)
2367 {
2368   dissector_handle_t ositp_handle;
2369
2370   ositp_handle = find_dissector("ositp");
2371   dissector_add("ip.proto", IP_PROTO_TP, ositp_handle);
2372 }
2373
2374 void proto_register_cltp(void)
2375 {
2376   static hf_register_info hf[] = {
2377     { &hf_cltp_type,
2378       { "CLTP PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
2379         "CLTP PDU Type", HFILL}},
2380   };
2381   static gint *ett[] = {
2382         &ett_cltp,
2383   };
2384
2385   proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2386   proto_register_field_array(proto_cltp, hf, array_length(hf));
2387   proto_register_subtree_array(ett, array_length(ett));
2388 }