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