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