Moved the value_string for MS country codes from packet-dcerpc-nt.c to
[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.50 2002/02/27 05:45: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                          gboolean *subdissector_found)
1410 {
1411   proto_item *ti;
1412   proto_tree *cltp_tree = NULL;
1413   tvbuff_t   *next_tvb;
1414
1415   if (check_col(pinfo->cinfo, COL_INFO))
1416     col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1417
1418   if (tree) {
1419     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1420     cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1421     proto_tree_add_text(cltp_tree, tvb, offset, 1,
1422                         "Length indicator: %u", li);
1423   }
1424   offset += 1;
1425
1426   if (tree) {
1427     proto_tree_add_text(cltp_tree, tvb, offset, 1, 
1428                         "TPDU code: 0x%x (UD)", tpdu);
1429   }
1430   offset += 1;
1431   li -= 1;
1432
1433   if (tree)
1434     osi_decode_tp_var_part(tvb, offset, li, 0, cltp_tree);
1435   offset += li;
1436
1437   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1438   call_dissector(data_handle,next_tvb, pinfo, tree);
1439   offset += tvb_length_remaining(tvb, offset);
1440      /* we dissected all of the containing PDU */
1441
1442   return offset;
1443
1444 } /* osi_decode_UD */
1445
1446 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1447    otherwise.
1448
1449    There doesn't seem to be any way in which the OSI network layer protocol
1450    distinguishes between COTP and CLTP, but the first two octets of both
1451    protocols' headers mean the same thing - length and PDU type - and the
1452    only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1453    both of them here. */
1454 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1455                   proto_tree *tree, gboolean uses_inactive_subset) 
1456 {
1457   int offset = 0;
1458   gboolean first_tpdu = TRUE;
1459   int new_offset;
1460   gboolean found_ositp = FALSE;
1461   gboolean is_cltp = FALSE;
1462   gboolean subdissector_found = FALSE;
1463
1464   if (!proto_is_protocol_enabled(proto_cotp))
1465     return FALSE;       /* COTP has been disabled */
1466   /* XXX - what about CLTP? */
1467
1468   pinfo->current_proto = "COTP";
1469
1470   /* Initialize the COL_INFO field; each of the TPDUs will have its
1471      information appended. */
1472   if (check_col(pinfo->cinfo, COL_INFO))
1473     col_add_str(pinfo->cinfo, COL_INFO, "");
1474
1475   while (tvb_offset_exists(tvb, offset)) {
1476     if (!first_tpdu) {
1477       if (check_col(pinfo->cinfo, COL_INFO))
1478         col_append_str(pinfo->cinfo, COL_INFO, ", ");
1479     }
1480     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1481       if (check_col(pinfo->cinfo, COL_INFO))
1482         col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1483       if (!first_tpdu)
1484         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1485       return found_ositp;
1486     }
1487
1488     tpdu    = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1489     if (tpdu == UD_TPDU)
1490       pinfo->current_proto = "CLTP";    /* connectionless transport */
1491     cdt     = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1492     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1493
1494     switch (tpdu) {
1495       case CC_TPDU :
1496       case CR_TPDU :
1497         new_offset = osi_decode_CC(tvb, offset, pinfo, tree);
1498         break;
1499       case DR_TPDU :
1500         new_offset = osi_decode_DR(tvb, offset, pinfo, tree);
1501         break;
1502       case DT_TPDU :
1503         new_offset = osi_decode_DT(tvb, offset, pinfo, tree,
1504                                    uses_inactive_subset, &subdissector_found);
1505         break;
1506       case ED_TPDU :
1507         new_offset = osi_decode_ED(tvb, offset, pinfo, tree);
1508         break;
1509       case RJ_TPDU :
1510         new_offset = osi_decode_RJ(tvb, offset, pinfo, tree);
1511         break;
1512       case DC_TPDU :
1513         new_offset = osi_decode_DC(tvb, offset, pinfo, tree);
1514         break;
1515       case AK_TPDU :
1516         new_offset = osi_decode_AK(tvb, offset, pinfo, tree);
1517         break;
1518       case EA_TPDU :
1519         new_offset = osi_decode_EA(tvb, offset, pinfo, tree);
1520         break;
1521       case ER_TPDU :
1522         new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
1523         break;
1524       case UD_TPDU :
1525         new_offset = osi_decode_UD(tvb, offset, pinfo, tree,
1526                                    &subdissector_found);
1527         is_cltp = TRUE;
1528         break;
1529       default      :
1530         if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1531           col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1532         new_offset = -1;        /* bad PDU type */
1533         break;
1534     }
1535
1536     if (new_offset == -1) { /* incorrect TPDU */
1537       if (!first_tpdu)
1538         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1539       break;
1540     }
1541
1542     if (first_tpdu) {
1543       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1544          is either COTP or CLTP. */
1545       if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1546         col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1547       found_ositp = TRUE;
1548     }
1549
1550     offset = new_offset;
1551     first_tpdu = FALSE;
1552   }
1553   return found_ositp;
1554 } /* dissect_ositp_internal */
1555
1556 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
1557 {
1558   if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1559     call_dissector(data_handle,tvb, pinfo, tree);
1560 }
1561
1562
1563 /*
1564  *  CLNP part / main entry point 
1565 */
1566
1567 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1568 {
1569   proto_tree *clnp_tree = NULL;
1570   proto_item *ti;
1571   guint8      cnf_proto_id;
1572   guint8      cnf_hdr_len;
1573   guint8      cnf_vers;
1574   guint8      cnf_ttl;
1575   guint8      cnf_type;
1576   char        flag_string[6+1];
1577   char       *pdu_type_string;
1578   proto_tree *type_tree;
1579   guint16     segment_length;
1580   guint16     du_id = 0;
1581   guint16     segment_offset = 0;
1582   guint16     cnf_cksum;
1583   cksum_status_t cksum_status;
1584   int         offset;
1585   u_char      src_len, dst_len, nsel, opt_len = 0;
1586   const guint8     *dst_addr, *src_addr;
1587   gint        len;
1588   guint       next_length;
1589   proto_tree *discpdu_tree;
1590   volatile address save_dl_src;
1591   volatile address save_dl_dst;
1592   volatile address save_net_src;
1593   volatile address save_net_dst;
1594   volatile address save_src;
1595   volatile address save_dst;
1596   gboolean    save_in_error_pkt;
1597   fragment_data *fd_head;
1598   tvbuff_t   *volatile next_tvb;
1599   gboolean    update_col_info = TRUE;
1600   gboolean    save_fragmented;
1601
1602   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1603     col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1604   if (check_col(pinfo->cinfo, COL_INFO))
1605     col_clear(pinfo->cinfo, COL_INFO);
1606
1607   cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1608   if (cnf_proto_id == NLPID_NULL) {
1609     if (check_col(pinfo->cinfo, COL_INFO))
1610       col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1611     if (tree) {
1612       ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1613       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1614       proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, 
1615                                  cnf_proto_id,
1616                                  "Inactive subset");
1617     } 
1618     next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1619     dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1620     return;
1621   } 
1622  
1623   /* return if version not known */
1624   cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1625   if (cnf_vers != ISO8473_V1) {
1626     call_dissector(data_handle,tvb, pinfo, tree);
1627     return;
1628   }
1629
1630   /* fixed part decoding */
1631   cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1632   opt_len = cnf_hdr_len;
1633
1634   if (tree) {
1635     ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1636     clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1637     proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, 
1638                                cnf_proto_id);
1639     proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, 
1640                         cnf_hdr_len); 
1641     proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1, 
1642                         cnf_vers);
1643     cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1644     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1, 
1645                                cnf_ttl,
1646                                "Holding Time : %u (%u.%u secs)", 
1647                                cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1648   }
1649
1650   cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1651   pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1652                                 "Unknown (0x%02x)");
1653   flag_string[0] = '\0';
1654   if (cnf_type & CNF_SEG_OK)
1655     strcat(flag_string, "S ");
1656   if (cnf_type & CNF_MORE_SEGS)
1657     strcat(flag_string, "M ");
1658   if (cnf_type & CNF_ERR_OK)
1659     strcat(flag_string, "E ");
1660   if (tree) {
1661     ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1662                                cnf_type,
1663                                "PDU Type     : 0x%02x (%s%s)",
1664                                cnf_type,
1665                                flag_string,
1666                                pdu_type_string);
1667     type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1668     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1669                         decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1670                                       "Segmentation permitted",
1671                                       "Segmentation not permitted"));
1672     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1673                         decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1674                                       "More segments",
1675                                       "Last segment"));
1676     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1677                         decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1678                                       "Report error if PDU discarded",
1679                                       "Don't report error if PDU discarded"));
1680     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1681                         decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1682                                       npdu_type_vals, "%s"));
1683   }
1684
1685   /* If we don't have the full header - i.e., not enough to see the
1686      segmentation part and determine whether this datagram is segmented
1687      or not - set the Info column now; we'll get an exception before
1688      we set it otherwise. */
1689
1690   if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1691     if (check_col(pinfo->cinfo, COL_INFO))
1692       col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1693   }
1694
1695   segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1696   cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1697   cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1698   if (tree) {
1699     proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1700                         segment_length);
1701     switch (cksum_status) {
1702
1703     default:
1704         /*
1705          * No checksum present, or not enough of the header present to
1706          * checksum it.
1707          */
1708         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1709                                P_CLNP_CKSUM, 2,
1710                                cnf_cksum,
1711                                "Checksum     : 0x%04x",
1712                                cnf_cksum);
1713         break;
1714
1715     case CKSUM_OK:
1716         /*
1717          * Checksum is correct.
1718          */
1719         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1720                                P_CLNP_CKSUM, 2,
1721                                cnf_cksum,
1722                                "Checksum     : 0x%04x (correct)",
1723                                cnf_cksum);
1724         break;
1725
1726     case CKSUM_NOT_OK:
1727         /*
1728          * Checksum is not correct.
1729          */
1730         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1731                                P_CLNP_CKSUM, 2,
1732                                cnf_cksum,
1733                                "Checksum     : 0x%04x (incorrect)",
1734                                cnf_cksum);
1735         break;
1736     }
1737     opt_len -= 9; /* Fixed part of Hesder */
1738   } /* tree */
1739
1740   /* address part */
1741   
1742   offset = P_CLNP_ADDRESS_PART;
1743   dst_len  = tvb_get_guint8(tvb, offset);
1744   dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1745   nsel     = tvb_get_guint8(tvb, offset + dst_len);
1746   src_len  = tvb_get_guint8(tvb, offset + dst_len + 1);
1747   src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1748
1749   if (tree) {
1750     proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, 
1751                         dst_len);
1752     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len, 
1753                                dst_addr,
1754                                " DA : %s", 
1755                                print_nsap_net(dst_addr, dst_len));
1756     proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, 
1757                         offset + 1 + dst_len, 1, src_len);
1758     proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb, 
1759                                offset + dst_len + 2, src_len,
1760                                src_addr,
1761                                " SA : %s", 
1762                                print_nsap_net(src_addr, src_len));
1763
1764     opt_len -= dst_len + src_len +2;
1765   }
1766
1767   SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1768   SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1769   SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1770   SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1771
1772   /* Segmentation Part */
1773
1774   offset += dst_len + src_len + 2;
1775
1776   if (cnf_type & CNF_SEG_OK) {
1777     struct clnp_segment seg;                    /* XXX - not used */
1778     tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg));       /* XXX - not used */
1779     
1780     segment_offset = tvb_get_ntohs(tvb, offset + 2);
1781     du_id = tvb_get_ntohs(tvb, offset);
1782     if (tree) {
1783       proto_tree_add_text(clnp_tree, tvb, offset, 2, 
1784                         "Data unit identifier: %06u",
1785                         du_id);
1786       proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1787                         "Segment offset      : %6u", 
1788                         segment_offset);
1789       proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1790                         "Total length        : %6u", 
1791                         tvb_get_ntohs(tvb, offset + 4));
1792     }
1793     
1794     offset  += 6;
1795     opt_len -= 6;
1796   }
1797
1798   if (tree) {
1799     /* To do : decode options  */
1800 /*
1801     proto_tree_add_text(clnp_tree, tvb, offset, 
1802                         cnf_hdr_len - offset,
1803                         "Options/Data: <not shown>");
1804 */
1805 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1806
1807     dissect_osi_options( 0xff, 
1808                          opt_len,
1809                          tvb, offset, pinfo, clnp_tree ); 
1810   }
1811
1812   /* Length of CLNP datagram plus headers above it. */
1813   len = segment_length;
1814
1815   offset = cnf_hdr_len;
1816
1817   /* If clnp_reassemble is on, and this is a segment, we have all the
1818    * data in the segment, and the checksum is valid, then just add the
1819    * segment to the hashtable.
1820    */
1821   save_fragmented = pinfo->fragmented;
1822   if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1823         ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1824         (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1825         cksum_status != CKSUM_NOT_OK) {
1826     fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1827                            segment_offset, segment_length - cnf_hdr_len,
1828                            cnf_type & CNF_MORE_SEGS);
1829
1830     if (fd_head != NULL) {
1831       fragment_data *fd;
1832       proto_tree *ft=NULL;
1833       proto_item *fi=NULL;
1834
1835       /* OK, we have the complete reassembled payload. */
1836       /* show all segments */
1837       fi = proto_tree_add_item(clnp_tree, hf_clnp_segments, 
1838                 tvb, 0, 0, FALSE);
1839       ft = proto_item_add_subtree(fi, ett_clnp_segments);
1840       for (fd = fd_head->next; fd != NULL; fd = fd->next){
1841         if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
1842                           |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1843           /* this segment has some flags set, create a subtree 
1844            * for it and display the flags.
1845            */
1846           proto_tree *fet = NULL;
1847           proto_item *fei = NULL;
1848           int hf;
1849
1850           if (fd->flags & (FD_OVERLAPCONFLICT
1851                       |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1852             hf = hf_clnp_segment_error;
1853           } else {
1854             hf = hf_clnp_segment;
1855           }
1856           fei = proto_tree_add_none_format(ft, hf, 
1857                    tvb, 0, 0,
1858                    "Frame:%u payload:%u-%u",
1859                    fd->frame,
1860                    fd->offset,
1861                    fd->offset+fd->len-1
1862           );
1863           fet = proto_item_add_subtree(fei, ett_clnp_segment);
1864           if (fd->flags&FD_OVERLAP) {
1865             proto_tree_add_boolean(fet, 
1866                  hf_clnp_segment_overlap, tvb, 0, 0, 
1867                  TRUE);
1868           }
1869           if (fd->flags&FD_OVERLAPCONFLICT) {
1870             proto_tree_add_boolean(fet, 
1871                  hf_clnp_segment_overlap_conflict, tvb, 0, 0, 
1872                  TRUE);
1873           }
1874           if (fd->flags&FD_MULTIPLETAILS) {
1875             proto_tree_add_boolean(fet, 
1876                  hf_clnp_segment_multiple_tails, tvb, 0, 0, 
1877                  TRUE);
1878           }
1879           if (fd->flags&FD_TOOLONGFRAGMENT) {
1880             proto_tree_add_boolean(fet, 
1881                  hf_clnp_segment_too_long_segment, tvb, 0, 0, 
1882                  TRUE);
1883           }
1884         } else {
1885           /* nothing of interest for this segment */
1886           proto_tree_add_none_format(ft, hf_clnp_segment, 
1887                    tvb, 0, 0,
1888                    "Frame:%u payload:%u-%u",
1889                    fd->frame,
1890                    fd->offset,
1891                    fd->offset+fd->len-1
1892           );
1893         }
1894       }
1895       if (fd_head->flags & (FD_OVERLAPCONFLICT
1896                         |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1897         if (check_col(pinfo->cinfo, COL_INFO)) {
1898           col_set_str(pinfo->cinfo, COL_INFO, "[Illegal segments]");
1899           update_col_info = FALSE;
1900         }
1901       }
1902
1903       /* Allocate a new tvbuff, referring to the reassembled payload. */
1904       next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1905         fd_head->datalen);
1906
1907       /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1908          were handed refers, so it'll get cleaned up when that tvbuff
1909          is cleaned up. */
1910       tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1911
1912       /* Add the defragmented data to the data source list. */
1913       add_new_data_source(pinfo->fd, next_tvb, "Reassembled CLNP");
1914
1915       /* It's not fragmented. */
1916       pinfo->fragmented = FALSE;
1917     } else {
1918       /* We don't have the complete reassembled payload. */
1919       next_tvb = NULL;
1920     }
1921   } else {
1922     /* If this is the first segment, dissect its contents, otherwise
1923        just show it as a segment.
1924
1925        XXX - if we eventually don't save the reassembled contents of all
1926        segmented datagrams, we may want to always reassemble. */
1927     if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1928       /* Not the first segment - don't dissect it. */
1929       next_tvb = NULL;
1930     } else {
1931       /* First segment, or not segmented.  Dissect what we have here. */
1932
1933       /* Get a tvbuff for the payload. */
1934       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1935
1936       /*
1937        * If this is the first segment, but not the only segment,
1938        * tell the next protocol that.
1939        */
1940       if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1941         pinfo->fragmented = TRUE;
1942       else
1943         pinfo->fragmented = FALSE;
1944     }
1945   }
1946
1947   if (next_tvb == NULL) {
1948     /* Just show this as a segment. */
1949     if (check_col(pinfo->cinfo, COL_INFO))
1950       col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1951                 pdu_type_string, flag_string, segment_offset);
1952
1953     /* As we haven't reassembled anything, we haven't changed "pi", so
1954        we don't have to restore it. */
1955     call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1956     pinfo->fragmented = save_fragmented;
1957     return;
1958   }
1959
1960   if (tvb_offset_exists(tvb, offset)) {
1961     switch (cnf_type & CNF_TYPE) {
1962
1963     case DT_NPDU:
1964     case MD_NPDU:
1965       /* Continue with COTP if any data.
1966          XXX - if this isn't the first Derived PDU of a segmented Initial
1967          PDU, skip that? */
1968
1969       if (nsel == (char)tp_nsap_selector || always_decode_transport) { 
1970         if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1971           pinfo->fragmented = save_fragmented;
1972           return;       /* yes, it appears to be COTP or CLTP */
1973         }
1974       }
1975       break;
1976
1977     case ER_NPDU:
1978       /* The payload is the header and "none, some, or all of the data
1979          part of the discarded PDU", i.e. it's like an ICMP error;
1980          dissect it as a CLNP PDU. */
1981       if (check_col(pinfo->cinfo, COL_INFO))
1982         col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1983       if (tree) {
1984         next_length = tvb_length_remaining(tvb, offset);
1985         if (next_length != 0) {
1986           /* We have payload; dissect it.
1987              Make the columns non-writable, so the packet isn't shown
1988              in the summary based on what the discarded PDU's contents
1989              are. */
1990           col_set_writable(pinfo->cinfo, FALSE);
1991
1992           /* Also, save the current values of the addresses, and restore
1993              them when we're finished dissecting the contained packet, so
1994              that the address columns in the summary don't reflect the
1995              contained packet, but reflect this packet instead. */
1996           save_dl_src = pinfo->dl_src;
1997           save_dl_dst = pinfo->dl_dst;
1998           save_net_src = pinfo->net_src;
1999           save_net_dst = pinfo->net_dst;
2000           save_src = pinfo->src;
2001           save_dst = pinfo->dst;
2002
2003           /* Save the current value of the "we're inside an error packet"
2004              flag, and set that flag; subdissectors may treat packets
2005              that are the payload of error packets differently from
2006              "real" packets. */
2007           save_in_error_pkt = pinfo->in_error_pkt;
2008           pinfo->in_error_pkt = TRUE;
2009
2010           /* Dissect the contained packet.
2011              Catch ReportedBoundsError, and do nothing if we see it,
2012              because it's not an error if the contained packet is short;
2013              there's no guarantee that all of it was included.
2014
2015              XXX - should catch BoundsError, and re-throw it after cleaning
2016              up. */
2017           ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2018             "Discarded PDU");
2019           discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2020           TRY {
2021             dissect_clnp(next_tvb, pinfo, discpdu_tree);
2022           }
2023           CATCH(ReportedBoundsError) {
2024             ; /* do nothing */
2025           }
2026           ENDTRY;
2027
2028           /* Restore the "we're inside an error packet" flag. */
2029           pinfo->in_error_pkt = save_in_error_pkt;
2030
2031           /* Restore the addresses. */
2032           pinfo->dl_src = save_dl_src;
2033           pinfo->dl_dst = save_dl_dst;
2034           pinfo->net_src = save_net_src;
2035           pinfo->net_dst = save_net_dst;
2036           pinfo->src = save_src;
2037           pinfo->dst = save_dst;
2038         }
2039       }
2040       pinfo->fragmented = save_fragmented;
2041       return;   /* we're done with this PDU */
2042
2043     case ERQ_NPDU:
2044     case ERP_NPDU:
2045       /* XXX - dissect this */
2046       break;
2047     }
2048   }
2049   if (check_col(pinfo->cinfo, COL_INFO))
2050     col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2051   call_dissector(data_handle,next_tvb, pinfo, tree);
2052   pinfo->fragmented = save_fragmented;
2053 } /* dissect_clnp */
2054
2055 static void
2056 clnp_reassemble_init(void)
2057 {
2058   fragment_table_init(&clnp_segment_table);
2059 }
2060
2061 void proto_register_clnp(void)
2062 {
2063   static hf_register_info hf[] = {
2064     { &hf_clnp_id,
2065       { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX, 
2066         VALS(nlpid_vals), 0x0, "", HFILL }},
2067
2068     { &hf_clnp_length,
2069       { "HDR Length   ", "clnp.len",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2070
2071     { &hf_clnp_version,
2072       { "Version      ", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2073
2074     { &hf_clnp_ttl,
2075       { "Holding Time ", "clnp.ttl",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2076
2077     { &hf_clnp_type,
2078       { "PDU Type     ", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2079
2080     { &hf_clnp_pdu_length,
2081       { "PDU length   ", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2082
2083     { &hf_clnp_checksum,
2084       { "Checksum     ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2085
2086     { &hf_clnp_dest_length,
2087       { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2088
2089     { &hf_clnp_dest,
2090       { " DA ", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2091
2092     { &hf_clnp_src_length,
2093       { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2094
2095     { &hf_clnp_src,
2096       { " SA ", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2097
2098     { &hf_clnp_segment_overlap,
2099       { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2100         "Segment overlaps with other segments", HFILL }},
2101
2102     { &hf_clnp_segment_overlap_conflict,
2103       { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2104         "Overlapping segments contained conflicting data", HFILL }},
2105
2106     { &hf_clnp_segment_multiple_tails,
2107       { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2108         "Several tails were found when reassembling the packet", HFILL }},
2109
2110     { &hf_clnp_segment_too_long_segment,
2111       { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2112         "Segment contained data past end of packet", HFILL }},
2113
2114     { &hf_clnp_segment_error,
2115       { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0,
2116         "Reassembly error due to illegal segments", HFILL }},
2117
2118     { &hf_clnp_segment,
2119       { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0,
2120         "CLNP Segment", HFILL }},
2121
2122     { &hf_clnp_segments,
2123       { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2124         "CLNP Segments", HFILL }},
2125   };
2126   static gint *ett[] = {
2127     &ett_clnp,
2128     &ett_clnp_type,
2129     &ett_clnp_segments,
2130     &ett_clnp_segment,
2131     &ett_clnp_disc_pdu,
2132   };
2133
2134   module_t *clnp_module;
2135
2136   proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2137   proto_register_field_array(proto_clnp, hf, array_length(hf));
2138   proto_register_subtree_array(ett, array_length(ett));
2139
2140   clnp_module = prefs_register_protocol(proto_clnp, NULL);
2141   prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2142         "NSAP selector for Transport Protocol (last byte in hexa)",
2143         "NSAP selector for Transport Protocol (last byte in hexa)",
2144         16, &tp_nsap_selector);
2145   prefs_register_bool_preference(clnp_module, "always_decode_transport",
2146         "Always try to decode NSDU as transport PDUs",
2147         "Always try to decode NSDU as transport PDUs",
2148         &always_decode_transport);
2149   prefs_register_bool_preference(clnp_module, "reassemble",
2150         "Reassemble segmented CLNP datagrams",
2151         "Whether segmented CLNP datagrams should be reassembled",
2152         &clnp_reassemble);
2153 }
2154
2155 void proto_register_cotp(void)
2156 {
2157   /*        static hf_register_info hf[] = {
2158                 { &variable,
2159                 { "Name",           "cotp.abbreviation", TYPE, VALS_POINTER }},
2160         };*/
2161         static gint *ett[] = {
2162                 &ett_cotp,
2163         };
2164
2165         proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2166  /*       proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2167         proto_register_subtree_array(ett, array_length(ett));
2168
2169 /* subdissector code */
2170         register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2171
2172         /* XXX - what about CLTP? */
2173         register_dissector("ositp", dissect_ositp, proto_cotp);
2174 }
2175
2176 void proto_register_cltp(void)
2177 {
2178   /*        static hf_register_info hf[] = {
2179                 { &variable,
2180                 { "Name",           "cltp.abbreviation", TYPE, VALS_POINTER }},
2181         };*/
2182         static gint *ett[] = {
2183                 &ett_cltp,
2184         };
2185
2186         proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2187  /*       proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2188         proto_register_subtree_array(ett, array_length(ett));
2189         register_init_routine(clnp_reassemble_init);
2190 }
2191
2192 void
2193 proto_reg_handoff_clnp(void)
2194 {
2195         dissector_handle_t clnp_handle;
2196
2197         data_handle = find_dissector("data");
2198
2199         clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2200         dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2201         dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2202         dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2203 }