Small explanation for why MS created their own KRB5 OID value.
[metze/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.66 2003/02/04 21:43:56 deniel Exp $
5  * Laurent Deniel <laurent.deniel@free.fr>
6  * Ralf Schneider <Ralf.Schneider@t-online.de>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <signal.h>
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 clnp_handle;
90 static dissector_handle_t data_handle;
91
92 /*
93  * ISO 8473 OSI CLNP definition (see RFC994)
94  *
95  *            _________________________________
96  *           |           Fixed Part            |
97  *           |_________________________________|
98  *           |          Address Part           |
99  *           |_________________________________|
100  *           |   Segmentation Part (optional)  |
101  *           |_________________________________|
102  *           |     Options Part (optional)     |
103  *           |_________________________________|
104  *           |         Data (optional)         |
105  *           |_________________________________|
106  */
107
108 #define ISO8473_V1  0x01    /* CLNP version 1 */
109
110 /* Fixed part */
111
112 #define CNF_TYPE                0x1f
113 #define CNF_ERR_OK              0x20
114 #define CNF_MORE_SEGS           0x40
115 #define CNF_SEG_OK              0x80
116
117 #define DT_NPDU                 0x1C
118 #define MD_NPDU                 0x1D
119 #define ER_NPDU                 0x01
120 #define ERQ_NPDU                0x1E
121 #define ERP_NPDU                0x1F
122
123 static const value_string npdu_type_abbrev_vals[] = {
124   { DT_NPDU,    "DT" },
125   { MD_NPDU,    "MD" },
126   { ER_NPDU,    "ER" },
127   { ERQ_NPDU,   "ERQ" },
128   { ERP_NPDU,   "ERP" },
129   { 0,          NULL }
130 };
131
132 static const value_string npdu_type_vals[] = {
133   { DT_NPDU,    "Data" },
134   { MD_NPDU,    "Multicast Data" },
135   { ER_NPDU,    "Error Report" },
136   { ERQ_NPDU,   "Echo Request" },
137   { ERP_NPDU,   "Echo Response" },
138   { 0,          NULL }
139 };
140
141 /* field position */
142
143 #define P_CLNP_PROTO_ID         0
144 #define P_CLNP_HDR_LEN          1
145 #define P_CLNP_VERS             2
146 #define P_CLNP_TTL              3
147 #define P_CLNP_TYPE             4
148 #define P_CLNP_SEGLEN           5
149 #define P_CLNP_CKSUM            7
150 #define P_CLNP_ADDRESS_PART     9
151
152 /* Segmentation part */
153
154 struct clnp_segment {
155   gushort       cng_id;         /* data unit identifier */
156   gushort       cng_off;        /* segment offset */
157   gushort       cng_tot_len;    /* total length */
158 };
159
160 /* NSAP selector */
161
162 #define NSEL_NET                0x00
163 #define NSEL_NP                 0x20
164 #define NSEL_TP                 0x21
165
166 /*
167  * ISO8073 OSI COTP definition (see RFC905)
168  */
169
170 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
171
172 /* TPDU definition */
173
174 #define ED_TPDU                 0x1     /* COTP */
175 #define EA_TPDU                 0x2     /* COTP */
176 #define UD_TPDU                 0x4     /* CLTP */
177 #define RJ_TPDU                 0x5     /* COTP */
178 #define AK_TPDU                 0x6     /* COTP */
179 #define ER_TPDU                 0x7     /* COTP */
180 #define DR_TPDU                 0x8     /* COTP */
181 #define DC_TPDU                 0xC     /* COTP */
182 #define CC_TPDU                 0xD     /* COTP */
183 #define CR_TPDU                 0xE     /* COTP */
184 #define DT_TPDU                 0xF     /* COTP */
185
186 /* field position */
187
188 #define P_LI                    0
189 #define P_TPDU                  1
190 #define P_CDT                   1
191 #define P_DST_REF               2
192 #define P_SRC_REF               4
193 #define P_TPDU_NR_0_1           2
194 #define P_TPDU_NR_234           4
195 #define P_VAR_PART_NDT          5
196 #define P_VAR_PART_EDT          8
197 #define P_VAR_PART_DC           6
198 #define P_CDT_IN_AK             8
199 #define P_CDT_IN_RJ             8
200 #define P_REJECT_ER             4
201 #define P_REASON_IN_DR          6
202 #define P_CLASS_OPTION          6
203
204 /* TPDU length indicator */
205
206 #define LI_NORMAL_DT_CLASS_01            2
207 #define LI_NORMAL_DT_WITH_CHECKSUM       8
208 #define LI_NORMAL_DT_WITHOUT_CHECKSUM    4
209 #define LI_EXTENDED_DT_WITH_CHECKSUM     11
210 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM  7
211 #define LI_NORMAL_EA_WITH_CHECKSUM       8
212 #define LI_NORMAL_EA_WITHOUT_CHECKSUM    4
213 #define LI_EXTENDED_EA_WITH_CHECKSUM     11
214 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM  7
215 #define LI_NORMAL_RJ                     4
216 #define LI_EXTENDED_RJ                   9
217 #define LI_MIN_DR                        6
218 #define LI_MAX_DC                        9
219 #define LI_MAX_AK                        27
220 #define LI_MAX_EA                        11
221 #define LI_MAX_ER                        8
222 /* XXX - can we always decide this based on whether the length
223    indicator is odd or not?  What if the variable part has an odd
224    number of octets? */
225 #define is_LI_NORMAL_AK(p)               ( ( p & 0x01 ) == 0 )
226
227 /* variant part */
228
229 #define VP_ACK_TIME             0x85
230 #define VP_RES_ERROR            0x86
231 #define VP_PRIORITY             0x87
232 #define VP_TRANSIT_DEL          0x88
233 #define VP_THROUGHPUT           0x89
234 #define VP_SEQ_NR               0x8A         /* in AK */
235 #define VP_REASSIGNMENT         0x8B
236 #define VP_FLOW_CNTL            0x8C         /* in AK */
237 #define VP_TPDU_SIZE            0xC0
238 #define VP_SRC_TSAP             0xC1         /* in CR/CC */
239 #define VP_DST_TSAP             0xC2
240 #define VP_CHECKSUM             0xC3
241 #define VP_VERSION_NR           0xC4
242 #define VP_PROTECTION           0xC5
243 #define VP_OPT_SEL              0xC6
244 #define VP_PROTO_CLASS          0xC7
245 #define VP_PREF_MAX_TPDU_SIZE   0xF0
246 #define VP_INACTIVITY_TIMER     0xF2
247
248 static const value_string tp_vpart_type_vals[] = {
249   { VP_ACK_TIME,                "ack time" },
250   { VP_RES_ERROR,               "res error" },
251   { VP_PRIORITY,                "priority" },
252   { VP_TRANSIT_DEL,             "transit delay" },
253   { VP_THROUGHPUT,              "throughput" },
254   { VP_SEQ_NR,                  "seq number" },
255   { VP_REASSIGNMENT,            "reassignment" },
256   { VP_FLOW_CNTL,               "flow control" },
257   { VP_TPDU_SIZE,               "tpdu-size" },
258   { VP_SRC_TSAP,                "src-tsap" },
259   { VP_DST_TSAP,                "dst-tsap" },
260   { VP_CHECKSUM,                "checksum" },
261   { VP_VERSION_NR,              "version" },
262   { VP_PROTECTION,              "protection" },
263   { VP_OPT_SEL,                 "options" },
264   { VP_PROTO_CLASS,             "proto class" },
265   { VP_PREF_MAX_TPDU_SIZE,      "preferred max TPDU size" },
266   { 0,                          NULL }
267 };
268
269 /* misc */
270
271 #define EXTRACT_SHORT(p)        pntohs(p)
272 #define EXTRACT_LONG(p)         pntohl(p)
273
274 /* global variables */
275
276 /* List of dissectors to call for COTP packets put atop the Inactive
277    Subset of CLNP. */
278 static heur_dissector_list_t cotp_is_heur_subdissector_list;
279 /* List of dissectors to call for COTP packets put atop CLNP */
280 static heur_dissector_list_t cotp_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 ositp_decode_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 ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
672                          packet_info *pinfo, proto_tree *tree)
673 {
674   proto_tree *cotp_tree;
675   proto_item *ti;
676   guint16 dst_ref, src_ref;
677   guchar  reason;
678   char *str;
679
680   if (li < LI_MIN_DR)
681     return -1;
682
683   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
684   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
685   reason  = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
686
687   switch(reason) {
688     case (128+0): str = "Normal Disconnect"; break;
689     case (128+1): str = "Remote transport entity congestion"; break;
690     case (128+2): str = "Connection negotiation failed"; break;
691     case (128+3): str = "Duplicate source reference"; break;
692     case (128+4): str = "Mismatched references"; break;
693     case (128+5): str = "Protocol error"; break;
694     case (128+7): str = "Reference overflow"; break;
695     case (128+8): str = "Connection requestion refused"; break;
696     case (128+10):str = "Header or parameter length invalid"; break;
697     case (0):     str = "Reason not specified"; break;
698     case (1):     str = "Congestion at TSAP"; break;
699     case (2):     str = "Session entity not attached to TSAP"; break;
700     case (3):     str = "Address unknown"; break;
701     default:      return -1;
702       /*NOTREACHED*/
703       break;
704   }
705
706   if (check_col(pinfo->cinfo, COL_INFO))
707     col_append_fstr(pinfo->cinfo, COL_INFO,
708                 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
709                  src_ref, dst_ref);
710
711   if (tree) {
712     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
713     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
714     proto_tree_add_text(cotp_tree, tvb, offset,      1,
715                         "Length indicator: %u", li);
716     proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
717                         "TPDU code: 0x%x (DR)", tpdu);
718     proto_tree_add_text(cotp_tree, tvb, offset +  2, 2,
719                         "Destination reference: 0x%04x", dst_ref);
720     proto_tree_add_text(cotp_tree, tvb, offset +  4, 2,
721                         "Source reference: 0x%04x", src_ref);
722     proto_tree_add_text(cotp_tree, tvb, offset +  6, 1,
723                         "Cause: %s", str);
724   }
725
726   offset += li + 1;
727
728   /* User data */
729   call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
730   offset += tvb_length_remaining(tvb, offset);
731      /* we dissected all of the containing PDU */
732
733   return offset;
734
735 } /* ositp_decode_DR */
736
737 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
738                          packet_info *pinfo, proto_tree *tree,
739                          gboolean uses_inactive_subset,
740                          gboolean *subdissector_found)
741 {
742   proto_tree *cotp_tree = NULL;
743   proto_item *ti;
744   gboolean is_extended;
745   gboolean is_class_234;
746   guint16  dst_ref;
747   guint    tpdu_nr;
748   guint    fragment = 0;
749   tvbuff_t *next_tvb;
750
751   /* VP_CHECKSUM is the only parameter allowed in the variable part.
752      (This means we may misdissect this if the packet is bad and
753      contains other parameters.) */
754   switch (li) {
755
756     case LI_NORMAL_DT_WITH_CHECKSUM      :
757       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
758         return -1;
759       /* FALLTHROUGH */
760
761     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
762       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
763       if ( tpdu_nr & 0x80 )
764         tpdu_nr = tpdu_nr & 0x7F;
765       else
766         fragment = 1;
767       is_extended = FALSE;
768       is_class_234 = TRUE;
769       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
770       break;
771
772     case LI_EXTENDED_DT_WITH_CHECKSUM    :
773       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
774         return -1;
775       /* FALLTHROUGH */
776
777     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
778       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
779       if ( tpdu_nr & 0x80000000 )
780         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
781       else
782         fragment = 1;
783       is_extended = TRUE;
784       is_class_234 = TRUE;
785       dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
786       break;
787
788     case LI_NORMAL_DT_CLASS_01           :
789       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
790       if ( tpdu_nr & 0x80 )
791         tpdu_nr = tpdu_nr & 0x7F;
792       else
793         fragment = 1;
794       is_extended = FALSE;
795       is_class_234 = FALSE;
796       dst_ref = 0;
797       break;
798
799     default : /* bad TPDU */
800       return -1;
801       /*NOTREACHED*/
802       break;
803   }
804
805   if (check_col(pinfo->cinfo, COL_INFO)) {
806     if (is_class_234) {
807       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
808                  tpdu_nr,
809                  dst_ref,
810                  (fragment)? "(fragment)" : "");
811     } else {
812       col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) %s",
813                  tpdu_nr,
814                  (fragment)? "(fragment)" : "");
815     }
816   }
817
818   if (tree) {
819     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
820     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
821     proto_tree_add_text(cotp_tree, tvb, offset, 1,
822                         "Length indicator: %u", li);
823   }
824   offset += 1;
825
826   if (tree) {
827     proto_tree_add_text(cotp_tree, tvb, offset, 1,
828                         "TPDU code: 0x%x (DT)", tpdu);
829
830   }
831   offset += 1;
832   li -= 1;
833
834   if (is_class_234) {
835     if (tree) {
836       proto_tree_add_text(cotp_tree, tvb, offset, 2,
837                           "Destination reference: 0x%04x", dst_ref);
838     }
839     offset += 2;
840     li -= 2;
841   }
842
843   if (is_extended) {
844     if (tree) {
845       proto_tree_add_text(cotp_tree, tvb, offset, 4,
846                             "TPDU number: 0x%08x (%s)",
847                             tpdu_nr,
848                             (fragment)? "fragment":"complete");
849     }
850     offset += 4;
851     li -= 4;
852   } else {
853     if (tree) {
854       proto_tree_add_text(cotp_tree, tvb, offset, 1,
855                             "TPDU number: 0x%02x (%s)",
856                             tpdu_nr,
857                             (fragment)? "fragment":"complete");
858     }
859     offset += 1;
860     li -= 1;
861   }
862
863   if (tree)
864     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
865   offset += li;
866
867   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
868   if (uses_inactive_subset){
869         if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
870                                         pinfo, tree)) {
871                 *subdissector_found = TRUE;
872         } else {
873           /* Fill in other Dissectors using inactive subset here */
874           call_dissector(data_handle,next_tvb, pinfo, tree);
875         }
876   } else {
877         if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
878                                     pinfo, tree)) {
879                 *subdissector_found = TRUE;
880         } else {
881                 call_dissector(data_handle,next_tvb, pinfo, tree);
882         }
883   }
884   offset += tvb_length_remaining(tvb, offset);
885      /* we dissected all of the containing PDU */
886
887   return offset;
888
889 } /* ositp_decode_DT */
890
891 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
892                          packet_info *pinfo, proto_tree *tree)
893 {
894   proto_tree *cotp_tree = NULL;
895   proto_item *ti;
896   gboolean is_extended;
897   guint16  dst_ref;
898   guint    tpdu_nr;
899   tvbuff_t *next_tvb;
900
901   /* ED TPDUs are never fragmented */
902
903   /* VP_CHECKSUM is the only parameter allowed in the variable part.
904      (This means we may misdissect this if the packet is bad and
905      contains other parameters.) */
906   switch (li) {
907
908     case LI_NORMAL_DT_WITH_CHECKSUM      :
909       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
910         return -1;
911       /* FALLTHROUGH */
912
913     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
914       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
915       if ( tpdu_nr & 0x80 )
916         tpdu_nr = tpdu_nr & 0x7F;
917       else
918         return -1;
919       is_extended = FALSE;
920       break;
921
922     case LI_EXTENDED_DT_WITH_CHECKSUM    :
923       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
924         return -1;
925       /* FALLTHROUGH */
926
927     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
928       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
929       if ( tpdu_nr & 0x80000000 )
930         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
931       else
932         return -1;
933       is_extended = TRUE;
934       break;
935
936     default : /* bad TPDU */
937       return -1;
938       /*NOTREACHED*/
939       break;
940   } /* li */
941
942   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
943   if (check_col(pinfo->cinfo, COL_INFO))
944     col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
945                  tpdu_nr, dst_ref);
946
947   if (tree) {
948     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
949     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
950     proto_tree_add_text(cotp_tree, tvb, offset, 1,
951                         "Length indicator: %u", li);
952   }
953   offset += 1;
954
955   if (tree) {
956     proto_tree_add_text(cotp_tree, tvb, offset, 1,
957                         "TPDU code: 0x%x (ED)", tpdu);
958   }
959   offset += 1;
960   li -= 1;
961
962   if (tree) {
963     proto_tree_add_text(cotp_tree, tvb, offset, 2,
964                         "Destination reference: 0x%04x", dst_ref);
965   }
966   offset += 2;
967   li -= 2;
968
969   if (is_extended) {
970     if (tree) {
971       proto_tree_add_text(cotp_tree, tvb, offset, 4,
972                             "TPDU number: 0x%02x", tpdu_nr);
973     }
974     offset += 4;
975     li -= 4;
976   } else {
977     if (tree) {
978       proto_tree_add_text(cotp_tree, tvb, offset, 1,
979                             "TPDU number: 0x%02x", tpdu_nr);
980     }
981     offset += 1;
982     li -= 1;
983   }
984
985   if (tree)
986     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
987   offset += li;
988
989   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
990   call_dissector(data_handle,next_tvb, pinfo, tree);
991
992   offset += tvb_length_remaining(tvb, offset);
993      /* we dissected all of the containing PDU */
994
995   return offset;
996
997 } /* ositp_decode_ED */
998
999 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1000                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1001 {
1002   proto_tree *cotp_tree;
1003   proto_item *ti;
1004   guint16  dst_ref;
1005   guint    tpdu_nr;
1006   gushort  credit = 0;
1007
1008   switch(li) {
1009     case LI_NORMAL_RJ   :
1010       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1011       break;
1012     case LI_EXTENDED_RJ :
1013       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1014       credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1015       break;
1016     default :
1017       return -1;
1018       /*NOTREACHED*/
1019       break;
1020   }
1021
1022   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1023   if (check_col(pinfo->cinfo, COL_INFO))
1024     col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1025                  tpdu_nr, dst_ref);
1026
1027   if (tree) {
1028     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1029     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1030     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1031                         "Length indicator: %u", li);
1032     proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1033                         "TPDU code: 0x%x (RJ)", tpdu);
1034     if (li == LI_NORMAL_RJ)
1035       proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1036                           "Credit: %u", cdt);
1037     proto_tree_add_text(cotp_tree, tvb, offset +  2, 2,
1038                         "Destination reference: 0x%04x", dst_ref);
1039     if (li == LI_NORMAL_RJ)
1040       proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1041                           "Your TPDU number: 0x%02x", tpdu_nr);
1042     else {
1043       proto_tree_add_text(cotp_tree, tvb, offset +  4, 4,
1044                           "Your TPDU number: 0x%02x", tpdu_nr);
1045       proto_tree_add_text(cotp_tree, tvb, offset +  8, 2,
1046                           "Credit: 0x%02x", credit);
1047     }
1048   }
1049
1050   offset += li + 1;
1051
1052   return offset;
1053
1054 } /* ositp_decode_RJ */
1055
1056 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1057                          packet_info *pinfo, proto_tree *tree)
1058 {
1059
1060   /* CC & CR decoding in the same function */
1061
1062   proto_tree *cotp_tree = NULL;
1063   proto_item *ti;
1064   guint16 dst_ref, src_ref;
1065   guchar  class_option;
1066
1067   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1068   class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1069   if (class_option > 4)
1070     return -1;
1071
1072   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1073   if (check_col(pinfo->cinfo, COL_INFO))
1074     col_append_fstr(pinfo->cinfo, COL_INFO,
1075                  "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1076                  (tpdu == CR_TPDU) ? "CR" : "CC",
1077                  src_ref,
1078                  dst_ref);
1079
1080   if (tree) {
1081     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1082     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1083     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1084                         "Length indicator: %u", li);
1085   }
1086   offset += 1;
1087
1088   if (tree) {
1089     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1090                         "TPDU code: 0x%x (%s)", tpdu,
1091                         (tpdu == CR_TPDU) ? "CR" : "CC");
1092   }
1093   offset += 1;
1094   li -= 1;
1095
1096   if (tree) {
1097     proto_tree_add_text(cotp_tree, tvb, offset, 2,
1098                         "Destination reference: 0x%04x", dst_ref);
1099   }
1100   offset += 2;
1101   li -= 2;
1102
1103   if (tree) {
1104     proto_tree_add_text(cotp_tree, tvb, offset, 2,
1105                         "Source reference: 0x%04x", src_ref);
1106   }
1107   offset += 2;
1108   li -= 2;
1109
1110   if (tree) {
1111     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1112                         "Class option: 0x%02x", class_option);
1113   }
1114   offset += 1;
1115   li -= 1;
1116
1117   if (tree)
1118     ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1119   offset += li;
1120
1121   /* User data */
1122   call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
1123   offset += tvb_length_remaining(tvb, offset);
1124      /* we dissected all of the containing PDU */
1125
1126   return offset;
1127
1128 } /* ositp_decode_CC */
1129
1130 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1131                          packet_info *pinfo, proto_tree *tree)
1132 {
1133   proto_tree *cotp_tree = NULL;
1134   proto_item *ti;
1135   guint16 dst_ref, src_ref;
1136
1137   if (li > LI_MAX_DC)
1138     return -1;
1139
1140   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1141   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1142
1143   if (check_col(pinfo->cinfo, COL_INFO))
1144     col_append_fstr(pinfo->cinfo, COL_INFO,
1145                  "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1146                  src_ref,
1147                  dst_ref);
1148
1149   if (tree) {
1150     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1151     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1152     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1153                         "Length indicator: %u", li);
1154   }
1155   offset += 1;
1156
1157   if (tree) {
1158     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1159                         "TPDU code: 0x%x (DC)", tpdu);
1160   }
1161   offset += 1;
1162   li -= 1;
1163
1164   if (tree) {
1165     proto_tree_add_text(cotp_tree, tvb, offset, 2,
1166                         "Destination reference: 0x%04x", dst_ref);
1167   }
1168   offset += 2;
1169   li -= 2;
1170
1171   if (tree) {
1172     proto_tree_add_text(cotp_tree, tvb, offset, 2,
1173                         "Source reference: 0x%04x", src_ref);
1174   }
1175   offset += 2;
1176   li -= 2;
1177
1178   if (tree)
1179     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1180   offset += li;
1181
1182   return offset;
1183
1184 } /* ositp_decode_DC */
1185
1186 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1187                          guint8 cdt, packet_info *pinfo, proto_tree *tree)
1188 {
1189   proto_tree *cotp_tree = NULL;
1190   proto_item *ti;
1191   guint16    dst_ref;
1192   guint      tpdu_nr;
1193   gushort    cdt_in_ak;
1194
1195   if (li > LI_MAX_AK)
1196     return -1;
1197
1198   if (is_LI_NORMAL_AK(li)) {
1199
1200     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1201     tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1202
1203     if (check_col(pinfo->cinfo, COL_INFO))
1204       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1205                    tpdu_nr, dst_ref);
1206
1207     if (tree) {
1208       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1209       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1210       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1211                           "Length indicator: %u", li);
1212     }
1213     offset += 1;
1214
1215     if (tree) {
1216       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1217                           "TPDU code: 0x%x (AK)", tpdu);
1218       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1219                           "Credit: %u", cdt);
1220     }
1221     offset += 1;
1222     li -= 1;
1223
1224     if (tree) {
1225       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1226                           "Destination reference: 0x%04x", dst_ref);
1227     }
1228     offset += 2;
1229     li -= 2;
1230
1231     if (tree) {
1232       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1233                           "Your TPDU number: 0x%02x", tpdu_nr);
1234     }
1235     offset += 1;
1236     li -= 1;
1237
1238     if (tree)
1239       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1240     offset += li;
1241
1242   } else { /* extended format */
1243
1244     dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1245     tpdu_nr   = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1246     cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1247
1248     if (check_col(pinfo->cinfo, COL_INFO))
1249       col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1250                    tpdu_nr, dst_ref);
1251
1252     if (tree) {
1253       ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1254       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1255       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1256                           "Length indicator: %u", li);
1257     }
1258     offset += 1;
1259
1260     if (tree) {
1261       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1262                           "TPDU code: 0x%x (AK)", tpdu);
1263     }
1264     offset += 1;
1265     li -= 1;
1266
1267     if (tree) {
1268       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1269                           "Destination reference: 0x%04x", dst_ref);
1270     }
1271     offset += 2;
1272     li -= 2;
1273
1274     if (tree) {
1275       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1276                           "Your TPDU number: 0x%08x", tpdu_nr);
1277     }
1278     offset += 4;
1279     li -= 4;
1280
1281     if (tree) {
1282       proto_tree_add_text(cotp_tree, tvb, offset, 2,
1283                           "Credit: 0x%04x", cdt_in_ak);
1284     }
1285     offset += 2;
1286     li -= 2;
1287
1288     if (tree)
1289       ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1290     offset += li;
1291
1292   } /* is_LI_NORMAL_AK */
1293
1294   return offset;
1295
1296 } /* ositp_decode_AK */
1297
1298 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1299                          packet_info *pinfo, proto_tree *tree)
1300 {
1301   proto_tree *cotp_tree = NULL;
1302   proto_item *ti;
1303   gboolean is_extended;
1304   guint16  dst_ref;
1305   guint    tpdu_nr;
1306
1307   if (li > LI_MAX_EA)
1308     return -1;
1309
1310   /* VP_CHECKSUM is the only parameter allowed in the variable part.
1311      (This means we may misdissect this if the packet is bad and
1312      contains other parameters.) */
1313   switch (li) {
1314
1315     case LI_NORMAL_EA_WITH_CHECKSUM      :
1316       if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1317                 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1318         return -1;
1319       /* FALLTHROUGH */
1320
1321     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1322       tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1323       is_extended = FALSE;
1324       break;
1325
1326     case LI_EXTENDED_EA_WITH_CHECKSUM    :
1327       if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1328                 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1329         return -1;
1330       /* FALLTHROUGH */
1331
1332     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1333       tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1334       is_extended = TRUE;
1335       break;
1336
1337     default : /* bad TPDU */
1338       return -1;
1339       /*NOTREACHED*/
1340       break;
1341   } /* li */
1342
1343   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1344   if (check_col(pinfo->cinfo, COL_INFO))
1345     col_append_fstr(pinfo->cinfo, COL_INFO,
1346                  "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1347
1348   if (tree) {
1349     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1350     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1351     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1352                         "Length indicator: %u", li);
1353   }
1354   offset += 1;
1355
1356   if (tree) {
1357     proto_tree_add_text(cotp_tree, tvb, offset, 1,
1358                         "TPDU code: 0x%x (EA)", tpdu);
1359   }
1360   offset += 1;
1361   li -= 1;
1362
1363   if (tree) {
1364     proto_tree_add_text(cotp_tree, tvb, offset, 2,
1365                         "Destination reference: 0x%04x", dst_ref);
1366   }
1367   offset += 2;
1368   li -= 2;
1369
1370   if (is_extended) {
1371     if (tree) {
1372       proto_tree_add_text(cotp_tree, tvb, offset, 4,
1373                             "Your TPDU number: 0x%08x", tpdu_nr);
1374     }
1375     offset += 4;
1376     li -= 4;
1377   } else {
1378     if (tree) {
1379       proto_tree_add_text(cotp_tree, tvb, offset, 1,
1380                             "Your TPDU number: 0x%02x", tpdu_nr);
1381     }
1382     offset += 1;
1383     li -= 1;
1384   }
1385
1386   if (tree)
1387     ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1388   offset += li;
1389
1390   return offset;
1391
1392 } /* ositp_decode_EA */
1393
1394 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1395                          packet_info *pinfo, proto_tree *tree)
1396 {
1397   proto_tree *cotp_tree;
1398   proto_item *ti;
1399   guchar *str;
1400   guint16 dst_ref;
1401
1402   if (li > LI_MAX_ER)
1403     return -1;
1404
1405   switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1406     case 0 :
1407       str = "Reason not specified";
1408       break;
1409     case 1 :
1410       str = "Invalid parameter code";
1411       break;
1412     case 2 :
1413       str = "Invalid TPDU type";
1414       break;
1415     case 3 :
1416       str = "Invalid parameter value";
1417       break;
1418     default:
1419       return -1;
1420       /*NOTREACHED*/
1421       break;
1422   }
1423
1424   dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1425   if (check_col(pinfo->cinfo, COL_INFO))
1426     col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1427
1428   if (tree) {
1429     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1430     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1431     proto_tree_add_text(cotp_tree, tvb, offset,      1,
1432                         "Length indicator: %u", li);
1433     proto_tree_add_text(cotp_tree, tvb, offset +  1, 1,
1434                         "TPDU code: 0x%x (ER)", tpdu);
1435     proto_tree_add_text(cotp_tree, tvb, offset +  2, 2,
1436                         "Destination reference: 0x%04x", dst_ref);
1437     proto_tree_add_text(cotp_tree, tvb, offset +  4, 1,
1438                         "Reject cause: %s", str);
1439   }
1440
1441   offset += li + 1;
1442
1443   return offset;
1444
1445 } /* ositp_decode_ER */
1446
1447 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1448                          packet_info *pinfo, proto_tree *tree)
1449 {
1450   proto_item *ti;
1451   proto_tree *cltp_tree = NULL;
1452   tvbuff_t   *next_tvb;
1453
1454   if (check_col(pinfo->cinfo, COL_INFO))
1455     col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1456
1457   if (tree) {
1458     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1459     cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1460     proto_tree_add_text(cltp_tree, tvb, offset, 1,
1461                         "Length indicator: %u", li);
1462   }
1463   offset += 1;
1464
1465   if (tree) {
1466     proto_tree_add_text(cltp_tree, tvb, offset, 1,
1467                         "TPDU code: 0x%x (UD)", tpdu);
1468   }
1469   offset += 1;
1470   li -= 1;
1471
1472   if (tree)
1473     ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1474   offset += li;
1475
1476   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1477   call_dissector(data_handle,next_tvb, pinfo, tree);
1478   offset += tvb_length_remaining(tvb, offset);
1479      /* we dissected all of the containing PDU */
1480
1481   return offset;
1482
1483 } /* ositp_decode_UD */
1484
1485 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1486    otherwise.
1487
1488    There doesn't seem to be any way in which the OSI network layer protocol
1489    distinguishes between COTP and CLTP, but the first two octets of both
1490    protocols' headers mean the same thing - length and PDU type - and the
1491    only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1492    both of them here. */
1493 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1494                   proto_tree *tree, gboolean uses_inactive_subset)
1495 {
1496   int offset = 0;
1497   guint8 li, tpdu, cdt;
1498   gboolean first_tpdu = TRUE;
1499   int new_offset;
1500   gboolean found_ositp = FALSE;
1501   gboolean is_cltp = FALSE;
1502   gboolean subdissector_found = FALSE;
1503
1504   if (!proto_is_protocol_enabled(proto_cotp))
1505     return FALSE;       /* COTP has been disabled */
1506   /* XXX - what about CLTP? */
1507
1508   pinfo->current_proto = "COTP";
1509
1510   /* Initialize the COL_INFO field; each of the TPDUs will have its
1511      information appended. */
1512   if (check_col(pinfo->cinfo, COL_INFO))
1513     col_add_str(pinfo->cinfo, COL_INFO, "");
1514
1515   while (tvb_offset_exists(tvb, offset)) {
1516     if (!first_tpdu) {
1517       if (check_col(pinfo->cinfo, COL_INFO))
1518         col_append_str(pinfo->cinfo, COL_INFO, ", ");
1519     }
1520     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1521       if (check_col(pinfo->cinfo, COL_INFO))
1522         col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1523       if (!first_tpdu)
1524         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1525                        pinfo, tree);
1526       return found_ositp;
1527     }
1528
1529     tpdu    = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1530     if (tpdu == UD_TPDU)
1531       pinfo->current_proto = "CLTP";    /* connectionless transport */
1532     cdt     = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1533
1534     switch (tpdu) {
1535       case CC_TPDU :
1536       case CR_TPDU :
1537         new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree);
1538         break;
1539       case DR_TPDU :
1540         new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1541         break;
1542       case DT_TPDU :
1543         new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1544                                    uses_inactive_subset, &subdissector_found);
1545         break;
1546       case ED_TPDU :
1547         new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1548         break;
1549       case RJ_TPDU :
1550         new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1551         break;
1552       case DC_TPDU :
1553         new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1554         break;
1555       case AK_TPDU :
1556         new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1557         break;
1558       case EA_TPDU :
1559         new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1560         break;
1561       case ER_TPDU :
1562         new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1563         break;
1564       case UD_TPDU :
1565         new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1566         is_cltp = TRUE;
1567         break;
1568       default      :
1569         if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1570           col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1571         new_offset = -1;        /* bad PDU type */
1572         break;
1573     }
1574
1575     if (new_offset == -1) { /* incorrect TPDU */
1576       if (!first_tpdu)
1577         call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1578                        pinfo, tree);
1579       break;
1580     }
1581
1582     if (first_tpdu) {
1583       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1584          is either COTP or CLTP. */
1585       if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1586         col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1587       found_ositp = TRUE;
1588     }
1589
1590     offset = new_offset;
1591     first_tpdu = FALSE;
1592   }
1593   return found_ositp;
1594 } /* dissect_ositp_internal */
1595
1596 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1597 {
1598   if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1599     call_dissector(data_handle,tvb, pinfo, tree);
1600 }
1601
1602 /*
1603  *  CLNP part / main entry point
1604 */
1605
1606 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1607 {
1608   proto_tree *clnp_tree = NULL;
1609   proto_item *ti;
1610   guint8      cnf_proto_id;
1611   guint8      cnf_hdr_len;
1612   guint8      cnf_vers;
1613   guint8      cnf_ttl;
1614   guint8      cnf_type;
1615   char        flag_string[6+1];
1616   char       *pdu_type_string;
1617   proto_tree *type_tree;
1618   guint16     segment_length;
1619   guint16     du_id = 0;
1620   guint16     segment_offset = 0;
1621   guint16     cnf_cksum;
1622   cksum_status_t cksum_status;
1623   int         offset;
1624   guchar      src_len, dst_len, nsel, opt_len = 0;
1625   const guint8     *dst_addr, *src_addr;
1626   gint        len;
1627   guint       next_length;
1628   proto_tree *discpdu_tree;
1629   gboolean    save_in_error_pkt;
1630   fragment_data *fd_head;
1631   tvbuff_t   *next_tvb;
1632   gboolean    update_col_info = TRUE;
1633   gboolean    save_fragmented;
1634
1635   signal(SIGSEGV, SIG_DFL);
1636
1637   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1638     col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1639   if (check_col(pinfo->cinfo, COL_INFO))
1640     col_clear(pinfo->cinfo, COL_INFO);
1641
1642   cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1643   if (cnf_proto_id == NLPID_NULL) {
1644     if (check_col(pinfo->cinfo, COL_INFO))
1645       col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1646     if (tree) {
1647       ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1648       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1649       proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1650                                  cnf_proto_id,
1651                                  "Inactive subset");
1652     }
1653     next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1654     dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1655     return;
1656   }
1657
1658   /* return if version not known */
1659   cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1660   if (cnf_vers != ISO8473_V1) {
1661     call_dissector(data_handle,tvb, pinfo, tree);
1662     return;
1663   }
1664
1665   /* fixed part decoding */
1666   cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1667   opt_len = cnf_hdr_len;
1668
1669   if (tree) {
1670     ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1671     clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1672     proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1673                                cnf_proto_id);
1674     proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1675                         cnf_hdr_len);
1676     proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1677                         cnf_vers);
1678     cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1679     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1680                                cnf_ttl,
1681                                "Holding Time : %u (%u.%u secs)",
1682                                cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1683   }
1684
1685   cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1686   pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1687                                 "Unknown (0x%02x)");
1688   flag_string[0] = '\0';
1689   if (cnf_type & CNF_SEG_OK)
1690     strcat(flag_string, "S ");
1691   if (cnf_type & CNF_MORE_SEGS)
1692     strcat(flag_string, "M ");
1693   if (cnf_type & CNF_ERR_OK)
1694     strcat(flag_string, "E ");
1695   if (tree) {
1696     ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1697                                cnf_type,
1698                                "PDU Type     : 0x%02x (%s%s)",
1699                                cnf_type,
1700                                flag_string,
1701                                pdu_type_string);
1702     type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1703     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1704                         decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1705                                       "Segmentation permitted",
1706                                       "Segmentation not permitted"));
1707     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1708                         decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1709                                       "More segments",
1710                                       "Last segment"));
1711     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1712                         decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1713                                       "Report error if PDU discarded",
1714                                       "Don't report error if PDU discarded"));
1715     proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1716                         decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1717                                       npdu_type_vals, "%s"));
1718   }
1719
1720   /* If we don't have the full header - i.e., not enough to see the
1721      segmentation part and determine whether this datagram is segmented
1722      or not - set the Info column now; we'll get an exception before
1723      we set it otherwise. */
1724
1725   if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1726     if (check_col(pinfo->cinfo, COL_INFO))
1727       col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1728   }
1729
1730   segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1731   cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1732   cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1733   if (tree) {
1734     proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1735                         segment_length);
1736     switch (cksum_status) {
1737
1738     default:
1739         /*
1740          * No checksum present, or not enough of the header present to
1741          * checksum it.
1742          */
1743         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1744                                P_CLNP_CKSUM, 2,
1745                                cnf_cksum,
1746                                "Checksum     : 0x%04x",
1747                                cnf_cksum);
1748         break;
1749
1750     case CKSUM_OK:
1751         /*
1752          * Checksum is correct.
1753          */
1754         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1755                                P_CLNP_CKSUM, 2,
1756                                cnf_cksum,
1757                                "Checksum     : 0x%04x (correct)",
1758                                cnf_cksum);
1759         break;
1760
1761     case CKSUM_NOT_OK:
1762         /*
1763          * Checksum is not correct.
1764          */
1765         proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1766                                P_CLNP_CKSUM, 2,
1767                                cnf_cksum,
1768                                "Checksum     : 0x%04x (incorrect)",
1769                                cnf_cksum);
1770         break;
1771     }
1772     opt_len -= 9; /* Fixed part of Hesder */
1773   } /* tree */
1774
1775   /* address part */
1776
1777   offset = P_CLNP_ADDRESS_PART;
1778   dst_len  = tvb_get_guint8(tvb, offset);
1779   dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1780   nsel     = tvb_get_guint8(tvb, offset + dst_len);
1781   src_len  = tvb_get_guint8(tvb, offset + dst_len + 1);
1782   src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1783
1784   if (tree) {
1785     proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1786                         dst_len);
1787     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1788                                dst_addr,
1789                                " DA : %s",
1790                                print_nsap_net(dst_addr, dst_len));
1791     proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1792                         offset + 1 + dst_len, 1, src_len);
1793     proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1794                                offset + dst_len + 2, src_len,
1795                                src_addr,
1796                                " SA : %s",
1797                                print_nsap_net(src_addr, src_len));
1798
1799     opt_len -= dst_len + src_len +2;
1800   }
1801
1802   SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1803   SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1804   SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1805   SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1806
1807   /* Segmentation Part */
1808
1809   offset += dst_len + src_len + 2;
1810
1811   if (cnf_type & CNF_SEG_OK) {
1812     struct clnp_segment seg;                    /* XXX - not used */
1813     tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg));       /* XXX - not used */
1814
1815     segment_offset = tvb_get_ntohs(tvb, offset + 2);
1816     du_id = tvb_get_ntohs(tvb, offset);
1817     if (tree) {
1818       proto_tree_add_text(clnp_tree, tvb, offset, 2,
1819                         "Data unit identifier: %06u",
1820                         du_id);
1821       proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1822                         "Segment offset      : %6u",
1823                         segment_offset);
1824       proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1825                         "Total length        : %6u",
1826                         tvb_get_ntohs(tvb, offset + 4));
1827     }
1828
1829     offset  += 6;
1830     opt_len -= 6;
1831   }
1832
1833   if (tree) {
1834     /* To do : decode options  */
1835 /*
1836     proto_tree_add_text(clnp_tree, tvb, offset,
1837                         cnf_hdr_len - offset,
1838                         "Options/Data: <not shown>");
1839 */
1840 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1841
1842     dissect_osi_options( opt_len,
1843                          tvb, offset, clnp_tree );
1844   }
1845
1846   /* Length of CLNP datagram plus headers above it. */
1847   len = segment_length;
1848
1849   offset = cnf_hdr_len;
1850
1851   /* If clnp_reassemble is on, and this is a segment, we have all the
1852    * data in the segment, and the checksum is valid, then just add the
1853    * segment to the hashtable.
1854    */
1855   save_fragmented = pinfo->fragmented;
1856   if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1857         ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1858         (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1859         cksum_status != CKSUM_NOT_OK) {
1860     fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1861                            segment_offset, segment_length - cnf_hdr_len,
1862                            cnf_type & CNF_MORE_SEGS);
1863
1864     if (fd_head != NULL) {
1865       /* OK, we have the complete reassembled payload.
1866          Allocate a new tvbuff, referring to the reassembled payload. */
1867       next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1868         fd_head->datalen);
1869
1870       /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1871          were handed refers, so it'll get cleaned up when that tvbuff
1872          is cleaned up. */
1873       tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1874
1875       /* Add the defragmented data to the data source list. */
1876       add_new_data_source(pinfo, next_tvb, "Reassembled CLNP");
1877
1878       update_col_info = !show_fragment_tree(fd_head, &clnp_frag_items,
1879         clnp_tree, pinfo, next_tvb);
1880     } else {
1881       /* We don't have the complete reassembled payload. */
1882       next_tvb = NULL;
1883     }
1884   } else {
1885     /* If this is the first segment, dissect its contents, otherwise
1886        just show it as a segment.
1887
1888        XXX - if we eventually don't save the reassembled contents of all
1889        segmented datagrams, we may want to always reassemble. */
1890     if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1891       /* Not the first segment - don't dissect it. */
1892       next_tvb = NULL;
1893     } else {
1894       /* First segment, or not segmented.  Dissect what we have here. */
1895
1896       /* Get a tvbuff for the payload. */
1897       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1898
1899       /*
1900        * If this is the first segment, but not the only segment,
1901        * tell the next protocol that.
1902        */
1903       if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1904         pinfo->fragmented = TRUE;
1905       else
1906         pinfo->fragmented = FALSE;
1907     }
1908   }
1909
1910   if (next_tvb == NULL) {
1911     /* Just show this as a segment. */
1912     if (check_col(pinfo->cinfo, COL_INFO))
1913       col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1914                 pdu_type_string, flag_string, segment_offset);
1915
1916     /* As we haven't reassembled anything, we haven't changed "pi", so
1917        we don't have to restore it. */
1918     call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
1919                    tree);
1920     pinfo->fragmented = save_fragmented;
1921     return;
1922   }
1923
1924   if (tvb_offset_exists(tvb, offset)) {
1925     switch (cnf_type & CNF_TYPE) {
1926
1927     case DT_NPDU:
1928     case MD_NPDU:
1929       /* Continue with COTP if any data.
1930          XXX - if this isn't the first Derived PDU of a segmented Initial
1931          PDU, skip that? */
1932
1933       if (nsel == (char)tp_nsap_selector || always_decode_transport) {
1934         if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1935           pinfo->fragmented = save_fragmented;
1936           return;       /* yes, it appears to be COTP or CLTP */
1937         }
1938       }
1939       break;
1940
1941     case ER_NPDU:
1942       /* The payload is the header and "none, some, or all of the data
1943          part of the discarded PDU", i.e. it's like an ICMP error;
1944          dissect it as a CLNP PDU. */
1945       if (check_col(pinfo->cinfo, COL_INFO))
1946         col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1947       if (tree) {
1948         next_length = tvb_length_remaining(tvb, offset);
1949         if (next_length != 0) {
1950           /* We have payload; dissect it. */
1951           ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
1952             "Discarded PDU");
1953           discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
1954
1955           /* Save the current value of the "we're inside an error packet"
1956              flag, and set that flag; subdissectors may treat packets
1957              that are the payload of error packets differently from
1958              "real" packets. */
1959           save_in_error_pkt = pinfo->in_error_pkt;
1960           pinfo->in_error_pkt = TRUE;
1961
1962           call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
1963
1964           /* Restore the "we're inside an error packet" flag. */
1965           pinfo->in_error_pkt = save_in_error_pkt;
1966         }
1967       }
1968       pinfo->fragmented = save_fragmented;
1969       return;   /* we're done with this PDU */
1970
1971     case ERQ_NPDU:
1972     case ERP_NPDU:
1973       /* XXX - dissect this */
1974       break;
1975     }
1976   }
1977   if (check_col(pinfo->cinfo, COL_INFO))
1978     col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1979   call_dissector(data_handle,next_tvb, pinfo, tree);
1980   pinfo->fragmented = save_fragmented;
1981 } /* dissect_clnp */
1982
1983 static void
1984 clnp_reassemble_init(void)
1985 {
1986   fragment_table_init(&clnp_segment_table);
1987 }
1988
1989 void proto_register_clnp(void)
1990 {
1991   static hf_register_info hf[] = {
1992     { &hf_clnp_id,
1993       { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
1994         VALS(nlpid_vals), 0x0, "", HFILL }},
1995
1996     { &hf_clnp_length,
1997       { "HDR Length   ", "clnp.len",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1998
1999     { &hf_clnp_version,
2000       { "Version      ", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2001
2002     { &hf_clnp_ttl,
2003       { "Holding Time ", "clnp.ttl",       FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2004
2005     { &hf_clnp_type,
2006       { "PDU Type     ", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2007
2008     { &hf_clnp_pdu_length,
2009       { "PDU length   ", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2010
2011     { &hf_clnp_checksum,
2012       { "Checksum     ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2013
2014     { &hf_clnp_dest_length,
2015       { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2016
2017     { &hf_clnp_dest,
2018       { " DA ", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2019
2020     { &hf_clnp_src_length,
2021       { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2022
2023     { &hf_clnp_src,
2024       { " SA ", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2025
2026     { &hf_clnp_segment_overlap,
2027       { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2028         "Segment overlaps with other segments", HFILL }},
2029
2030     { &hf_clnp_segment_overlap_conflict,
2031       { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2032         "Overlapping segments contained conflicting data", HFILL }},
2033
2034     { &hf_clnp_segment_multiple_tails,
2035       { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2036         "Several tails were found when reassembling the packet", HFILL }},
2037
2038     { &hf_clnp_segment_too_long_segment,
2039       { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2040         "Segment contained data past end of packet", HFILL }},
2041
2042     { &hf_clnp_segment_error,
2043       { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2044         "Reassembly error due to illegal segments", HFILL }},
2045
2046     { &hf_clnp_segment,
2047       { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2048         "CLNP Segment", HFILL }},
2049
2050     { &hf_clnp_segments,
2051       { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2052         "CLNP Segments", HFILL }},
2053   };
2054   static gint *ett[] = {
2055     &ett_clnp,
2056     &ett_clnp_type,
2057     &ett_clnp_segments,
2058     &ett_clnp_segment,
2059     &ett_clnp_disc_pdu,
2060   };
2061
2062   module_t *clnp_module;
2063
2064   proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2065   proto_register_field_array(proto_clnp, hf, array_length(hf));
2066   proto_register_subtree_array(ett, array_length(ett));
2067   register_dissector("clnp", dissect_clnp, proto_clnp);
2068
2069   clnp_module = prefs_register_protocol(proto_clnp, NULL);
2070   prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2071         "NSAP selector for Transport Protocol (last byte in hexa)",
2072         "NSAP selector for Transport Protocol (last byte in hexa)",
2073         16, &tp_nsap_selector);
2074   prefs_register_bool_preference(clnp_module, "always_decode_transport",
2075         "Always try to decode NSDU as transport PDUs",
2076         "Always try to decode NSDU as transport PDUs",
2077         &always_decode_transport);
2078   prefs_register_bool_preference(clnp_module, "reassemble",
2079         "Reassemble segmented CLNP datagrams",
2080         "Whether segmented CLNP datagrams should be reassembled",
2081         &clnp_reassemble);
2082 }
2083
2084 void proto_register_cotp(void)
2085 {
2086   /*        static hf_register_info hf[] = {
2087                 { &variable,
2088                 { "Name",           "cotp.abbreviation", TYPE, VALS_POINTER }},
2089         };*/
2090         static gint *ett[] = {
2091                 &ett_cotp,
2092         };
2093
2094         proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2095  /*       proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2096         proto_register_subtree_array(ett, array_length(ett));
2097
2098         /* subdissector code in inactive subset */
2099         register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2100
2101         /* other COTP/ISO 8473 subdissectors */
2102         register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2103
2104         /* XXX - what about CLTP and proto_cltp? */
2105         register_dissector("ositp", dissect_ositp, proto_cotp);
2106 }
2107
2108 void proto_register_cltp(void)
2109 {
2110   /*        static hf_register_info hf[] = {
2111                 { &variable,
2112                 { "Name",           "cltp.abbreviation", TYPE, VALS_POINTER }},
2113         };*/
2114         static gint *ett[] = {
2115                 &ett_cltp,
2116         };
2117
2118         proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2119  /*       proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2120         proto_register_subtree_array(ett, array_length(ett));
2121         register_init_routine(clnp_reassemble_init);
2122 }
2123
2124 void
2125 proto_reg_handoff_clnp(void)
2126 {
2127         data_handle = find_dissector("data");
2128
2129         clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2130         dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2131         dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2132         dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2133 }