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