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