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