Be kind and say "Please note" instead of simply "Note" when something went wrong...
[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.86 2004/06/20 01:05:07 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      * For now, we assume segments arrive in order, and just supply
995      * the negation of the EOT flag as the "more flags" argument.
996      * We should probably handle out-of-order packets separately,
997      * so that we can deliver them in order even when *not*
998      * reassembling.
999      *
1000      * Note also that TP0 has no sequence number, and relies on
1001      * the protocol atop which it runs to guarantee in-order delivery.
1002      */
1003     fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
1004                                      cotp_segment_table,
1005                                      cotp_reassembled_table,
1006                                      fragment_length, fragment);
1007     if (fd_head) {
1008       if (fd_head->next) {
1009         /* This is the last packet */
1010         reassembled_tvb = tvb_new_real_data(fd_head->data,
1011                                             fd_head->len,
1012                                             fd_head->len);
1013         tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
1014         add_new_data_source(pinfo, reassembled_tvb, "Reassembled COTP");
1015         
1016         show_fragment_seq_tree(fd_head,
1017                                &cotp_frag_items,
1018                                cotp_tree,
1019                                pinfo, reassembled_tvb);
1020         pinfo->fragmented = fragment;
1021         next_tvb = reassembled_tvb;
1022       }
1023     }
1024     if (fragment && reassembled_tvb == NULL) {
1025       proto_tree_add_text(cotp_tree, tvb, offset, -1,
1026                           "User data (%u byte%s)", fragment_length,
1027                           plurality(fragment_length, "", "s"));
1028     } 
1029
1030   } 
1031
1032   if (uses_inactive_subset) {
1033     if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
1034                                 pinfo, tree)) {
1035       *subdissector_found = TRUE;
1036     } else {
1037       /* Fill in other Dissectors using inactive subset here */
1038       call_dissector(data_handle,next_tvb, pinfo, tree);
1039     }
1040   } else {
1041     /*
1042      * We dissect payload if one of the following is TRUE: 
1043      *
1044      * - Reassembly option for COTP in preferences is unchecked 
1045      * - Reassembly option is checked and this packet is the last fragment
1046      */
1047     if ( (!cotp_reassemble) ||
1048          ((cotp_reassemble) && (!fragment))) {
1049       if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1050                                   pinfo, tree)) {
1051         *subdissector_found = TRUE;
1052       } else {
1053         call_dissector(data_handle,next_tvb, pinfo, tree);
1054       }
1055     }
1056   }   
1057
1058   offset += tvb_length_remaining(tvb, offset);
1059      /* we dissected all of the containing PDU */
1060
1061   return offset;
1062
1063 } /* ositp_decode_DT */
1064
1065 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1066                          packet_info *pinfo, proto_tree *tree)
1067 {
1068   proto_tree *cotp_tree = NULL;
1069   proto_item *ti;
1070   gboolean is_extended;
1071   guint16  dst_ref;
1072   guint    tpdu_nr;
1073   tvbuff_t *next_tvb;
1074
1075   /* ED TPDUs are never fragmented */
1076
1077   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1078      (This means we may misdissect this if the packet is bad and
1079      contains other parameters.) */
1080   switch (li) {
1081
1082     case LI_NORMAL_DT_WITH_CHECKSUM      :
1083       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1084         return -1;
1085       /* FALLTHROUGH */
1086
1087     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
1088       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1089       if ( tpdu_nr & 0x80 )
1090         tpdu_nr = tpdu_nr & 0x7F;
1091       else
1092         return -1;
1093       is_extended = FALSE;
1094       break;
1095
1096     case LI_EXTENDED_DT_WITH_CHECKSUM    :
1097       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1098         return -1;
1099       /* FALLTHROUGH */
1100
1101     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1102       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1103       if ( tpdu_nr & 0x80000000 )
1104         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1105       else
1106         return -1;
1107       is_extended = TRUE;
1108       break;
1109
1110     default : /* bad TPDU */
1111       return -1;
1112       /*NOTREACHED*/
1113       break;
1114   } /* li */
1115
1116   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1117
1118   /* pinfo->destport = dst_ref; */
1119   /* pinfo->srcport = 0; */
1120   if (check_col(pinfo->cinfo, COL_INFO))
1121     col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1122                  tpdu_nr, dst_ref);
1123
1124   if (tree) {
1125     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1126     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1127     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1128                         "Length indicator: %u", li);
1129   }
1130   offset += 1;
1131
1132   if (tree) {
1133     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1134                         "TPDU code: 0x%x (ED)", tpdu);
1135   }
1136   offset += 1;
1137   li -= 1;
1138
1139   if (tree)
1140     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1141   offset += 2;
1142   li -= 2;
1143
1144   if (is_extended) {
1145     if (tree) {
1146       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1147                             "TPDU number: 0x%02x", tpdu_nr);
1148     }
1149     offset += 4;
1150     li -= 4;
1151   } else {
1152     if (tree) {
1153       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1154                             "TPDU number: 0x%02x", tpdu_nr);
1155     }
1156     offset += 1;
1157     li -= 1;
1158   }
1159
1160   if (tree)
1161     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1162   offset += li;
1163
1164   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1165   call_dissector(data_handle,next_tvb, pinfo, tree);
1166
1167   offset += tvb_length_remaining(tvb, offset);
1168      /* we dissected all of the containing PDU */
1169
1170   return offset;
1171
1172 } /* ositp_decode_ED */
1173
1174 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1175                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1176 {
1177   proto_tree *cotp_tree;
1178   proto_item *ti;
1179   guint16  dst_ref;
1180   guint    tpdu_nr;
1181   gushort  credit = 0;
1182
1183   switch(li) {
1184     case LI_NORMAL_RJ   :
1185       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1186       break;
1187     case LI_EXTENDED_RJ :
1188       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1189       credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1190       break;
1191     default :
1192       return -1;
1193       /*NOTREACHED*/
1194       break;
1195   }
1196
1197   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1198
1199   /* pinfo->destport = dst_ref; */
1200   /* pinfo->srcport = 0; */
1201   if (check_col(pinfo->cinfo, COL_INFO))
1202     col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1203                  tpdu_nr, dst_ref);
1204
1205   if (tree) {
1206     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1207     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1208     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1209                         "Length indicator: %u", li);
1210     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu,
1211                         "TPDU code: 0x%x (RJ)", tpdu);
1212     if (li == LI_NORMAL_RJ)
1213       proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1214                           "Credit: %u", cdt);
1215     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1216     if (li == LI_NORMAL_RJ)
1217       proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1218                           "Your TPDU number: 0x%02x", tpdu_nr);
1219     else {
1220       proto_tree_add_text(cotp_tree, tvb, offset +  4, 4,
1221                           "Your TPDU number: 0x%02x", tpdu_nr);
1222       proto_tree_add_text(cotp_tree, tvb, offset +  8, 2,
1223                           "Credit: 0x%02x", credit);
1224     }
1225   }
1226
1227   offset += li + 1;
1228
1229   return offset;
1230
1231 } /* ositp_decode_RJ */
1232
1233 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1234                          packet_info *pinfo, proto_tree *tree,
1235                          gboolean uses_inactive_subset,
1236                          gboolean *subdissector_found)
1237 {
1238
1239   /* CC & CR decoding in the same function */
1240
1241   proto_tree *cotp_tree = NULL;
1242   proto_item *ti;
1243   guint16 dst_ref, src_ref;
1244   guchar  class_option;
1245   tvbuff_t *next_tvb;
1246
1247   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1248   
1249   class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1250   if (class_option > 4)
1251     return -1;
1252
1253   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1254   /* pinfo->srcport = src_ref; */
1255   /* pinfo->destport = dst_ref; */
1256   if (check_col(pinfo->cinfo, COL_INFO))
1257     col_append_fstr(pinfo->cinfo, COL_INFO,
1258                  "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1259                  (tpdu == CR_TPDU) ? "CR" : "CC",
1260                  src_ref,
1261                  dst_ref);
1262
1263   if (tree) {
1264     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1265     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1266     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1267                         "Length indicator: %u", li);
1268   }
1269   offset += 1;
1270
1271   if (tree) {
1272     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1273                         "TPDU code: 0x%x (%s)", tpdu,
1274                         (tpdu == CR_TPDU) ? "CR" : "CC");
1275   }
1276   offset += 1;
1277   li -= 1;
1278
1279   if (tree)
1280     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1281   offset += 2;
1282   li -= 2;
1283
1284   if (tree)
1285     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1286   offset += 2;
1287   li -= 2;
1288
1289   if (tree) {
1290     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1291                         "Class option: 0x%02x", class_option);
1292   }
1293   offset += 1;
1294   li -= 1;
1295
1296   if (tree)
1297     ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1298   offset += li;
1299
1300   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1301   if (!uses_inactive_subset){
1302     if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1303                                 pinfo, tree)) {
1304       *subdissector_found = TRUE;
1305     } else {
1306       call_dissector(data_handle,next_tvb, pinfo, tree);
1307     }
1308   }
1309   else
1310     call_dissector(data_handle, next_tvb, pinfo, tree);
1311   offset += tvb_length_remaining(tvb, offset);
1312      /* we dissected all of the containing PDU */
1313
1314   return offset;
1315
1316 } /* ositp_decode_CC */
1317
1318 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1319                          packet_info *pinfo, proto_tree *tree)
1320 {
1321   proto_tree *cotp_tree = NULL;
1322   proto_item *ti;
1323   guint16 dst_ref, src_ref;
1324
1325   if (li > LI_MAX_DC)
1326     return -1;
1327
1328   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1329   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1330
1331   /* pinfo->srcport = src_ref; */
1332   /* pinfo->destport = dst_ref; */
1333   if (check_col(pinfo->cinfo, COL_INFO))
1334     col_append_fstr(pinfo->cinfo, COL_INFO,
1335                  "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1336                  src_ref,
1337                  dst_ref);
1338
1339   if (tree) {
1340     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1341     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1342     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1343                         "Length indicator: %u", li);
1344   }
1345   offset += 1;
1346
1347   if (tree) {
1348     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1349                         "TPDU code: 0x%x (DC)", tpdu);
1350   }
1351   offset += 1;
1352   li -= 1;
1353
1354   if (tree)
1355     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1356   offset += 2;
1357   li -= 2;
1358
1359   if (tree)
1360     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1361   offset += 2;
1362   li -= 2;
1363
1364   if (tree)
1365     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1366   offset += li;
1367
1368   return offset;
1369
1370 } /* ositp_decode_DC */
1371
1372 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1373                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1374 {
1375   proto_tree *cotp_tree = NULL;
1376   proto_item *ti;
1377   guint16    dst_ref;
1378   guint      tpdu_nr;
1379   gushort    cdt_in_ak;
1380
1381   if (li > LI_MAX_AK)
1382     return -1;
1383
1384   if (is_LI_NORMAL_AK(li)) {
1385
1386     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1387     tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1388
1389     /* pinfo->srcport = 0; */
1390     /* pinfo->destport = dst_ref; */
1391     if (check_col(pinfo->cinfo, COL_INFO))
1392       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1393                    tpdu_nr, dst_ref);
1394
1395     if (tree) {
1396       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1397       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1398       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1399                           "Length indicator: %u", li);
1400     }
1401     offset += 1;
1402
1403     if (tree) {
1404       proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1405                           "TPDU code: 0x%x (AK)", tpdu);
1406       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1407                           "Credit: %u", cdt);
1408     }
1409     offset += 1;
1410     li -= 1;
1411
1412     if (tree)
1413       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1414     offset += 2;
1415     li -= 2;
1416
1417     if (tree) {
1418       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1419                           "Your TPDU number: 0x%02x", tpdu_nr);
1420     }
1421     offset += 1;
1422     li -= 1;
1423
1424     if (tree)
1425       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1426     offset += li;
1427
1428   } else { /* extended format */
1429
1430     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1431     tpdu_nr   = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1432     cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1433
1434     if (check_col(pinfo->cinfo, COL_INFO))
1435       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1436                    tpdu_nr, dst_ref);
1437
1438     if (tree) {
1439       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1440       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1441       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1442                           "Length indicator: %u", li);
1443     }
1444     offset += 1;
1445
1446     if (tree) {
1447       proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu, 
1448                           "TPDU code: 0x%x (AK)", tpdu);
1449     }
1450     offset += 1;
1451     li -= 1;
1452
1453     if (tree)
1454       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1455     offset += 2;
1456     li -= 2;
1457
1458     if (tree) {
1459       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1460                           "Your TPDU number: 0x%08x", tpdu_nr);
1461     }
1462     offset += 4;
1463     li -= 4;
1464
1465     if (tree) {
1466       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1467                           "Credit: 0x%04x", cdt_in_ak);
1468     }
1469     offset += 2;
1470     li -= 2;
1471
1472     if (tree)
1473       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1474     offset += li;
1475
1476   } /* is_LI_NORMAL_AK */
1477
1478   return offset;
1479
1480 } /* ositp_decode_AK */
1481
1482 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1483                          packet_info *pinfo, proto_tree *tree)
1484 {
1485   proto_tree *cotp_tree = NULL;
1486   proto_item *ti;
1487   gboolean is_extended;
1488   guint16  dst_ref;
1489   guint    tpdu_nr;
1490
1491   if (li > LI_MAX_EA)
1492     return -1;
1493
1494   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1495      (This means we may misdissect this if the packet is bad and
1496      contains other parameters.) */
1497   switch (li) {
1498
1499     case LI_NORMAL_EA_WITH_CHECKSUM      :
1500       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1501                 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1502         return -1;
1503       /* FALLTHROUGH */
1504
1505     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1506       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1507       is_extended = FALSE;
1508       break;
1509
1510     case LI_EXTENDED_EA_WITH_CHECKSUM    :
1511       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1512                 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1513         return -1;
1514       /* FALLTHROUGH */
1515
1516     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1517       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1518       is_extended = TRUE;
1519       break;
1520
1521     default : /* bad TPDU */
1522       return -1;
1523       /*NOTREACHED*/
1524       break;
1525   } /* li */
1526
1527   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1528   /* pinfo->srcport = 0; */
1529   /* pinfo->destport = dst_ref; */
1530   if (check_col(pinfo->cinfo, COL_INFO))
1531     col_append_fstr(pinfo->cinfo, COL_INFO,
1532                  "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1533
1534   if (tree) {
1535     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1536     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1537     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1538                         "Length indicator: %u", li);
1539   }
1540   offset += 1;
1541
1542   if (tree) {
1543     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1544                         "TPDU code: 0x%x (EA)", tpdu);
1545   }
1546   offset += 1;
1547   li -= 1;
1548
1549   if (tree)
1550     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1551   offset += 2;
1552   li -= 2;
1553
1554   if (is_extended) {
1555     if (tree) {
1556       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1557                             "Your TPDU number: 0x%08x", tpdu_nr);
1558     }
1559     offset += 4;
1560     li -= 4;
1561   } else {
1562     if (tree) {
1563       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1564                             "Your TPDU number: 0x%02x", tpdu_nr);
1565     }
1566     offset += 1;
1567     li -= 1;
1568   }
1569
1570   if (tree)
1571     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1572   offset += li;
1573
1574   return offset;
1575
1576 } /* ositp_decode_EA */
1577
1578 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1579                          packet_info *pinfo, proto_tree *tree)
1580 {
1581   proto_tree *cotp_tree;
1582   proto_item *ti;
1583   guchar *str;
1584   guint16 dst_ref;
1585
1586   if (li > LI_MAX_ER)
1587     return -1;
1588
1589   switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1590     case 0 :
1591       str = "Reason not specified";
1592       break;
1593     case 1 :
1594       str = "Invalid parameter code";
1595       break;
1596     case 2 :
1597       str = "Invalid TPDU type";
1598       break;
1599     case 3 :
1600       str = "Invalid parameter value";
1601       break;
1602     default:
1603       return -1;
1604       /*NOTREACHED*/
1605       break;
1606   }
1607
1608   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1609   /* pinfo->srcport = 0; */
1610   /* pinfo->destport = dst_ref; */
1611   if (check_col(pinfo->cinfo, COL_INFO))
1612     col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1613
1614   if (tree) {
1615     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1616     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1617     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1618                         "Length indicator: %u", li);
1619     proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu,
1620                         "TPDU code: 0x%x (ER)", tpdu);
1621     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1622     proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1623                         "Reject cause: %s", str);
1624   }
1625
1626   offset += li + 1;
1627
1628   return offset;
1629
1630 } /* ositp_decode_ER */
1631
1632 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1633                          packet_info *pinfo, proto_tree *tree)
1634 {
1635   proto_item *ti;
1636   proto_tree *cltp_tree = NULL;
1637   tvbuff_t   *next_tvb;
1638
1639   if (check_col(pinfo->cinfo, COL_INFO))
1640     col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1641
1642   if (tree) {
1643     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1644     cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1645     proto_tree_add_text(cltp_tree, tvb, offset, 1,
1646                         "Length indicator: %u", li);
1647   }
1648   offset += 1;
1649
1650   if (tree) {
1651     proto_tree_add_uint_format(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu, 
1652                         "TPDU code: 0x%x (UD)", tpdu);
1653   }
1654   offset += 1;
1655   li -= 1;
1656
1657   if (tree)
1658     ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1659   offset += li;
1660
1661   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1662   call_dissector(data_handle,next_tvb, pinfo, tree);
1663   offset += tvb_length_remaining(tvb, offset);
1664      /* we dissected all of the containing PDU */
1665
1666   return offset;
1667
1668 } /* ositp_decode_UD */
1669
1670 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1671    otherwise.
1672
1673    There doesn't seem to be any way in which the OSI network layer protocol
1674    distinguishes between COTP and CLTP, but the first two octets of both
1675    protocols' headers mean the same thing - length and PDU type - and the
1676    only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1677    both of them here. */
1678 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1679                   proto_tree *tree, gboolean uses_inactive_subset)
1680 {
1681   int offset = 0;
1682   guint8 li, tpdu, cdt;
1683   gboolean first_tpdu = TRUE;
1684   int new_offset;
1685   gboolean found_ositp = FALSE;
1686   gboolean is_cltp = FALSE;
1687   gboolean subdissector_found = FALSE;
1688
1689   if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1690     return FALSE;       /* COTP has been disabled */
1691   /* XXX - what about CLTP? */
1692
1693   pinfo->current_proto = "COTP";
1694
1695   /* Initialize the COL_INFO field; each of the TPDUs will have its
1696      information appended. */
1697   if (check_col(pinfo->cinfo, COL_INFO))
1698     col_add_str(pinfo->cinfo, COL_INFO, "");
1699
1700   while (tvb_offset_exists(tvb, offset)) {
1701     if (!first_tpdu) {
1702       if (check_col(pinfo->cinfo, COL_INFO))
1703         col_append_str(pinfo->cinfo, COL_INFO, ", ");
1704     }
1705     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1706       if (check_col(pinfo->cinfo, COL_INFO))
1707         col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1708       if (!first_tpdu)
1709         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1710                        pinfo, tree);
1711       return found_ositp;
1712     }
1713
1714     tpdu    = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1715     if (tpdu == UD_TPDU)
1716       pinfo->current_proto = "CLTP";    /* connectionless transport */
1717     cdt     = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1718
1719     switch (tpdu) {
1720       case CC_TPDU :
1721       case CR_TPDU :
1722         new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1723                                      uses_inactive_subset, &subdissector_found);
1724         break;
1725       case DR_TPDU :
1726         new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1727         break;
1728       case DT_TPDU :
1729         new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1730                                    uses_inactive_subset, &subdissector_found);
1731         break;
1732       case ED_TPDU :
1733         new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1734         break;
1735       case RJ_TPDU :
1736         new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1737         break;
1738       case DC_TPDU :
1739         new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1740         break;
1741       case AK_TPDU :
1742         new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1743         break;
1744       case EA_TPDU :
1745         new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1746         break;
1747       case ER_TPDU :
1748         new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1749         break;
1750       case UD_TPDU :
1751         new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1752         is_cltp = TRUE;
1753         break;
1754       default      :
1755         if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1756           col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1757         new_offset = -1;        /* bad PDU type */
1758         break;
1759     }
1760
1761     if (new_offset == -1) { /* incorrect TPDU */
1762       if (!first_tpdu)
1763         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1764                        pinfo, tree);
1765       break;
1766     }
1767
1768     if (first_tpdu) {
1769       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1770          is either COTP or CLTP. */
1771       if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1772         col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1773       found_ositp = TRUE;
1774     }
1775
1776     offset = new_offset;
1777     first_tpdu = FALSE;
1778   }
1779   return found_ositp;
1780 } /* dissect_ositp_internal */
1781
1782 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1783 {
1784   if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1785     call_dissector(data_handle,tvb, pinfo, tree);
1786 }
1787
1788 /*
1789  *  CLNP part / main entry point
1790 */
1791
1792 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1793 {
1794   proto_tree *clnp_tree = NULL;
1795   proto_item *ti;
1796   guint8      cnf_proto_id;
1797   guint8      cnf_hdr_len;
1798   guint8      cnf_vers;
1799   guint8      cnf_ttl;
1800   guint8      cnf_type;
1801   char        flag_string[6+1];
1802   char       *pdu_type_string;
1803   proto_tree *type_tree;
1804   guint16     segment_length;
1805   guint16     du_id = 0;
1806   guint16     segment_offset = 0;
1807   guint16     cnf_cksum;
1808   cksum_status_t cksum_status;
1809   int         offset;
1810   guchar      src_len, dst_len, nsel, opt_len = 0;
1811   const guint8     *dst_addr, *src_addr;
1812   gint        len;
1813   guint       next_length;
1814   proto_tree *discpdu_tree;
1815   gboolean    save_in_error_pkt;
1816   fragment_data *fd_head;
1817   tvbuff_t   *next_tvb;
1818   gboolean    update_col_info = TRUE;
1819   gboolean    save_fragmented;
1820
1821   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1822     col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1823   if (check_col(pinfo->cinfo, COL_INFO))
1824     col_clear(pinfo->cinfo, COL_INFO);
1825
1826   cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1827   if (cnf_proto_id == NLPID_NULL) {
1828     if (check_col(pinfo->cinfo, COL_INFO))
1829       col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1830     if (tree) {
1831       ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1832       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1833       proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1834                                  cnf_proto_id,
1835                                  "Inactive subset");
1836     }
1837     next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1838     dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1839     return;
1840   }
1841
1842   /* return if version not known */
1843   cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1844   if (cnf_vers != ISO8473_V1) {
1845     call_dissector(data_handle,tvb, pinfo, tree);
1846     return;
1847   }
1848
1849   /* fixed part decoding */
1850   cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1851   opt_len = cnf_hdr_len;
1852
1853   if (tree) {
1854     ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1855     clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1856     proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1857                                cnf_proto_id);
1858     proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1859                         cnf_hdr_len);
1860     proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1861                         cnf_vers);
1862     cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1863     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1864                                cnf_ttl,
1865                                "Holding Time : %u (%u.%u secs)",
1866                                cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1867   }
1868
1869   cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1870   pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1871                                 "Unknown (0x%02x)");
1872   flag_string[0] = '\0';
1873   if (cnf_type & CNF_SEG_OK)
1874     strcat(flag_string, "S ");
1875   if (cnf_type & CNF_MORE_SEGS)
1876     strcat(flag_string, "M ");
1877   if (cnf_type & CNF_ERR_OK)
1878     strcat(flag_string, "E ");
1879   if (tree) {
1880     ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1881                                cnf_type,
1882                                "PDU Type     : 0x%02x (%s%s)",
1883                                cnf_type,
1884                                flag_string,
1885                                pdu_type_string);
1886     type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1887     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1888                         decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1889                                       "Segmentation permitted",
1890                                       "Segmentation not permitted"));
1891     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1892                         decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1893                                       "More segments",
1894                                       "Last segment"));
1895     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1896                         decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1897                                       "Report error if PDU discarded",
1898                                       "Don't report error if PDU discarded"));
1899     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1900                         decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1901                                       npdu_type_vals, "%s"));
1902   }
1903
1904   /* If we don't have the full header - i.e., not enough to see the
1905      segmentation part and determine whether this datagram is segmented
1906      or not - set the Info column now; we'll get an exception before
1907      we set it otherwise. */
1908
1909   if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1910     if (check_col(pinfo->cinfo, COL_INFO))
1911       col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1912   }
1913
1914   segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1915   cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1916   cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1917   if (tree) {
1918     proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1919                         segment_length);
1920     switch (cksum_status) {
1921
1922     default:
1923         /*
1924          * No checksum present, or not enough of the header present to
1925          * checksum it.
1926          */
1927         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1928                                P_CLNP_CKSUM, 2,
1929                                cnf_cksum,
1930                                "Checksum     : 0x%04x",
1931                                cnf_cksum);
1932         break;
1933
1934     case CKSUM_OK:
1935         /*
1936          * Checksum is correct.
1937          */
1938         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1939                                P_CLNP_CKSUM, 2,
1940                                cnf_cksum,
1941                                "Checksum     : 0x%04x (correct)",
1942                                cnf_cksum);
1943         break;
1944
1945     case CKSUM_NOT_OK:
1946         /*
1947          * Checksum is not correct.
1948          */
1949         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1950                                P_CLNP_CKSUM, 2,
1951                                cnf_cksum,
1952                                "Checksum     : 0x%04x (incorrect)",
1953                                cnf_cksum);
1954         break;
1955     }
1956     opt_len -= 9; /* Fixed part of Hesder */
1957   } /* tree */
1958
1959   /* address part */
1960
1961   offset = P_CLNP_ADDRESS_PART;
1962   dst_len  = tvb_get_guint8(tvb, offset);
1963   dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1964   nsel     = tvb_get_guint8(tvb, offset + dst_len);
1965   src_len  = tvb_get_guint8(tvb, offset + dst_len + 1);
1966   src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1967
1968   if (tree) {
1969     proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1970                         dst_len);
1971     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1972                                dst_addr,
1973                                " DA : %s",
1974                                print_nsap_net(dst_addr, dst_len));
1975     proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1976                         offset + 1 + dst_len, 1, src_len);
1977     proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1978                                offset + dst_len + 2, src_len,
1979                                src_addr,
1980                                " SA : %s",
1981                                print_nsap_net(src_addr, src_len));
1982
1983     opt_len -= dst_len + src_len +2;
1984   }
1985
1986   SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1987   SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1988   SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1989   SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1990
1991   /* Segmentation Part */
1992
1993   offset += dst_len + src_len + 2;
1994
1995   if (cnf_type & CNF_SEG_OK) {
1996     struct clnp_segment seg;                    /* XXX - not used */
1997     tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg));       /* XXX - not used */
1998
1999     segment_offset = tvb_get_ntohs(tvb, offset + 2);
2000     du_id = tvb_get_ntohs(tvb, offset);
2001     if (tree) {
2002       proto_tree_add_text(clnp_tree, tvb, offset, 2,
2003                         "Data unit identifier: %06u",
2004                         du_id);
2005       proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
2006                         "Segment offset      : %6u",
2007                         segment_offset);
2008       proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
2009                         "Total length        : %6u",
2010                         tvb_get_ntohs(tvb, offset + 4));
2011     }
2012
2013     offset  += 6;
2014     opt_len -= 6;
2015   }
2016
2017   if (tree) {
2018     /* To do : decode options  */
2019 /*
2020     proto_tree_add_text(clnp_tree, tvb, offset,
2021                         cnf_hdr_len - offset,
2022                         "Options/Data: <not shown>");
2023 */
2024 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
2025
2026     dissect_osi_options( opt_len,
2027                          tvb, offset, clnp_tree );
2028   }
2029
2030   /* Length of CLNP datagram plus headers above it. */
2031   len = segment_length;
2032
2033   offset = cnf_hdr_len;
2034
2035   /* If clnp_reassemble is on, this is a segment, we have all the
2036    * data in the segment, and the checksum is valid, then just add the
2037    * segment to the hashtable.
2038    */
2039   save_fragmented = pinfo->fragmented;
2040   if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
2041         ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
2042         tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
2043         cksum_status != CKSUM_NOT_OK) {
2044     fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table,
2045                            clnp_reassembled_table, segment_offset,
2046                            segment_length - cnf_hdr_len,
2047                            cnf_type & CNF_MORE_SEGS);
2048
2049     next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
2050         fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
2051   } else {
2052     /* If this is the first segment, dissect its contents, otherwise
2053        just show it as a segment.
2054
2055        XXX - if we eventually don't save the reassembled contents of all
2056        segmented datagrams, we may want to always reassemble. */
2057     if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
2058       /* Not the first segment - don't dissect it. */
2059       next_tvb = NULL;
2060     } else {
2061       /* First segment, or not segmented.  Dissect what we have here. */
2062
2063       /* Get a tvbuff for the payload. */
2064       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
2065
2066       /*
2067        * If this is the first segment, but not the only segment,
2068        * tell the next protocol that.
2069        */
2070       if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
2071         pinfo->fragmented = TRUE;
2072       else
2073         pinfo->fragmented = FALSE;
2074     }
2075   }
2076
2077   if (next_tvb == NULL) {
2078     /* Just show this as a segment. */
2079     if (check_col(pinfo->cinfo, COL_INFO))
2080       col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
2081                 pdu_type_string, flag_string, segment_offset);
2082
2083     /* As we haven't reassembled anything, we haven't changed "pi", so
2084        we don't have to restore it. */
2085     call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
2086                    tree);
2087     pinfo->fragmented = save_fragmented;
2088     return;
2089   }
2090
2091   if (tvb_offset_exists(tvb, offset)) {
2092     switch (cnf_type & CNF_TYPE) {
2093
2094     case DT_NPDU:
2095     case MD_NPDU:
2096       /* Continue with COTP if any data.
2097          XXX - if this isn't the first Derived PDU of a segmented Initial
2098          PDU, skip that? */
2099
2100       if (nsel == (char)tp_nsap_selector || always_decode_transport) {
2101         if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
2102           pinfo->fragmented = save_fragmented;
2103           return;       /* yes, it appears to be COTP or CLTP */
2104         }
2105       }
2106       if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
2107                                   pinfo, tree)) {
2108           pinfo->fragmented = save_fragmented;
2109           return;       /* yes, it appears to be COTP or CLTP */
2110       }
2111         
2112       break;
2113
2114     case ER_NPDU:
2115       /* The payload is the header and "none, some, or all of the data
2116          part of the discarded PDU", i.e. it's like an ICMP error;
2117          dissect it as a CLNP PDU. */
2118       if (check_col(pinfo->cinfo, COL_INFO))
2119         col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2120       if (tree) {
2121         next_length = tvb_length_remaining(tvb, offset);
2122         if (next_length != 0) {
2123           /* We have payload; dissect it. */
2124           ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2125             "Discarded PDU");
2126           discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2127
2128           /* Save the current value of the "we're inside an error packet"
2129              flag, and set that flag; subdissectors may treat packets
2130              that are the payload of error packets differently from
2131              "real" packets. */
2132           save_in_error_pkt = pinfo->in_error_pkt;
2133           pinfo->in_error_pkt = TRUE;
2134
2135           call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
2136
2137           /* Restore the "we're inside an error packet" flag. */
2138           pinfo->in_error_pkt = save_in_error_pkt;
2139         }
2140       }
2141       pinfo->fragmented = save_fragmented;
2142       return;   /* we're done with this PDU */
2143
2144     case ERQ_NPDU:
2145     case ERP_NPDU:
2146       /* XXX - dissect this */
2147       break;
2148     }
2149   }
2150   if (check_col(pinfo->cinfo, COL_INFO))
2151     col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2152   call_dissector(data_handle,next_tvb, pinfo, tree);
2153   pinfo->fragmented = save_fragmented;
2154 } /* dissect_clnp */
2155
2156 static void
2157 clnp_reassemble_init(void)
2158 {
2159   fragment_table_init(&clnp_segment_table);
2160   reassembled_table_init(&clnp_reassembled_table);
2161 }
2162
2163 static void
2164 cotp_reassemble_init(void)
2165 {
2166   fragment_table_init(&cotp_segment_table);
2167   reassembled_table_init(&cotp_reassembled_table);
2168 }
2169
2170 void proto_register_clnp(void)
2171 {
2172   static hf_register_info hf[] = {
2173     { &hf_clnp_id,
2174       { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2175         VALS(nlpid_vals), 0x0, "", HFILL }},
2176
2177     { &hf_clnp_length,
2178       { "HDR Length   ", "clnp.len",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2179
2180     { &hf_clnp_version,
2181       { "Version      ", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2182
2183     { &hf_clnp_ttl,
2184       { "Holding Time ", "clnp.ttl",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2185
2186     { &hf_clnp_type,
2187       { "PDU Type     ", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2188
2189     { &hf_clnp_pdu_length,
2190       { "PDU length   ", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2191
2192     { &hf_clnp_checksum,
2193       { "Checksum     ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2194
2195     { &hf_clnp_dest_length,
2196       { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2197
2198     { &hf_clnp_dest,
2199       { " DA ", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2200
2201     { &hf_clnp_src_length,
2202       { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2203
2204     { &hf_clnp_src,
2205       { " SA ", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2206
2207     { &hf_clnp_segment_overlap,
2208       { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2209         "Segment overlaps with other segments", HFILL }},
2210
2211     { &hf_clnp_segment_overlap_conflict,
2212       { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2213         "Overlapping segments contained conflicting data", HFILL }},
2214
2215     { &hf_clnp_segment_multiple_tails,
2216       { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2217         "Several tails were found when reassembling the packet", HFILL }},
2218
2219     { &hf_clnp_segment_too_long_segment,
2220       { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2221         "Segment contained data past end of packet", HFILL }},
2222
2223     { &hf_clnp_segment_error,
2224       { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2225         "Reassembly error due to illegal segments", HFILL }},
2226
2227     { &hf_clnp_segment,
2228       { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2229         "CLNP Segment", HFILL }},
2230
2231     { &hf_clnp_segments,
2232       { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2233         "CLNP Segments", HFILL }},
2234
2235     { &hf_clnp_reassembled_in,
2236       { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2237         "This CLNP packet is reassembled in this frame", HFILL }}
2238   };
2239   static gint *ett[] = {
2240     &ett_clnp,
2241     &ett_clnp_type,
2242     &ett_clnp_segments,
2243     &ett_clnp_segment,
2244     &ett_clnp_disc_pdu,
2245   };
2246
2247   module_t *clnp_module;
2248
2249   proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2250   proto_register_field_array(proto_clnp, hf, array_length(hf));
2251   proto_register_subtree_array(ett, array_length(ett));
2252   register_dissector("clnp", dissect_clnp, proto_clnp);
2253   register_heur_dissector_list("clnp", &clnp_heur_subdissector_list);  
2254   register_init_routine(clnp_reassemble_init);
2255   register_init_routine(cotp_reassemble_init);
2256
2257   clnp_module = prefs_register_protocol(proto_clnp, NULL);
2258   prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2259         "NSAP selector for Transport Protocol (last byte in hex)",
2260         "NSAP selector for Transport Protocol (last byte in hex)",
2261         16, &tp_nsap_selector);
2262   prefs_register_bool_preference(clnp_module, "always_decode_transport",
2263         "Always try to decode NSDU as transport PDUs",
2264         "Always try to decode NSDU as transport PDUs",
2265         &always_decode_transport);
2266   prefs_register_bool_preference(clnp_module, "reassemble",
2267         "Reassemble segmented CLNP datagrams",
2268         "Whether segmented CLNP datagrams should be reassembled",
2269         &clnp_reassemble);
2270 }
2271
2272 void
2273 proto_reg_handoff_clnp(void)
2274 {
2275   data_handle = find_dissector("data");
2276
2277   clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2278   dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2279   dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2280   dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2281 }
2282
2283 void proto_register_cotp(void)
2284 {
2285   static hf_register_info hf[] = {
2286     { &hf_cotp_srcref,
2287       { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
2288         "Source address reference", HFILL}},
2289     { &hf_cotp_destref,
2290       { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
2291         "Destination address reference", HFILL}}, 
2292     { &hf_cotp_type,
2293       { "COTP PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2294         "COTP PDU Type", HFILL}},
2295     { &hf_cotp_segment_overlap,
2296       { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2297         "Segment overlaps with other segments", HFILL }},
2298     { &hf_cotp_segment_overlap_conflict,
2299       { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2300         "Overlapping segments contained conflicting data", HFILL }},
2301     { &hf_cotp_segment_multiple_tails,
2302       { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2303         "Several tails were found when reassembling the packet", HFILL }},
2304     { &hf_cotp_segment_too_long_segment,
2305       { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2306         "Segment contained data past end of packet", HFILL }},
2307     { &hf_cotp_segment_error,
2308       { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2309         "Reassembly error due to illegal segments", HFILL }},
2310     { &hf_cotp_segment,
2311       { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2312         "COTP Segment", HFILL }},
2313     { &hf_cotp_segments,
2314       { "COTP Segments", "cotp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2315         "COTP Segments", HFILL }},
2316     { &hf_cotp_reassembled_in,
2317       { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2318         "This COTP packet is reassembled in this frame", HFILL }},
2319 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
2320    identifiers of unspecified type and length.
2321    Some implementations of COTP use printable strings, others use raw bytes.
2322    We always add both representations to the tree; one will always be hidden
2323    depending on the tsap display preference */
2324     { &hf_cotp_vp_src_tsap,
2325       { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2326         "Calling TSAP", HFILL }},
2327     { &hf_cotp_vp_src_tsap_bytes,
2328       { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2329         "Calling TSAP (bytes representation)", HFILL }},
2330     { &hf_cotp_vp_dst_tsap,
2331       { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
2332         "Called TSAP", HFILL }},
2333     { &hf_cotp_vp_dst_tsap_bytes,
2334       { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
2335         "Called TSAP (bytes representation)", HFILL }},
2336
2337   };
2338   static gint *ett[] = {
2339         &ett_cotp,
2340         &ett_cotp_segment,
2341         &ett_cotp_segments,
2342   };
2343
2344   module_t *cotp_module;
2345
2346   proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2347   proto_register_field_array(proto_cotp, hf, array_length(hf));
2348   proto_register_subtree_array(ett, array_length(ett));
2349   cotp_module = prefs_register_protocol(proto_cotp, NULL);
2350
2351   prefs_register_bool_preference(cotp_module, "reassemble",
2352          "Reassemble segmented COTP datagrams",
2353          "Whether segmented COTP datagrams should be reassembled",
2354         &cotp_reassemble);
2355
2356   prefs_register_enum_preference(cotp_module, "tsap_display",
2357          "Display TSAPs as strings or bytes",
2358          "How TSAPs should be displayed",
2359         &tsap_display,
2360         tsap_display_options,
2361         FALSE);
2362
2363   /* subdissector code in inactive subset */
2364   register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2365
2366   /* other COTP/ISO 8473 subdissectors */
2367   register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2368
2369   /* XXX - what about CLTP and proto_cltp? */
2370   register_dissector("ositp", dissect_ositp, proto_cotp);
2371 }
2372
2373 void
2374 proto_reg_handoff_cotp(void)
2375 {
2376   dissector_handle_t ositp_handle;
2377
2378   ositp_handle = find_dissector("ositp");
2379   dissector_add("ip.proto", IP_PROTO_TP, ositp_handle);
2380 }
2381
2382 void proto_register_cltp(void)
2383 {
2384   static hf_register_info hf[] = {
2385     { &hf_cltp_type,
2386       { "CLTP PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
2387         "CLTP PDU Type", HFILL}},
2388   };
2389   static gint *ett[] = {
2390         &ett_cltp,
2391   };
2392
2393   proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2394   proto_register_field_array(proto_cltp, hf, array_length(hf));
2395   proto_register_subtree_array(ett, array_length(ett));
2396 }