2024f2313888c216f2607447aa7373c83c9bc548
[metze/wireshark/wip.git] / epan / dissectors / packet-ositp.c
1 /* packet-ositp.c
2  * Routines for ISO/OSI 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 <ctype.h>
31 #include <glib.h>
32 #include <epan/prefs.h>
33 #include <epan/packet.h>
34 #include <epan/reassemble.h>
35 #include <epan/conversation.h>
36 #include <epan/emem.h>
37 #include "packet-frame.h"
38 #include "packet-osi.h"
39 #include "packet-osi-options.h"
40 #include "packet-isis.h"
41 #include "packet-esis.h"
42 #include <epan/nlpid.h>
43 #include <epan/ipproto.h>
44 #include <epan/expert.h>
45 #include <epan/strutil.h>
46
47 /* protocols and fields */
48
49 static int  proto_clnp;
50
51 static int  proto_cotp         = -1;
52 static gint ett_cotp           = -1;
53 static gint ett_cotp_segments  = -1;
54 static gint ett_cotp_segment   = -1;
55
56 static int hf_cotp_li          = -1;
57 static int hf_cotp_type        = -1;
58 static int hf_cotp_srcref      = -1;
59 static int hf_cotp_destref     = -1;
60 static int hf_cotp_class       = -1;
61 static int hf_cotp_opts_extended_formats = -1;
62 static int hf_cotp_opts_no_explicit_flow_control = -1;
63 static int hf_cotp_tpdu_number = -1;
64 static int hf_cotp_tpdu_number_extended = -1;
65 static int hf_cotp_next_tpdu_number = -1;
66 static int hf_cotp_next_tpdu_number_extended = -1;
67 static int hf_cotp_eot                  = -1;
68 static int hf_cotp_eot_extended = -1;
69
70 static int hf_cotp_segments    = -1;
71 static int hf_cotp_segment     = -1;
72 static int hf_cotp_segment_overlap = -1;
73 static int hf_cotp_segment_overlap_conflict = -1;
74 static int hf_cotp_segment_multiple_tails = -1;
75 static int hf_cotp_segment_too_long_segment = -1;
76 static int hf_cotp_segment_error = -1;
77 static int hf_cotp_reassembled_in = -1;
78 static int hf_cotp_reassembled_length = -1;
79
80 static const true_false_string fragment_descriptions = {
81         "Yes",
82         "No"
83 };
84
85 static int  proto_cltp         = -1;
86 static gint ett_cltp           = -1;
87
88 static int hf_cltp_li = -1;
89 static int hf_cltp_type = -1;
90
91 static const fragment_items cotp_frag_items = {
92         &ett_cotp_segment,
93         &ett_cotp_segments,
94         &hf_cotp_segments,
95         &hf_cotp_segment,
96         &hf_cotp_segment_overlap,
97         &hf_cotp_segment_overlap_conflict,
98         &hf_cotp_segment_multiple_tails,
99         &hf_cotp_segment_too_long_segment,
100         &hf_cotp_segment_error,
101         &hf_cotp_reassembled_in,
102         &hf_cotp_reassembled_length,
103         "segments"
104 };
105
106 static dissector_handle_t data_handle;
107
108 /*
109  * ISO8073 OSI COTP definition
110  * See http://standards.iso.org/ittf/PubliclyAvailableStandards/index.html
111  * (or RFC905 for historic, and now-outdated information)
112  */
113
114 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
115
116 /* TPDU definition */
117
118 #define ED_TPDU                 0x1     /* COTP */
119 #define EA_TPDU                 0x2     /* COTP */
120 #define UD_TPDU                 0x4     /* CLTP */
121 #define RJ_TPDU                 0x5     /* COTP */
122 #define AK_TPDU                 0x6     /* COTP */
123 #define ER_TPDU                 0x7     /* COTP */
124 #define DR_TPDU                 0x8     /* COTP */
125 #define DC_TPDU                 0xC     /* COTP */
126 #define CC_TPDU                 0xD     /* COTP */
127 #define CR_TPDU                 0xE     /* COTP */
128 #define DT_TPDU                 0xF     /* COTP */
129
130 static const value_string cotp_tpdu_type_abbrev_vals[] = {
131   { ED_TPDU,    "ED Expedited Data" },
132   { EA_TPDU,    "EA Expedited Data Acknowledgement" },
133   { RJ_TPDU,    "RJ Reject" },
134   { AK_TPDU,    "AK Data Acknowledgement" },
135   { ER_TPDU,    "ER TPDU Error" },
136   { DR_TPDU,    "DR Disconnect Request" },
137   { DC_TPDU,    "DC Disconnect Confirm" },
138   { CC_TPDU,    "CC Connect Confirm" },
139   { CR_TPDU,    "CR Connect Request" },
140   { DT_TPDU,    "DT Data" },
141   { 0,          NULL }
142 };
143
144 static const value_string cltp_tpdu_type_abbrev_vals[] = {
145   { UD_TPDU,    "UD" },
146   { 0,          NULL }
147 };
148
149 static const value_string class_option_vals[] = {
150   {0,   "Class 0"},
151   {1,   "Class 1"},
152   {2,   "Class 2"},
153   {3,   "Class 3"},
154   {4,   "Class 4"},
155   {0,   NULL}
156 };
157
158 /* field position */
159
160 #define P_LI                    0
161 #define P_TPDU                  1
162 #define P_CDT                   1
163 #define P_DST_REF               2
164 #define P_SRC_REF               4
165 #define P_TPDU_NR_0_1           2
166 #define P_TPDU_NR_234           4
167 #define P_VAR_PART_NDT          5
168 #define P_VAR_PART_EDT          8
169 #define P_VAR_PART_DC           6
170 #define P_CDT_IN_AK             8
171 #define P_CDT_IN_RJ             8
172 #define P_REJECT_ER             4
173 #define P_REASON_IN_DR          6
174 #define P_CLASS_OPTION          6
175
176 /* TPDU length indicator */
177
178 #define LI_NORMAL_DT_CLASS_01            2
179 #define LI_NORMAL_DT_WITH_CHECKSUM       8
180 #define LI_NORMAL_DT_WITHOUT_CHECKSUM    4
181 #define LI_EXTENDED_DT_WITH_CHECKSUM     11
182 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM  7
183 #define LI_NORMAL_EA_WITH_CHECKSUM       8
184 #define LI_NORMAL_EA_WITHOUT_CHECKSUM    4
185 #define LI_EXTENDED_EA_WITH_CHECKSUM     11
186 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM  7
187 #define LI_NORMAL_RJ                     4
188 #define LI_EXTENDED_RJ                   9
189 #define LI_MIN_DR                        6
190 #define LI_MAX_DC                        9
191 #define LI_MAX_AK                        27
192 #define LI_MAX_EA                        11
193 #define LI_MAX_ER                        8
194 /* XXX - can we always decide this based on whether the length
195    indicator is odd or not?  What if the variable part has an odd
196    number of octets? */
197 #define is_LI_NORMAL_AK(p)               ( ( p & 0x01 ) == 0 )
198
199 /* variant part */
200
201 #define VP_ACK_TIME             0x85
202 #define VP_RES_ERROR            0x86
203 #define VP_PRIORITY             0x87
204 #define VP_TRANSIT_DEL          0x88
205 #define VP_THROUGHPUT           0x89
206 #define VP_SEQ_NR               0x8A         /* in AK */
207 #define VP_REASSIGNMENT         0x8B
208 #define VP_FLOW_CNTL            0x8C         /* in AK */
209 #define VP_TPDU_SIZE            0xC0
210 #define VP_SRC_TSAP             0xC1         /* in CR/CC */
211 #define VP_DST_TSAP             0xC2
212 #define VP_CHECKSUM             0xC3
213 #define VP_VERSION_NR           0xC4
214 #define VP_PROTECTION           0xC5
215 #define VP_OPT_SEL              0xC6
216 #define VP_PROTO_CLASS          0xC7
217 #define VP_PREF_MAX_TPDU_SIZE   0xF0
218 #define VP_INACTIVITY_TIMER     0xF2
219
220 static const value_string tp_vpart_type_vals[] = {
221   { VP_ACK_TIME,                "ack time" },
222   { VP_RES_ERROR,               "res error" },
223   { VP_PRIORITY,                "priority" },
224   { VP_TRANSIT_DEL,             "transit delay" },
225   { VP_THROUGHPUT,              "throughput" },
226   { VP_SEQ_NR,                  "seq number" },
227   { VP_REASSIGNMENT,            "reassignment" },
228   { VP_FLOW_CNTL,               "flow control" },
229   { VP_TPDU_SIZE,               "tpdu-size" },
230   { VP_SRC_TSAP,                "src-tsap" },
231   { VP_DST_TSAP,                "dst-tsap" },
232   { VP_CHECKSUM,                "checksum" },
233   { VP_VERSION_NR,              "version" },
234   { VP_PROTECTION,              "protection" },
235   { VP_OPT_SEL,                 "options" },
236   { VP_PROTO_CLASS,             "proto class" },
237   { VP_PREF_MAX_TPDU_SIZE,      "preferred max TPDU size" },
238   { 0,                          NULL }
239 };
240
241 static int hf_cotp_vp_src_tsap = -1;
242 static int hf_cotp_vp_dst_tsap = -1;
243 static int hf_cotp_vp_src_tsap_bytes = -1;
244 static int hf_cotp_vp_dst_tsap_bytes = -1;
245
246 /* global variables */
247
248 /* List of dissectors to call for COTP packets put atop the Inactive
249    Subset of CLNP. */
250 static heur_dissector_list_t cotp_is_heur_subdissector_list;
251 /* List of dissectors to call for COTP packets put atop CLNP */
252 static heur_dissector_list_t cotp_heur_subdissector_list;
253 /* List of dissectors to call for CLTP packets put atop CLNP */
254 static heur_dissector_list_t cltp_heur_subdissector_list;
255
256 /*
257  * Reassembly of COTP.
258  */
259 static GHashTable *cotp_segment_table = NULL;
260 static GHashTable *cotp_reassembled_table = NULL;
261 static guint16    cotp_dst_ref = 0;
262 static gboolean   cotp_frame_reset = FALSE;
263 static gboolean   cotp_last_fragment = FALSE;
264
265 #define TSAP_DISPLAY_AUTO       0
266 #define TSAP_DISPLAY_STRING     1
267 #define TSAP_DISPLAY_BYTES      2
268
269
270 /* options */
271 static gboolean cotp_reassemble = TRUE;
272 static gint32   tsap_display = TSAP_DISPLAY_AUTO;
273
274 const enum_val_t tsap_display_options[] = {
275   {"auto", "As strings if printable", TSAP_DISPLAY_AUTO},
276   {"string", "As strings", TSAP_DISPLAY_STRING},
277   {"bytes", "As bytes", TSAP_DISPLAY_BYTES},
278   {NULL, NULL, -1}
279 };
280
281
282 /* function definitions */
283
284 #define MAX_TSAP_LEN    32
285
286 static void cotp_frame_end(void)
287 {
288   if (!cotp_last_fragment) {
289     /* Last COTP in frame is not fragmented.  
290      * No need for incrementing the dst_ref, so we decrement it here.
291      */
292     cotp_dst_ref--;
293   }
294   cotp_frame_reset = TRUE;
295 }
296
297 static gboolean is_all_printable(const guchar *stringtocheck, int length)
298 {
299   gboolean allprintable;
300   int i;
301
302   allprintable=TRUE;
303   for (i=0;i<length;i++) {
304     if (!(isascii(stringtocheck[i]) && isprint(stringtocheck[i]))) {
305       allprintable=FALSE;
306       break;
307     }
308   }
309   return allprintable;
310 } /* is_all_printable */
311
312
313 static gchar *print_tsap(const guchar *tsap, int length)
314 {
315
316   gchar *cur;
317   gboolean allprintable;
318   gint idx = 0, returned_length;
319
320   cur=ep_alloc(MAX_TSAP_LEN * 2 + 3);
321   cur[0] = '\0';
322   if (length <= 0 || length > MAX_TSAP_LEN)
323     g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "<unsupported TSAP length>");
324   else {
325     allprintable = is_all_printable(tsap,length);
326     if (!allprintable) {
327       returned_length = g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x");
328       idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1);
329     }
330     while (length != 0) {
331       if (allprintable) {
332         returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%c", *tsap ++);
333         idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1 );
334       } else {
335         returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%02x", *tsap ++);
336         idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1);
337       }
338       length --;
339     }
340   }
341   return cur;
342
343 } /* print_tsap */
344
345 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
346                                       int vp_length, int class_option,
347                                       proto_tree *tree)
348 {
349   guint8  code, length;
350   guint8  c1;
351   guint16 s, s1,s2,s3,s4;
352   guint32 t1, t2, t3, t4;
353   guint32 pref_max_tpdu_size;
354   proto_item *hidden_item;
355
356   while (vp_length != 0) {
357     code = tvb_get_guint8(tvb, offset);
358     proto_tree_add_text(tree, tvb, offset, 1,
359                 "Parameter code:   0x%02x (%s)",
360                             code,
361                             val_to_str(code, tp_vpart_type_vals, "Unknown"));
362     offset += 1;
363     vp_length -= 1;
364
365     if (vp_length == 0)
366       break;
367     length = tvb_get_guint8(tvb, offset);
368     proto_tree_add_text(tree, tvb, offset, 1,
369                 "Parameter length: %u", length);
370     offset += 1;
371     vp_length -= 1;
372
373     switch (code) {
374
375     case VP_ACK_TIME:
376       s = tvb_get_ntohs(tvb, offset);
377       proto_tree_add_text(tree, tvb, offset, length,
378                               "Ack time (ms): %u", s);
379       offset += length;
380       vp_length -= length;
381       break;
382
383     case VP_RES_ERROR:
384       proto_tree_add_text(tree, tvb, offset, 1,
385                 "Residual error rate, target value: 10^%u",
386                 tvb_get_guint8(tvb, offset));
387       offset += 1;
388       length -= 1;
389       vp_length -= 1;
390
391       proto_tree_add_text(tree, tvb, offset, 1,
392                 "Residual error rate, minimum acceptable: 10^%u",
393                 tvb_get_guint8(tvb, offset));
394       offset += 1;
395       length -= 1;
396       vp_length -= 1;
397
398
399       proto_tree_add_text(tree, tvb, offset, 1,
400                 "Residual error rate, TSDU size of interest: %u",
401                 1<<tvb_get_guint8(tvb, offset));
402       offset += 1;
403       vp_length -= 1;
404
405       break;
406
407     case VP_PRIORITY:
408       s = tvb_get_ntohs(tvb, offset);
409       proto_tree_add_text(tree, tvb, offset, length,
410                 "Priority: %u", s);
411       offset += length;
412       vp_length -= length;
413       break;
414
415     case VP_TRANSIT_DEL:
416       s1 = tvb_get_ntohs(tvb, offset);
417       proto_tree_add_text(tree, tvb, offset, 2,
418                 "Transit delay, target value, calling-called: %u ms", s1);
419       offset += 2;
420       length -= 2;
421       vp_length -= 2;
422
423       s2 = tvb_get_ntohs(tvb, offset);
424       proto_tree_add_text(tree, tvb, offset, 2,
425                 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
426       offset += 2;
427       length -= 2;
428       vp_length -= 2;
429
430       s3 = tvb_get_ntohs(tvb, offset);
431       proto_tree_add_text(tree, tvb, offset, 2,
432                 "Transit delay, target value, called-calling: %u ms", s3);
433       offset += 2;
434       length -= 2;
435       vp_length -= 2;
436
437       s4 = tvb_get_ntohs(tvb, offset);
438       proto_tree_add_text(tree, tvb, offset, 2,
439                 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
440       offset += 2;
441       vp_length -= 2;
442       break;
443
444     case VP_THROUGHPUT:
445       t1 = tvb_get_ntoh24(tvb, offset);
446       proto_tree_add_text(tree, tvb, offset, 3,
447                 "Maximum throughput, target value, calling-called:       %u o/s", t1);
448       offset += 3;
449       length -= 3;
450       vp_length -= 3;
451
452       t2 = tvb_get_ntoh24(tvb, offset);
453       proto_tree_add_text(tree, tvb, offset, 3,
454                 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
455       offset += 3;
456       length -= 3;
457       vp_length -= 3;
458
459       t3 = tvb_get_ntoh24(tvb, offset);
460       proto_tree_add_text(tree, tvb, offset, 3,
461                 "Maximum throughput, target value, called-calling:       %u o/s", t3);
462       offset += 3;
463       length -= 3;
464       vp_length -= 3;
465
466       t4 = tvb_get_ntoh24(tvb, offset);
467       proto_tree_add_text(tree, tvb, offset, 3,
468                 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
469       offset += 3;
470       length -= 3;
471       vp_length -= 3;
472
473       if (length != 0) {        /* XXX - should be 0 or 12 */
474         t1 = tvb_get_ntoh24(tvb, offset);
475         proto_tree_add_text(tree, tvb, offset, 3,
476                 "Average throughput, target value, calling-called:       %u o/s", t1);
477         offset += 3;
478         length -= 3;
479         vp_length -= 3;
480
481         t2 = tvb_get_ntoh24(tvb, offset);
482         proto_tree_add_text(tree, tvb, offset, 3,
483                 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
484         offset += 3;
485         length -= 3;
486         vp_length -= 3;
487
488         t3 = tvb_get_ntoh24(tvb, offset);
489         proto_tree_add_text(tree, tvb, offset, 3,
490                 "Average throughput, target value, called-calling:       %u o/s", t3);
491         offset += 3;
492         length -= 3;
493         vp_length -= 3;
494
495         t4 = tvb_get_ntoh24(tvb, offset);
496         proto_tree_add_text(tree, tvb, offset, 3,
497                 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
498         offset += 3;
499         vp_length -= 3;
500       }
501       break;
502
503     case VP_SEQ_NR:
504       proto_tree_add_text(tree, tvb, offset, 2,
505                 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
506       offset += length;
507       vp_length -= length;
508       break;
509
510     case VP_REASSIGNMENT:
511       proto_tree_add_text(tree, tvb, offset, 2,
512                 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
513       offset += length;
514       vp_length -= length;
515       break;
516
517     case VP_FLOW_CNTL:
518       proto_tree_add_text(tree, tvb, offset, 4,
519                 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
520       offset += 4;
521       length -= 4;
522       vp_length -= 4;
523
524       proto_tree_add_text(tree, tvb, offset, 2,
525                 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
526       offset += 2;
527       length -= 2;
528       vp_length -= 2;
529
530       proto_tree_add_text(tree, tvb, offset, 2,
531                 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
532       offset += 2;
533       vp_length -= 2;
534
535       break;
536
537     case VP_TPDU_SIZE:
538       c1 = tvb_get_guint8(tvb, offset) & 0x0F;
539       proto_tree_add_text(tree, tvb, offset, length,
540                 "TPDU size: %u", 1 << c1);
541       offset += length;
542       vp_length -= length;
543       break;
544
545     case VP_SRC_TSAP:
546       /* if our preference is set to STRING or the
547          TSAP is not printable, add as bytes and hidden as string;
548          otherwise vice-versa */
549       if (tsap_display==TSAP_DISPLAY_STRING ||
550           (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
551         proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
552                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
553         hidden_item = proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
554         PROTO_ITEM_SET_HIDDEN(hidden_item);
555       } else {
556         hidden_item = proto_tree_add_string(tree, hf_cotp_vp_src_tsap, tvb, offset, length,
557                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
558         PROTO_ITEM_SET_HIDDEN(hidden_item);
559         proto_tree_add_item(tree, hf_cotp_vp_src_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
560       }
561       offset += length;
562       vp_length -= length;
563       break;
564
565     case VP_DST_TSAP:
566       /* if our preference is set to STRING or the
567          TSAP is not printable, add as bytes and hidden as string;
568          otherwise vice-versa */
569       if (tsap_display==TSAP_DISPLAY_STRING ||
570           (tsap_display==TSAP_DISPLAY_AUTO && is_all_printable(tvb_get_ptr(tvb,offset,length),length))) {
571         proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
572                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
573         hidden_item = proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
574         PROTO_ITEM_SET_HIDDEN(hidden_item);
575       } else {
576         hidden_item = proto_tree_add_string(tree, hf_cotp_vp_dst_tsap, tvb, offset, length,
577                 print_tsap(tvb_get_ptr(tvb, offset, length),length));
578         PROTO_ITEM_SET_HIDDEN(hidden_item);
579         proto_tree_add_item(tree, hf_cotp_vp_dst_tsap_bytes, tvb, offset, length, ENC_BIG_ENDIAN);
580       }
581       offset += length;
582       vp_length -= length;
583       break;
584
585     case VP_CHECKSUM:
586       proto_tree_add_text(tree, tvb, offset, length,
587                 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
588       offset += length;
589       vp_length -= length;
590       break;
591
592     case VP_VERSION_NR:
593       c1 = tvb_get_guint8(tvb, offset);
594       proto_tree_add_text(tree, tvb, offset, length,
595                 "Version: %u", c1);
596       offset += length;
597       vp_length -= length;
598       break;
599
600     case VP_OPT_SEL:
601       c1 = tvb_get_guint8(tvb, offset) & 0x0F;
602       switch (class_option) {
603
604       case 1:
605         if (c1 & 0x8)
606           proto_tree_add_text(tree, tvb, offset, 1,
607                                   "Use of network expedited data");
608         else
609           proto_tree_add_text(tree, tvb, offset, 1,
610                                   "Non use of network expedited data");
611         if (c1 & 0x4)
612           proto_tree_add_text(tree, tvb, offset, 1,
613                                   "Use of Receipt confirmation");
614         else
615           proto_tree_add_text(tree, tvb, offset, 1,
616                                   "Use of explicit AK variant");
617         break;
618
619       case 4:
620         if (c1 & 0x2)
621           proto_tree_add_text(tree, tvb, offset, 1,
622                                   "Non-use 16 bit checksum in class 4");
623         else
624           proto_tree_add_text(tree, tvb, offset, 1,
625                                   "Use 16 bit checksum ");
626         break;
627       }
628       if (c1 & 0x1)
629         proto_tree_add_text(tree, tvb, offset, 1,
630                                 "Use of transport expedited data transfer");
631       else
632         proto_tree_add_text(tree, tvb, offset, 1,
633                                 "Non-use of transport expedited data transfer");
634       offset += length;
635       vp_length -= length;
636       break;
637
638     case VP_PREF_MAX_TPDU_SIZE:
639       switch (length) {
640
641       case 1:
642         pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
643         break;
644
645       case 2:
646         pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
647         break;
648
649       case 3:
650         pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
651         break;
652
653       case 4:
654         pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
655         break;
656
657       default:
658         proto_tree_add_text(tree, tvb, offset, length,
659                 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
660                 length);
661         return FALSE;
662       }
663       proto_tree_add_text(tree, tvb, offset, length,
664                 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
665       offset += length;
666       vp_length -= length;
667       break;
668
669     case VP_INACTIVITY_TIMER:
670       proto_tree_add_text(tree, tvb, offset, length,
671                 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
672       offset += length;
673       vp_length -= length;
674       break;
675
676     case VP_PROTECTION:           /* user-defined */
677     case VP_PROTO_CLASS:          /* todo */
678     default:                      /* unknown, no decoding */
679       proto_tree_add_text(tree, tvb, offset, length,
680                               "Parameter value: <not shown>");
681       offset += length;
682       vp_length -= length;
683       break;
684     }
685   } /* while */
686
687   return TRUE;
688 }
689
690 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
691                          packet_info *pinfo, proto_tree *tree)
692 {
693   proto_tree *cotp_tree;
694   proto_item *ti = NULL;
695   guint16 dst_ref, src_ref;
696   guchar  reason;
697   const char *str;
698
699   if (li < LI_MIN_DR)
700     return -1;
701
702   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
703
704   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
705
706   reason  = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
707
708   pinfo->clnp_dstref = dst_ref;
709   pinfo->clnp_srcref = src_ref;
710
711   /* the settings of the TCP srcport and destport are currently disables,
712    * for the following reasons:
713    * a) only used for ISO conversation handling (which currently doesn't work)
714    * b) will prevent "ISO on TCP" (RFC1006) packets from using "follow TCP stream" correctly
715    *
716    * A future conversation handling might be able to handle different kinds of conversations
717    * (TCP, ISO, TCP on TCP, ...), but in that case this has to be fixed in any case.
718    */
719   /*pinfo->srcport = src_ref;*/
720   /*pinfo->destport = dst_ref;*/
721   switch(reason) {
722     case (128+0): str = "Normal Disconnect"; break;
723     case (128+1): str = "Remote transport entity congestion"; break;
724     case (128+2): str = "Connection negotiation failed"; break;
725     case (128+3): str = "Duplicate source reference"; break;
726     case (128+4): str = "Mismatched references"; break;
727     case (128+5): str = "Protocol error"; break;
728     case (128+7): str = "Reference overflow"; break;
729     case (128+8): str = "Connection request refused"; break;
730     case (128+10):str = "Header or parameter length invalid"; break;
731     case (0):     str = "Reason not specified"; break;
732     case (1):     str = "Congestion at TSAP"; break;
733     case (2):     str = "Session entity not attached to TSAP"; break;
734     case (3):     str = "Address unknown"; break;
735     default:      return -1;
736   }
737
738   if (check_col(pinfo->cinfo, COL_INFO))
739     col_append_fstr(pinfo->cinfo, COL_INFO,
740                 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
741                  src_ref, dst_ref);
742
743   if (tree) {
744     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
745     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
746     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
747     proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu);
748     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
749     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset +  4, 2, src_ref);
750     proto_tree_add_text(cotp_tree, tvb, offset +  6, 1,
751                         "Cause: %s", str);
752   }
753
754   offset += li + 1;
755
756   expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT,
757           "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref);
758
759   /* User data */
760   call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree);
761   offset += tvb_length_remaining(tvb, offset);
762      /* we dissected all of the containing PDU */
763
764   return offset;
765
766 } /* ositp_decode_DR */
767
768 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
769                          packet_info *pinfo, proto_tree *tree,
770                          gboolean uses_inactive_subset,
771                          gboolean *subdissector_found)
772 {
773   proto_tree *cotp_tree = NULL;
774   proto_item *ti;
775   gboolean is_extended;
776   gboolean is_class_234;
777   guint32  dst_ref;
778   guint32 *prev_dst_ref;
779   guint    tpdu_nr;
780   gboolean fragment = FALSE;
781   guint32  fragment_length = 0;
782   tvbuff_t *next_tvb;
783   fragment_data *fd_head;
784   conversation_t *conv;
785
786   /* VP_CHECKSUM is the only parameter allowed in the variable part.
787      (This means we may misdissect this if the packet is bad and
788      contains other parameters.) */
789   switch (li) {
790
791     case LI_NORMAL_DT_WITH_CHECKSUM      :
792       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
793         return -1;
794       /* FALLTHROUGH */
795
796     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
797       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
798       if ( tpdu_nr & 0x80 )
799         tpdu_nr = tpdu_nr & 0x7F;
800       else
801         fragment = TRUE;
802       is_extended = FALSE;
803       is_class_234 = TRUE;
804       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
805       break;
806
807     case LI_EXTENDED_DT_WITH_CHECKSUM    :
808       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
809         return -1;
810       /* FALLTHROUGH */
811
812     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
813       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
814       if ( tpdu_nr & 0x80000000 )
815         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
816       else
817         fragment = TRUE;
818       is_extended = TRUE;
819       is_class_234 = TRUE;
820       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
821       break;
822
823     case LI_NORMAL_DT_CLASS_01           :
824       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
825       if ( tpdu_nr & 0x80 )
826         tpdu_nr = tpdu_nr & 0x7F;
827       else
828         fragment = TRUE;
829       is_extended = FALSE;
830       is_class_234 = FALSE;
831       prev_dst_ref = p_get_proto_data (pinfo->fd, proto_clnp);
832       if (!prev_dst_ref) {
833         /* First COTP in frame - save previous dst_ref as offset */
834         prev_dst_ref = se_alloc (sizeof (guint32));
835         *prev_dst_ref = cotp_dst_ref;
836         p_add_proto_data (pinfo->fd, proto_clnp, prev_dst_ref);
837       } else if (cotp_frame_reset) {
838         cotp_dst_ref = *prev_dst_ref;
839       } 
840       cotp_frame_reset = FALSE;
841       cotp_last_fragment = fragment;
842       dst_ref = cotp_dst_ref;
843       conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
844                                 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
845       if (conv) {
846         /* Found a conversation, also use index for the generated dst_ref */
847         dst_ref += (conv->index << 16);
848       }
849       if (!fragment) {
850         cotp_dst_ref++;
851         register_frame_end_routine(cotp_frame_end);
852       }
853       break;
854
855     default : /* bad TPDU */
856       return -1;
857   }
858
859   pinfo->clnp_dstref = dst_ref;
860
861   pinfo->fragmented = fragment;
862   if (check_col(pinfo->cinfo, COL_INFO)) {
863     if (is_class_234) {
864       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x",
865                  tpdu_nr,
866                  dst_ref);
867     } else {
868       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u)", tpdu_nr);
869     }
870   }
871
872   if (tree) {
873     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
874     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
875     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
876   }
877   offset += 1;
878
879   if (tree) {
880     proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
881   }
882   offset += 1;
883   li -= 1;
884
885   if (is_class_234) {
886     if (tree)
887       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
888     offset += 2;
889     li -= 2;
890   } else if (tree) {
891     ti = proto_tree_add_uint (cotp_tree, hf_cotp_destref, tvb, offset, 0, dst_ref);
892     PROTO_ITEM_SET_GENERATED (ti);
893   }
894
895   if (is_extended) {
896     if (tree) {
897       proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb, offset, 4,
898                           tpdu_nr);
899       proto_tree_add_item(cotp_tree, hf_cotp_eot_extended, tvb, offset, 4,
900                           ENC_BIG_ENDIAN);
901     }
902     offset += 4;
903     li -= 4;
904   } else {
905     if (tree) {
906       proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
907                           tpdu_nr);
908       proto_tree_add_item(cotp_tree, hf_cotp_eot, tvb, offset, 1, ENC_BIG_ENDIAN);
909     }
910     offset += 1;
911     li -= 1;
912   }
913
914   if (tree)
915     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
916   offset += li;
917
918   next_tvb = tvb_new_subset_remaining(tvb, offset);
919   fragment_length = tvb_length(next_tvb);
920   if (check_col(pinfo->cinfo, COL_INFO)) {
921       if(fragment) {
922         col_append_fstr(pinfo->cinfo, COL_INFO, " [COTP fragment, %u byte%s]", 
923             fragment_length, plurality(fragment_length, "", "s"));
924       } else {
925         col_append_fstr(pinfo->cinfo, COL_INFO, " EOT");
926       }
927   }
928
929   if (cotp_reassemble) {
930     /*
931      * XXX - these sequence numbers are connection sequence number,
932      * not segment sequence numbers - the first segment of a
933      * segmented packet doesn't have a specific sequence number (e.g., 0
934      * or 1), it has whatever the appropriate sequence number is for
935      * it in the connection.
936      *
937      * For now, we assume segments arrive in order, and just supply
938      * the negation of the EOT flag as the "more flags" argument.
939      * We should probably handle out-of-order packets separately,
940      * so that we can deliver them in order even when *not*
941      * reassembling.
942      *
943      * Note also that TP0 has no sequence number, and relies on
944      * the protocol atop which it runs to guarantee in-order delivery.
945      */
946     fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
947                                      cotp_segment_table,
948                                      cotp_reassembled_table,
949                                      fragment_length, fragment);
950     if (fd_head && fd_head->next) {
951       /* don't use -1 if fragment length is zero (throws Exception) */
952       proto_tree_add_text(cotp_tree, tvb, offset, (fragment_length) ? -1 : 0,
953                           "COTP segment data (%u byte%s)", fragment_length,
954                           plurality(fragment_length, "", "s"));
955
956       if (!fragment) {
957         /* This is the last packet */
958         next_tvb = process_reassembled_data (next_tvb, offset, pinfo,
959                         "Reassembled COTP", fd_head, &cotp_frag_items, NULL, tree);
960       } else if (pinfo->fd->num != fd_head->reassembled_in) {
961         /* Add a "Reassembled in" link if not reassembled in this frame */
962         proto_tree_add_uint (cotp_tree, *(cotp_frag_items.hf_reassembled_in),
963                         next_tvb, 0, 0, fd_head->reassembled_in);
964       }
965       pinfo->fragmented = fragment;
966     }
967   }
968
969   if (uses_inactive_subset) {
970     if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
971                                 pinfo, tree)) {
972       *subdissector_found = TRUE;
973     } else {
974       /* Fill in other Dissectors using inactive subset here */
975       call_dissector(data_handle,next_tvb, pinfo, tree);
976     }
977   } else {
978     /*
979      * We dissect payload if one of the following is TRUE:
980      *
981      * - Reassembly option for COTP in preferences is unchecked
982      * - Reassembly option is checked and this packet is the last fragment
983      */
984     if ( (!cotp_reassemble) ||
985          ((cotp_reassemble) && (!fragment))) {
986       if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
987                                   pinfo, tree)) {
988         *subdissector_found = TRUE;
989       } else {
990         call_dissector(data_handle,next_tvb, pinfo, tree);
991       }
992     }
993   }
994
995   offset += tvb_length_remaining(tvb, offset);
996      /* we dissected all of the containing PDU */
997
998   return offset;
999
1000 } /* ositp_decode_DT */
1001
1002 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1003                          packet_info *pinfo, proto_tree *tree)
1004 {
1005   proto_tree *cotp_tree = NULL;
1006   proto_item *ti;
1007   gboolean is_extended;
1008   guint16  dst_ref;
1009   guint    tpdu_nr;
1010   tvbuff_t *next_tvb;
1011
1012   /* ED TPDUs are never fragmented */
1013
1014   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1015      (This means we may misdissect this if the packet is bad and
1016      contains other parameters.) */
1017   switch (li) {
1018
1019     case LI_NORMAL_DT_WITH_CHECKSUM      :
1020       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1021         return -1;
1022       /* FALLTHROUGH */
1023
1024     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
1025       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1026       if ( tpdu_nr & 0x80 )
1027         tpdu_nr = tpdu_nr & 0x7F;
1028       else
1029         return -1;
1030       is_extended = FALSE;
1031       break;
1032
1033     case LI_EXTENDED_DT_WITH_CHECKSUM    :
1034       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1035         return -1;
1036       /* FALLTHROUGH */
1037
1038     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1039       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1040       if ( tpdu_nr & 0x80000000 )
1041         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1042       else
1043         return -1;
1044       is_extended = TRUE;
1045       break;
1046
1047     default : /* bad TPDU */
1048       return -1;
1049   } /* li */
1050
1051   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1052   pinfo->clnp_dstref = dst_ref;
1053
1054   if (check_col(pinfo->cinfo, COL_INFO))
1055     col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1056                  tpdu_nr, dst_ref);
1057
1058   if (tree) {
1059     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1060     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1061     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1062   }
1063   offset += 1;
1064
1065   if (tree) {
1066     proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1067   }
1068   offset += 1;
1069   li -= 1;
1070
1071   if (tree)
1072     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1073   offset += 2;
1074   li -= 2;
1075
1076   if (is_extended) {
1077     if (tree) {
1078       proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number_extended, tvb,
1079                           offset, 4, tpdu_nr);
1080     }
1081     offset += 4;
1082     li -= 4;
1083   } else {
1084     if (tree) {
1085       proto_tree_add_uint(cotp_tree, hf_cotp_tpdu_number, tvb, offset, 1,
1086                           tpdu_nr);
1087     }
1088     offset += 1;
1089     li -= 1;
1090   }
1091
1092   if (tree)
1093     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1094   offset += li;
1095
1096   next_tvb = tvb_new_subset_remaining(tvb, offset);
1097   call_dissector(data_handle,next_tvb, pinfo, tree);
1098
1099   offset += tvb_length_remaining(tvb, offset);
1100      /* we dissected all of the containing PDU */
1101
1102   return offset;
1103
1104 } /* ositp_decode_ED */
1105
1106 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1107                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1108 {
1109   proto_tree *cotp_tree;
1110   proto_item *ti;
1111   proto_item *item = NULL;
1112   guint16  dst_ref;
1113   guint    tpdu_nr;
1114   gushort  credit = 0;
1115
1116   switch(li) {
1117     case LI_NORMAL_RJ   :
1118       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1119       break;
1120     case LI_EXTENDED_RJ :
1121       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1122       credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1123       break;
1124     default :
1125       return -1;
1126   }
1127
1128   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1129   pinfo->clnp_dstref = dst_ref;
1130
1131   if (check_col(pinfo->cinfo, COL_INFO))
1132     col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1133                  tpdu_nr, dst_ref);
1134
1135   if (tree) {
1136     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1137     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1138     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1139     item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu);
1140     if (li == LI_NORMAL_RJ)
1141       proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1142                           "Credit: %u", cdt);
1143     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1144     if (li == LI_NORMAL_RJ)
1145       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset + 4,
1146                           1, tpdu_nr);
1147     else {
1148       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1149                           offset + 4, 4, tpdu_nr);
1150       proto_tree_add_text(cotp_tree, tvb, offset +  8, 2,
1151                           "Credit: 0x%02x", credit);
1152     }
1153   }
1154
1155   offset += li + 1;
1156
1157   expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_NOTE,
1158           "Reject(RJ): -> 0x%x", dst_ref);
1159
1160   return offset;
1161
1162 } /* ositp_decode_RJ */
1163
1164 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1165                          packet_info *pinfo, proto_tree *tree,
1166                          gboolean uses_inactive_subset,
1167                          gboolean *subdissector_found)
1168 {
1169
1170   /* CC & CR decoding in the same function */
1171
1172   proto_tree *cotp_tree = NULL;
1173   proto_item *ti;
1174   proto_item *item = NULL;
1175   guint16 dst_ref, src_ref;
1176   guchar  class_option;
1177   tvbuff_t *next_tvb;
1178
1179   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1180
1181   class_option = tvb_get_guint8(tvb, offset + P_CLASS_OPTION);
1182   if (((class_option & 0xF0) >> 4) > 4) /* class 0..4 allowed */
1183     return -1;
1184
1185   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1186   pinfo->clnp_srcref = src_ref;
1187   pinfo->clnp_dstref = dst_ref;
1188
1189   if (check_col(pinfo->cinfo, COL_INFO))
1190     col_append_fstr(pinfo->cinfo, COL_INFO,
1191                  "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1192                  (tpdu == CR_TPDU) ? "CR" : "CC",
1193                  src_ref,
1194                  dst_ref);
1195
1196   if (tree) {
1197     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1198     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1199     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1200   }
1201   offset += 1;
1202
1203   if (tree) {
1204     item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1205   }
1206   offset += 1;
1207   li -= 1;
1208
1209   if (tree)
1210     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1211   offset += 2;
1212   li -= 2;
1213
1214   if (tree)
1215     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1216   offset += 2;
1217   li -= 2;
1218
1219   /* expert info, but only if not encapsulated in TCP/SMB */
1220   /* XXX - the best way to detect seems to be if we have a port set */
1221   if (pinfo->destport == 0) {
1222           expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1223                   tpdu == CR_TPDU ? "Connection Request(CR): 0x%x -> 0x%x" : "Connection Confirm(CC): 0x%x -> 0x%x",
1224                   src_ref, dst_ref);
1225   }
1226
1227   if (tree) {
1228     proto_tree_add_uint(cotp_tree, hf_cotp_class, tvb, offset, 1, class_option);
1229     proto_tree_add_boolean(cotp_tree, hf_cotp_opts_extended_formats, tvb, offset, 1, class_option);
1230     proto_tree_add_boolean(cotp_tree, hf_cotp_opts_no_explicit_flow_control, tvb, offset, 1, class_option);
1231   }
1232   offset += 1;
1233   li -= 1;
1234
1235   if (tree)
1236     ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1237   offset += li;
1238
1239   next_tvb = tvb_new_subset_remaining(tvb, offset);
1240   if (!uses_inactive_subset){
1241     if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1242                                 pinfo, tree)) {
1243       *subdissector_found = TRUE;
1244     } else {
1245       call_dissector(data_handle,next_tvb, pinfo, tree);
1246     }
1247   }
1248   else
1249     call_dissector(data_handle, next_tvb, pinfo, tree);
1250   offset += tvb_length_remaining(tvb, offset);
1251      /* we dissected all of the containing PDU */
1252
1253   return offset;
1254
1255 } /* ositp_decode_CC */
1256
1257 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1258                          packet_info *pinfo, proto_tree *tree)
1259 {
1260   proto_tree *cotp_tree = NULL;
1261   proto_item *ti;
1262   proto_item *item = NULL;
1263   guint16 dst_ref, src_ref;
1264
1265   if (li > LI_MAX_DC)
1266     return -1;
1267
1268   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1269   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1270   pinfo->clnp_dstref = dst_ref;
1271   pinfo->clnp_dstref = src_ref;
1272
1273   if (check_col(pinfo->cinfo, COL_INFO))
1274     col_append_fstr(pinfo->cinfo, COL_INFO,
1275                  "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1276                  src_ref,
1277                  dst_ref);
1278
1279   if (tree) {
1280     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1281     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1282     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1283   }
1284   offset += 1;
1285
1286   if (tree) {
1287     item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1288   }
1289   offset += 1;
1290   li -= 1;
1291
1292   if (tree)
1293     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1294   offset += 2;
1295   li -= 2;
1296
1297   if (tree)
1298     proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1299   offset += 2;
1300   li -= 2;
1301
1302   if (tree)
1303     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1304   offset += li;
1305
1306   expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT,
1307           "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref);
1308
1309   return offset;
1310
1311 } /* ositp_decode_DC */
1312
1313 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1314                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1315 {
1316   proto_tree *cotp_tree = NULL;
1317   proto_item *ti;
1318   guint16    dst_ref;
1319   guint      tpdu_nr;
1320   gushort    cdt_in_ak;
1321
1322   if (li > LI_MAX_AK)
1323     return -1;
1324
1325   if (is_LI_NORMAL_AK(li)) {
1326
1327     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1328     tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1329     pinfo->clnp_dstref = dst_ref;
1330
1331     if (check_col(pinfo->cinfo, COL_INFO))
1332       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1333                    tpdu_nr, dst_ref);
1334
1335     if (tree) {
1336       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1337       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1338       proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1339     }
1340     offset += 1;
1341
1342     if (tree) {
1343       proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1344       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1345                           "Credit: %u", cdt);
1346     }
1347     offset += 1;
1348     li -= 1;
1349
1350     if (tree)
1351       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1352     offset += 2;
1353     li -= 2;
1354
1355     if (tree) {
1356       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1357                           tpdu_nr);
1358     }
1359     offset += 1;
1360     li -= 1;
1361
1362     if (tree)
1363       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1364     offset += li;
1365
1366   } else { /* extended format */
1367
1368     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1369     tpdu_nr   = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1370     cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1371     pinfo->clnp_dstref = dst_ref;
1372
1373     if (check_col(pinfo->cinfo, COL_INFO))
1374       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x Credit: %u",
1375                    tpdu_nr, dst_ref, cdt_in_ak);
1376
1377     if (tree) {
1378       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1379       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1380       proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1381     }
1382     offset += 1;
1383
1384     if (tree) {
1385       proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1386     }
1387     offset += 1;
1388     li -= 1;
1389
1390     if (tree)
1391       proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1392     offset += 2;
1393     li -= 2;
1394
1395     if (tree) {
1396       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1397                           offset, 4, tpdu_nr);
1398     }
1399     offset += 4;
1400     li -= 4;
1401
1402     if (tree) {
1403       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1404                           "Credit: 0x%04x", cdt_in_ak);
1405     }
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   } /* is_LI_NORMAL_AK */
1414
1415   return offset;
1416
1417 } /* ositp_decode_AK */
1418
1419 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1420                          packet_info *pinfo, proto_tree *tree)
1421 {
1422   proto_tree *cotp_tree = NULL;
1423   proto_item *ti;
1424   gboolean is_extended;
1425   guint16  dst_ref;
1426   guint    tpdu_nr;
1427
1428   if (li > LI_MAX_EA)
1429     return -1;
1430
1431   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1432      (This means we may misdissect this if the packet is bad and
1433      contains other parameters.) */
1434   switch (li) {
1435
1436     case LI_NORMAL_EA_WITH_CHECKSUM      :
1437       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1438                 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1439         return -1;
1440       /* FALLTHROUGH */
1441
1442     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1443       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1444       is_extended = FALSE;
1445       break;
1446
1447     case LI_EXTENDED_EA_WITH_CHECKSUM    :
1448       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1449                 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1450         return -1;
1451       /* FALLTHROUGH */
1452
1453     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1454       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1455       is_extended = TRUE;
1456       break;
1457
1458     default : /* bad TPDU */
1459       return -1;
1460   } /* li */
1461
1462   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1463   pinfo->clnp_dstref = dst_ref;
1464
1465   if (check_col(pinfo->cinfo, COL_INFO))
1466     col_append_fstr(pinfo->cinfo, COL_INFO,
1467                  "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1468
1469   if (tree) {
1470     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1471     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1472     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1473   }
1474   offset += 1;
1475
1476   if (tree) {
1477     proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu);
1478   }
1479   offset += 1;
1480   li -= 1;
1481
1482   if (tree)
1483     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1484   offset += 2;
1485   li -= 2;
1486
1487   if (is_extended) {
1488     if (tree) {
1489       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number_extended, tvb,
1490                           offset, 4, tpdu_nr);
1491     }
1492     offset += 4;
1493     li -= 4;
1494   } else {
1495     if (tree) {
1496       proto_tree_add_uint(cotp_tree, hf_cotp_next_tpdu_number, tvb, offset, 1,
1497                           tpdu_nr);
1498     }
1499     offset += 1;
1500     li -= 1;
1501   }
1502
1503   if (tree)
1504     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1505   offset += li;
1506
1507   return offset;
1508
1509 } /* ositp_decode_EA */
1510
1511 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1512                          packet_info *pinfo, proto_tree *tree)
1513 {
1514   proto_tree *cotp_tree;
1515   proto_item *ti;
1516   const char *str;
1517   guint16 dst_ref;
1518
1519   if (li > LI_MAX_ER)
1520     return -1;
1521
1522   switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1523     case 0 :
1524       str = "Reason not specified";
1525       break;
1526     case 1 :
1527       str = "Invalid parameter code";
1528       break;
1529     case 2 :
1530       str = "Invalid TPDU type";
1531       break;
1532     case 3 :
1533       str = "Invalid parameter value";
1534       break;
1535     default:
1536       return -1;
1537   }
1538
1539   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1540   pinfo->clnp_dstref = dst_ref;
1541
1542   if (check_col(pinfo->cinfo, COL_INFO))
1543     col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1544
1545   if (tree) {
1546     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1547     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1548     proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li);
1549     proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset +  1, 1, tpdu);
1550     proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset +  2, 2, dst_ref);
1551     proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1552                         "Reject cause: %s", str);
1553   }
1554
1555   offset += li + 1;
1556
1557   return offset;
1558
1559 } /* ositp_decode_ER */
1560
1561 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1562                          packet_info *pinfo, proto_tree *tree,
1563                          gboolean *subdissector_found)
1564 {
1565   proto_item *ti;
1566   proto_tree *cltp_tree = NULL;
1567   tvbuff_t   *next_tvb;
1568
1569   col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1570
1571   if (tree) {
1572     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, ENC_BIG_ENDIAN);
1573     cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1574     proto_tree_add_uint(cltp_tree, hf_cltp_li, tvb, offset, 1,li);
1575   }
1576   offset += 1;
1577
1578   if (tree) {
1579     proto_tree_add_uint(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu);
1580   }
1581   offset += 1;
1582   li -= 1;
1583
1584   if (tree)
1585     ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1586   offset += li;
1587
1588   next_tvb = tvb_new_subset_remaining(tvb, offset);
1589
1590   if (dissector_try_heuristic(cltp_heur_subdissector_list, next_tvb,
1591                           pinfo, tree)) {
1592     *subdissector_found = TRUE;
1593   } else {
1594     call_dissector(data_handle,next_tvb, pinfo, tree);
1595   }
1596
1597
1598   /*call_dissector(data_handle,next_tvb, pinfo, tree); */
1599
1600
1601
1602   offset += tvb_length_remaining(tvb, offset);
1603      /* we dissected all of the containing PDU */
1604
1605   return offset;
1606
1607 } /* ositp_decode_UD */
1608
1609 /* Returns the offset past the last valid COTP or CLTP PDU if we found
1610    at least one valid COTP or CLTP PDU, 0 otherwise.
1611
1612    There doesn't seem to be any way in which the OSI network layer protocol
1613    distinguishes between COTP and CLTP, but the first two octets of both
1614    protocols' headers mean the same thing - length and PDU type - and the
1615    only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1616    both of them here. */
1617 static gint dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1618                   proto_tree *tree, gboolean uses_inactive_subset)
1619 {
1620   int offset = 0;
1621   guint8 li, tpdu, cdt;
1622   gboolean first_tpdu = TRUE;
1623   int new_offset;
1624   gboolean found_ositp = FALSE;
1625   gboolean is_cltp = FALSE;
1626   gboolean subdissector_found = FALSE;
1627
1628   if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1629     return FALSE;       /* COTP has been disabled */
1630   /* XXX - what about CLTP? */
1631
1632   pinfo->current_proto = "COTP";
1633
1634   /* Initialize the COL_INFO field; each of the TPDUs will have its
1635      information appended. */
1636   if (check_col(pinfo->cinfo, COL_INFO))
1637     col_set_str(pinfo->cinfo, COL_INFO, "");
1638
1639   while (tvb_offset_exists(tvb, offset)) {
1640     if (!first_tpdu) {
1641       col_append_str(pinfo->cinfo, COL_INFO, ", ");
1642           expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple TPDUs in one packet");
1643     }
1644     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1645       col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1646       if (!first_tpdu)
1647         call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset),
1648                        pinfo, tree);
1649       return found_ositp;
1650     }
1651
1652     tpdu    = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1653     if (tpdu == UD_TPDU)
1654       pinfo->current_proto = "CLTP";    /* connectionless transport */
1655     cdt     = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1656
1657     switch (tpdu) {
1658       case CC_TPDU :
1659       case CR_TPDU :
1660         new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1661                                      uses_inactive_subset, &subdissector_found);
1662         break;
1663       case DR_TPDU :
1664         new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1665         break;
1666       case DT_TPDU :
1667         new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1668                                    uses_inactive_subset, &subdissector_found);
1669         break;
1670       case ED_TPDU :
1671         new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1672         break;
1673       case RJ_TPDU :
1674         new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1675         break;
1676       case DC_TPDU :
1677         new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1678         break;
1679       case AK_TPDU :
1680         new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1681         break;
1682       case EA_TPDU :
1683         new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1684         break;
1685       case ER_TPDU :
1686         new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1687         break;
1688       case UD_TPDU :
1689         new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree, &subdissector_found);
1690         is_cltp = TRUE;
1691         break;
1692       default      :
1693         if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1694           col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1695         new_offset = -1;        /* bad PDU type */
1696         break;
1697     }
1698
1699     if (new_offset == -1) { /* incorrect TPDU */
1700       if (!first_tpdu)
1701         call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset),
1702                        pinfo, tree);
1703       break;
1704     }
1705
1706     if (first_tpdu) {
1707       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1708          is either COTP or CLTP. */
1709       if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1710         col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1711       found_ositp = TRUE;
1712     }
1713
1714     offset = new_offset;
1715     first_tpdu = FALSE;
1716   }
1717   return found_ositp ? offset : 0;
1718 } /* dissect_ositp_internal */
1719
1720 static gint dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1721 {
1722   return dissect_ositp_internal(tvb, pinfo, tree, FALSE);
1723 }
1724
1725 static gint dissect_ositp_inactive(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1726 {
1727   return dissect_ositp_internal(tvb, pinfo, tree, TRUE);
1728 }
1729
1730 static void
1731 cotp_reassemble_init(void)
1732 {
1733   fragment_table_init(&cotp_segment_table);
1734   reassembled_table_init(&cotp_reassembled_table);
1735   cotp_dst_ref = 0;
1736 }
1737
1738 void proto_register_cotp(void)
1739 {
1740   static hf_register_info hf[] = {
1741     { &hf_cotp_li,
1742       { "Length", "cotp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
1743         "Length Indicator, length of this header", HFILL}},
1744     { &hf_cotp_type,
1745       { "PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
1746         "PDU Type - upper nibble of byte", HFILL}},
1747     { &hf_cotp_srcref,
1748       { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
1749         "Source address reference", HFILL}},
1750     { &hf_cotp_destref,
1751       { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
1752         "Destination address reference", HFILL}},
1753     { &hf_cotp_class,
1754       { "Class", "cotp.class", FT_UINT8, BASE_DEC, NULL, 0xF0,
1755         "Transport protocol class", HFILL}},
1756     { &hf_cotp_opts_extended_formats,
1757       { "Extended formats", "cotp.opts.extended_formats", FT_BOOLEAN, 8, NULL, 0x02,
1758         "Use of extended formats in classes 2, 3, and 4", HFILL}},
1759     { &hf_cotp_opts_no_explicit_flow_control,
1760       { "No explicit flow control", "cotp.opts.no_explicit_flow_control", FT_BOOLEAN, 8, NULL, 0x01,
1761         "No explicit flow control in class 2", HFILL}},
1762     { &hf_cotp_tpdu_number,
1763       { "TPDU number", "cotp.tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x7f,
1764         NULL, HFILL}},
1765     { &hf_cotp_tpdu_number_extended,
1766       { "TPDU number", "cotp.tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0 /* XXX - 0x7fff? */,
1767         NULL, HFILL}},
1768     { &hf_cotp_next_tpdu_number,
1769       { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT8, BASE_HEX, NULL, 0x0,
1770         NULL, HFILL}},
1771     { &hf_cotp_next_tpdu_number_extended,
1772       { "Your TPDU number", "cotp.next-tpdu-number", FT_UINT32, BASE_HEX, NULL, 0x0,
1773         NULL, HFILL}},
1774     { &hf_cotp_eot,
1775       { "Last data unit", "cotp.eot", FT_BOOLEAN, 8, TFS(&fragment_descriptions),  0x80,
1776         "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
1777     { &hf_cotp_eot_extended,
1778       { "Last data unit", "cotp.eot", FT_BOOLEAN, 32, TFS(&fragment_descriptions),  0x80000000,
1779         "Is current TPDU the last data unit of a complete DT TPDU sequence (End of TSDU)?", HFILL}},
1780     { &hf_cotp_segment_overlap,
1781       { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1782         "Segment overlaps with other segments", HFILL }},
1783     { &hf_cotp_segment_overlap_conflict,
1784       { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1785         "Overlapping segments contained conflicting data", HFILL }},
1786     { &hf_cotp_segment_multiple_tails,
1787       { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1788         "Several tails were found when reassembling the packet", HFILL }},
1789     { &hf_cotp_segment_too_long_segment,
1790       { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1791         "Segment contained data past end of packet", HFILL }},
1792     { &hf_cotp_segment_error,
1793       { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1794         "Reassembly error due to illegal segments", HFILL }},
1795     { &hf_cotp_segment,
1796       { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1797         NULL, HFILL }},
1798     { &hf_cotp_segments,
1799       { "COTP Segments", "cotp.segments", FT_NONE, BASE_NONE, NULL, 0x0,
1800         NULL, HFILL }},
1801     { &hf_cotp_reassembled_in,
1802       { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1803         "This COTP packet is reassembled in this frame", HFILL }},
1804     { &hf_cotp_reassembled_length,
1805       { "Reassembled COTP length", "cotp.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
1806         "The total length of the reassembled payload", HFILL }},
1807 /* ISO DP 8073 i13.3.4(a) Source and destination TSAPs are defined as
1808    identifiers of unspecified type and length.
1809    Some implementations of COTP use printable strings, others use raw bytes.
1810    We always add both representations to the tree; one will always be hidden
1811    depending on the tsap display preference */
1812     { &hf_cotp_vp_src_tsap,
1813       { "Source TSAP", "cotp.src-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
1814         "Calling TSAP", HFILL }},
1815     { &hf_cotp_vp_src_tsap_bytes,
1816       { "Source TSAP", "cotp.src-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
1817         "Calling TSAP (bytes representation)", HFILL }},
1818     { &hf_cotp_vp_dst_tsap,
1819       { "Destination TSAP", "cotp.dst-tsap", FT_STRING, BASE_NONE, NULL, 0x0,
1820         "Called TSAP", HFILL }},
1821     { &hf_cotp_vp_dst_tsap_bytes,
1822       { "Destination TSAP", "cotp.dst-tsap-bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
1823         "Called TSAP (bytes representation)", HFILL }},
1824
1825   };
1826   static gint *ett[] = {
1827         &ett_cotp,
1828         &ett_cotp_segment,
1829         &ett_cotp_segments,
1830   };
1831
1832   module_t *cotp_module;
1833
1834   proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
1835   proto_register_field_array(proto_cotp, hf, array_length(hf));
1836   proto_register_subtree_array(ett, array_length(ett));
1837   cotp_module = prefs_register_protocol(proto_cotp, NULL);
1838
1839   prefs_register_bool_preference(cotp_module, "reassemble",
1840          "Reassemble segmented COTP datagrams",
1841          "Whether segmented COTP datagrams should be reassembled."
1842          " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1843         &cotp_reassemble);
1844
1845   prefs_register_enum_preference(cotp_module, "tsap_display",
1846          "Display TSAPs as strings or bytes",
1847          "How TSAPs should be displayed",
1848         &tsap_display,
1849         tsap_display_options,
1850         FALSE);
1851
1852   /* subdissector code in inactive subset */
1853   register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
1854
1855   /* other COTP/ISO 8473 subdissectors */
1856   register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
1857
1858   /* XXX - what about CLTP and proto_cltp? */
1859   new_register_dissector("ositp", dissect_ositp, proto_cotp);
1860   new_register_dissector("ositp_inactive", dissect_ositp_inactive, proto_cotp);
1861
1862   register_init_routine(cotp_reassemble_init);
1863 }
1864
1865 void proto_register_cltp(void)
1866 {
1867   static hf_register_info hf[] = {
1868     { &hf_cltp_li,
1869       { "Length", "cltp.li", FT_UINT8, BASE_DEC, NULL, 0x0,
1870         "Length Indicator, length of this header", HFILL}},
1871     { &hf_cltp_type,
1872       { "PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
1873         NULL, HFILL}},
1874   };
1875   static gint *ett[] = {
1876         &ett_cltp,
1877   };
1878
1879   proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
1880   proto_register_field_array(proto_cltp, hf, array_length(hf));
1881   proto_register_subtree_array(ett, array_length(ett));
1882
1883   register_heur_dissector_list("cltp", &cltp_heur_subdissector_list);
1884
1885 }
1886
1887 void
1888 proto_reg_handoff_cotp(void)
1889 {
1890   dissector_handle_t ositp_handle;
1891
1892   ositp_handle = find_dissector("ositp");
1893   dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle);
1894
1895   data_handle = find_dissector("data");
1896
1897   proto_clnp = proto_get_id_by_filter_name("clnp");
1898 }
1899