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