2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.80 2003/12/27 02:01:13 guy Exp $
5 * Laurent Deniel <laurent.deniel@free.fr>
6 * Ralf Schneider <Ralf.Schneider@t-online.de>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
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.
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.
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.
35 #include <epan/packet.h>
36 #include "reassemble.h"
37 #include "packet-osi.h"
38 #include "packet-osi-options.h"
39 #include "packet-isis.h"
40 #include "packet-esis.h"
43 /* protocols and fields */
45 static int proto_clnp = -1;
46 static gint ett_clnp = -1;
47 static gint ett_clnp_type = -1;
48 static gint ett_clnp_segments = -1;
49 static gint ett_clnp_segment = -1;
50 static gint ett_clnp_disc_pdu = -1;
52 static int hf_clnp_id = -1;
53 static int hf_clnp_length = -1;
54 static int hf_clnp_version = -1;
55 static int hf_clnp_ttl = -1;
56 static int hf_clnp_type = -1;
57 static int hf_clnp_pdu_length = -1;
58 static int hf_clnp_checksum = -1;
59 static int hf_clnp_dest_length = -1;
60 static int hf_clnp_dest = -1;
61 static int hf_clnp_src_length = -1;
62 static int hf_clnp_src = -1;
63 static int hf_clnp_segments = -1;
64 static int hf_clnp_segment = -1;
65 static int hf_clnp_segment_overlap = -1;
66 static int hf_clnp_segment_overlap_conflict = -1;
67 static int hf_clnp_segment_multiple_tails = -1;
68 static int hf_clnp_segment_too_long_segment = -1;
69 static int hf_clnp_segment_error = -1;
70 static int hf_clnp_reassembled_in = -1;
72 static int proto_cotp = -1;
73 static gint ett_cotp = -1;
74 static gint ett_cotp_segments = -1;
75 static gint ett_cotp_segment = -1;
77 static int hf_cotp_srcref = -1;
78 static int hf_cotp_destref = -1;
79 static int hf_cotp_type = -1;
80 static int hf_cotp_segments = -1;
81 static int hf_cotp_segment = -1;
82 static int hf_cotp_segment_overlap = -1;
83 static int hf_cotp_segment_overlap_conflict = -1;
84 static int hf_cotp_segment_multiple_tails = -1;
85 static int hf_cotp_segment_too_long_segment = -1;
86 static int hf_cotp_segment_error = -1;
87 static int hf_cotp_reassembled_in = -1;
89 static int proto_cltp = -1;
90 static gint ett_cltp = -1;
92 static int hf_cltp_type = -1;
94 static const fragment_items clnp_frag_items = {
99 &hf_clnp_segment_overlap,
100 &hf_clnp_segment_overlap_conflict,
101 &hf_clnp_segment_multiple_tails,
102 &hf_clnp_segment_too_long_segment,
103 &hf_clnp_segment_error,
104 &hf_clnp_reassembled_in,
108 static const fragment_items cotp_frag_items = {
113 &hf_cotp_segment_overlap,
114 &hf_cotp_segment_overlap_conflict,
115 &hf_cotp_segment_multiple_tails,
116 &hf_cotp_segment_too_long_segment,
117 &hf_cotp_segment_error,
118 &hf_cotp_reassembled_in,
122 static dissector_handle_t clnp_handle;
123 static dissector_handle_t data_handle;
126 * ISO 8473 OSI CLNP definition (see RFC994)
128 * _________________________________
130 * |_________________________________|
132 * |_________________________________|
133 * | Segmentation Part (optional) |
134 * |_________________________________|
135 * | Options Part (optional) |
136 * |_________________________________|
137 * | Data (optional) |
138 * |_________________________________|
141 #define ISO8473_V1 0x01 /* CLNP version 1 */
145 #define CNF_TYPE 0x1f
146 #define CNF_ERR_OK 0x20
147 #define CNF_MORE_SEGS 0x40
148 #define CNF_SEG_OK 0x80
153 #define ERQ_NPDU 0x1E
154 #define ERP_NPDU 0x1F
156 static const value_string npdu_type_abbrev_vals[] = {
165 static const value_string npdu_type_vals[] = {
167 { MD_NPDU, "Multicast Data" },
168 { ER_NPDU, "Error Report" },
169 { ERQ_NPDU, "Echo Request" },
170 { ERP_NPDU, "Echo Response" },
176 #define P_CLNP_PROTO_ID 0
177 #define P_CLNP_HDR_LEN 1
178 #define P_CLNP_VERS 2
180 #define P_CLNP_TYPE 4
181 #define P_CLNP_SEGLEN 5
182 #define P_CLNP_CKSUM 7
183 #define P_CLNP_ADDRESS_PART 9
185 /* Segmentation part */
187 struct clnp_segment {
188 gushort cng_id; /* data unit identifier */
189 gushort cng_off; /* segment offset */
190 gushort cng_tot_len; /* total length */
195 #define NSEL_NET 0x00
200 * ISO8073 OSI COTP definition (see RFC905)
203 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
205 /* TPDU definition */
207 #define ED_TPDU 0x1 /* COTP */
208 #define EA_TPDU 0x2 /* COTP */
209 #define UD_TPDU 0x4 /* CLTP */
210 #define RJ_TPDU 0x5 /* COTP */
211 #define AK_TPDU 0x6 /* COTP */
212 #define ER_TPDU 0x7 /* COTP */
213 #define DR_TPDU 0x8 /* COTP */
214 #define DC_TPDU 0xC /* COTP */
215 #define CC_TPDU 0xD /* COTP */
216 #define CR_TPDU 0xE /* COTP */
217 #define DT_TPDU 0xF /* COTP */
219 static const value_string cotp_tpdu_type_abbrev_vals[] = {
233 static const value_string cltp_tpdu_type_abbrev_vals[] = {
245 #define P_TPDU_NR_0_1 2
246 #define P_TPDU_NR_234 4
247 #define P_VAR_PART_NDT 5
248 #define P_VAR_PART_EDT 8
249 #define P_VAR_PART_DC 6
250 #define P_CDT_IN_AK 8
251 #define P_CDT_IN_RJ 8
252 #define P_REJECT_ER 4
253 #define P_REASON_IN_DR 6
254 #define P_CLASS_OPTION 6
256 /* TPDU length indicator */
258 #define LI_NORMAL_DT_CLASS_01 2
259 #define LI_NORMAL_DT_WITH_CHECKSUM 8
260 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
261 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
262 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
263 #define LI_NORMAL_EA_WITH_CHECKSUM 8
264 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
265 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
266 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
267 #define LI_NORMAL_RJ 4
268 #define LI_EXTENDED_RJ 9
274 /* XXX - can we always decide this based on whether the length
275 indicator is odd or not? What if the variable part has an odd
277 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
281 #define VP_ACK_TIME 0x85
282 #define VP_RES_ERROR 0x86
283 #define VP_PRIORITY 0x87
284 #define VP_TRANSIT_DEL 0x88
285 #define VP_THROUGHPUT 0x89
286 #define VP_SEQ_NR 0x8A /* in AK */
287 #define VP_REASSIGNMENT 0x8B
288 #define VP_FLOW_CNTL 0x8C /* in AK */
289 #define VP_TPDU_SIZE 0xC0
290 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
291 #define VP_DST_TSAP 0xC2
292 #define VP_CHECKSUM 0xC3
293 #define VP_VERSION_NR 0xC4
294 #define VP_PROTECTION 0xC5
295 #define VP_OPT_SEL 0xC6
296 #define VP_PROTO_CLASS 0xC7
297 #define VP_PREF_MAX_TPDU_SIZE 0xF0
298 #define VP_INACTIVITY_TIMER 0xF2
300 static const value_string tp_vpart_type_vals[] = {
301 { VP_ACK_TIME, "ack time" },
302 { VP_RES_ERROR, "res error" },
303 { VP_PRIORITY, "priority" },
304 { VP_TRANSIT_DEL, "transit delay" },
305 { VP_THROUGHPUT, "throughput" },
306 { VP_SEQ_NR, "seq number" },
307 { VP_REASSIGNMENT, "reassignment" },
308 { VP_FLOW_CNTL, "flow control" },
309 { VP_TPDU_SIZE, "tpdu-size" },
310 { VP_SRC_TSAP, "src-tsap" },
311 { VP_DST_TSAP, "dst-tsap" },
312 { VP_CHECKSUM, "checksum" },
313 { VP_VERSION_NR, "version" },
314 { VP_PROTECTION, "protection" },
315 { VP_OPT_SEL, "options" },
316 { VP_PROTO_CLASS, "proto class" },
317 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
323 #define EXTRACT_SHORT(p) pntohs(p)
324 #define EXTRACT_LONG(p) pntohl(p)
326 /* global variables */
328 /* List of dissectors to call for COTP packets put atop the Inactive
330 static heur_dissector_list_t cotp_is_heur_subdissector_list;
331 /* List of dissectors to call for COTP packets put atop CLNP */
332 static heur_dissector_list_t cotp_heur_subdissector_list;
333 /* List of dissectors to call for CLNP packets */
334 static heur_dissector_list_t clnp_heur_subdissector_list;
337 * Reassembly of CLNP.
339 static GHashTable *clnp_segment_table = NULL;
340 static GHashTable *clnp_reassembled_table = NULL;
343 * Reassembly of COTP.
345 static GHashTable *cotp_segment_table = NULL;
346 static GHashTable *cotp_reassembled_table = NULL;
349 static guint tp_nsap_selector = NSEL_TP;
350 static gboolean always_decode_transport = FALSE;
351 static gboolean clnp_reassemble = FALSE;
352 static gboolean cotp_reassemble = FALSE;
354 /* function definitions */
356 #define MAX_TSAP_LEN 32
357 static gchar *print_tsap(const guchar *tsap, int length)
360 static gchar str[3][MAX_TSAP_LEN * 2 + 3]; /* TSAP in hex + '0x' + NULL */
363 gboolean allprintable;
366 if (cur == &str[0][0]) {
368 } else if (cur == &str[1][0]) {
376 if (length <= 0 || length > MAX_TSAP_LEN)
377 sprintf(cur, "<unsupported TSAP length>");
380 for (i=0;i<length;i++) {
381 /* If any byte is not printable ASCII, display the TSAP as a
382 series of hex byte values rather than as a string; this
383 means that, for example, accented letters will cause it
384 to be displayed as hex, but it also means that byte values
385 such as 0xff and 0xfe, which *are* printable ISO 8859/x
386 characters, won't be treated as printable - 0xfffffffe
387 is probably binary, not text. */
388 if (!(isascii(tsap[i]) && isprint(tsap[i]))) {
396 while (length != 0) {
398 sprintf(tmp, "%c", *tsap ++);
400 sprintf(tmp, "%02x", *tsap ++);
409 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
410 int vp_length, int class_option,
415 guint16 s, s1,s2,s3,s4;
416 guint32 t1, t2, t3, t4;
417 guint32 pref_max_tpdu_size;
419 while (vp_length != 0) {
420 code = tvb_get_guint8(tvb, offset);
421 proto_tree_add_text(tree, tvb, offset, 1,
422 "Parameter code: 0x%02x (%s)",
424 val_to_str(code, tp_vpart_type_vals, "Unknown"));
430 length = tvb_get_guint8(tvb, offset);
431 proto_tree_add_text(tree, tvb, offset, 1,
432 "Parameter length: %u", length);
439 s = tvb_get_ntohs(tvb, offset);
440 proto_tree_add_text(tree, tvb, offset, length,
441 "Ack time (ms): %u", s);
447 proto_tree_add_text(tree, tvb, offset, 1,
448 "Residual error rate, target value: 10^%u",
449 tvb_get_guint8(tvb, offset));
454 proto_tree_add_text(tree, tvb, offset, 1,
455 "Residual error rate, minimum acceptable: 10^%u",
456 tvb_get_guint8(tvb, offset));
462 proto_tree_add_text(tree, tvb, offset, 1,
463 "Residual error rate, TSDU size of interest: %u",
464 1<<tvb_get_guint8(tvb, offset));
472 s = tvb_get_ntohs(tvb, offset);
473 proto_tree_add_text(tree, tvb, offset, length,
480 s1 = tvb_get_ntohs(tvb, offset);
481 proto_tree_add_text(tree, tvb, offset, 2,
482 "Transit delay, target value, calling-called: %u ms", s1);
487 s2 = tvb_get_ntohs(tvb, offset);
488 proto_tree_add_text(tree, tvb, offset, 2,
489 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
494 s3 = tvb_get_ntohs(tvb, offset);
495 proto_tree_add_text(tree, tvb, offset, 2,
496 "Transit delay, target value, called-calling: %u ms", s3);
501 s4 = tvb_get_ntohs(tvb, offset);
502 proto_tree_add_text(tree, tvb, offset, 2,
503 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
510 t1 = tvb_get_ntoh24(tvb, offset);
511 proto_tree_add_text(tree, tvb, offset, 3,
512 "Maximum throughput, target value, calling-called: %u o/s", t1);
517 t2 = tvb_get_ntoh24(tvb, offset);
518 proto_tree_add_text(tree, tvb, offset, 3,
519 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
524 t3 = tvb_get_ntoh24(tvb, offset);
525 proto_tree_add_text(tree, tvb, offset, 3,
526 "Maximum throughput, target value, called-calling: %u o/s", t3);
531 t4 = tvb_get_ntoh24(tvb, offset);
532 proto_tree_add_text(tree, tvb, offset, 3,
533 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
538 if (length != 0) { /* XXX - should be 0 or 12 */
539 t1 = tvb_get_ntoh24(tvb, offset);
540 proto_tree_add_text(tree, tvb, offset, 3,
541 "Average throughput, target value, calling-called: %u o/s", t1);
546 t2 = tvb_get_ntoh24(tvb, offset);
547 proto_tree_add_text(tree, tvb, offset, 3,
548 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
553 t3 = tvb_get_ntoh24(tvb, offset);
554 proto_tree_add_text(tree, tvb, offset, 3,
555 "Average throughput, target value, called-calling: %u o/s", t3);
560 t4 = tvb_get_ntoh24(tvb, offset);
561 proto_tree_add_text(tree, tvb, offset, 3,
562 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
570 proto_tree_add_text(tree, tvb, offset, 2,
571 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
576 case VP_REASSIGNMENT:
577 proto_tree_add_text(tree, tvb, offset, 2,
578 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
584 proto_tree_add_text(tree, tvb, offset, 4,
585 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
590 proto_tree_add_text(tree, tvb, offset, 2,
591 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
596 proto_tree_add_text(tree, tvb, offset, 2,
597 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
605 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
606 proto_tree_add_text(tree, tvb, offset, length,
607 "TPDU size: %u", 1 << c1);
613 proto_tree_add_text(tree, tvb, offset, length,
615 print_tsap(tvb_get_ptr(tvb, offset, length), length));
621 proto_tree_add_text(tree, tvb, offset, length,
623 print_tsap(tvb_get_ptr(tvb, offset, length), length));
629 proto_tree_add_text(tree, tvb, offset, length,
630 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
636 c1 = tvb_get_guint8(tvb, offset);
637 proto_tree_add_text(tree, tvb, offset, length,
644 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
645 switch (class_option) {
649 proto_tree_add_text(tree, tvb, offset, 1,
650 "Use of network expedited data");
652 proto_tree_add_text(tree, tvb, offset, 1,
653 "Non use of network expedited data");
655 proto_tree_add_text(tree, tvb, offset, 1,
656 "Use of Receipt confirmation");
658 proto_tree_add_text(tree, tvb, offset, 1,
659 "Use of explicit AK variant");
664 proto_tree_add_text(tree, tvb, offset, 1,
665 "Non-use 16 bit checksum in class 4");
667 proto_tree_add_text(tree, tvb, offset, 1,
668 "Use 16 bit checksum ");
672 proto_tree_add_text(tree, tvb, offset, 1,
673 "Use of transport expedited data transfer");
675 proto_tree_add_text(tree, tvb, offset, 1,
676 "Non-use of transport expedited data transfer");
681 case VP_PREF_MAX_TPDU_SIZE:
685 pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
689 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
693 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
697 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
701 proto_tree_add_text(tree, tvb, offset, length,
702 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
706 proto_tree_add_text(tree, tvb, offset, length,
707 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
712 case VP_INACTIVITY_TIMER:
713 proto_tree_add_text(tree, tvb, offset, length,
714 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
719 case VP_PROTECTION: /* user-defined */
720 case VP_PROTO_CLASS: /* todo */
721 default: /* unknown, no decoding */
722 proto_tree_add_text(tree, tvb, offset, length,
723 "Parameter value: <not shown>");
733 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
734 packet_info *pinfo, proto_tree *tree)
736 proto_tree *cotp_tree;
738 guint16 dst_ref, src_ref;
745 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
747 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
749 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
751 pinfo->srcport = src_ref;
752 pinfo->destport = dst_ref;
754 case (128+0): str = "Normal Disconnect"; break;
755 case (128+1): str = "Remote transport entity congestion"; break;
756 case (128+2): str = "Connection negotiation failed"; break;
757 case (128+3): str = "Duplicate source reference"; break;
758 case (128+4): str = "Mismatched references"; break;
759 case (128+5): str = "Protocol error"; break;
760 case (128+7): str = "Reference overflow"; break;
761 case (128+8): str = "Connection requestion refused"; break;
762 case (128+10):str = "Header or parameter length invalid"; break;
763 case (0): str = "Reason not specified"; break;
764 case (1): str = "Congestion at TSAP"; break;
765 case (2): str = "Session entity not attached to TSAP"; break;
766 case (3): str = "Address unknown"; break;
772 if (check_col(pinfo->cinfo, COL_INFO))
773 col_append_fstr(pinfo->cinfo, COL_INFO,
774 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
778 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
779 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
780 proto_tree_add_text(cotp_tree, tvb, offset, 1,
781 "Length indicator: %u", li);
782 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu,
783 "TPDU code: 0x%x (DR)", tpdu);
784 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
785 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset + 4, 2, src_ref);
786 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
793 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
794 offset += tvb_length_remaining(tvb, offset);
795 /* we dissected all of the containing PDU */
799 } /* ositp_decode_DR */
801 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
802 packet_info *pinfo, proto_tree *tree,
803 gboolean uses_inactive_subset,
804 gboolean *subdissector_found)
806 proto_tree *cotp_tree = NULL;
808 gboolean is_extended;
809 gboolean is_class_234;
813 guint32 fragment_length = 0;
815 tvbuff_t *reassembled_tvb = NULL;
816 fragment_data *fd_head;
818 /* VP_CHECKSUM is the only parameter allowed in the variable part.
819 (This means we may misdissect this if the packet is bad and
820 contains other parameters.) */
823 case LI_NORMAL_DT_WITH_CHECKSUM :
824 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
828 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
829 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
830 if ( tpdu_nr & 0x80 )
831 tpdu_nr = tpdu_nr & 0x7F;
836 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
839 case LI_EXTENDED_DT_WITH_CHECKSUM :
840 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
844 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
845 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
846 if ( tpdu_nr & 0x80000000 )
847 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
852 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
855 case LI_NORMAL_DT_CLASS_01 :
856 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
857 if ( tpdu_nr & 0x80 )
858 tpdu_nr = tpdu_nr & 0x7F;
862 is_class_234 = FALSE;
866 default : /* bad TPDU */
872 pinfo->destport = dst_ref;
874 pinfo->fragmented = fragment;
875 if (check_col(pinfo->cinfo, COL_INFO)) {
877 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
880 (fragment)? "(fragment)" : "");
882 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) %s",
884 (fragment)? "(fragment)" : "");
889 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
890 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
891 proto_tree_add_text(cotp_tree, tvb, offset, 1,
892 "Length indicator: %u", li);
897 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
898 "TPDU code: 0x%x (DT)", tpdu);
905 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
912 proto_tree_add_text(cotp_tree, tvb, offset, 4,
913 "TPDU number: 0x%08x (%s)",
915 (fragment)? "fragment":"complete");
921 proto_tree_add_text(cotp_tree, tvb, offset, 1,
922 "TPDU number: 0x%02x (%s)",
924 (fragment)? "fragment":"complete");
931 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
934 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
935 if (cotp_reassemble) {
936 fragment_length = tvb_length(next_tvb);
938 * XXX - these sequence numbers are connection sequence number,
939 * not segment sequence numbers - the first segment of a
940 * segmented packet doesn't have a specific sequence number (e.g., 0
941 * or 1), it has whatever the appropriate sequence number is for
942 * it in the connection.
944 fd_head = fragment_add_seq_check(next_tvb, 0, pinfo, dst_ref,
946 cotp_reassembled_table,
948 fragment_length, fragment);
951 /* This is the last packet */
952 reassembled_tvb = tvb_new_real_data(fd_head->data,
955 tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
956 add_new_data_source(pinfo, reassembled_tvb, "Reassembled COTP");
958 show_fragment_seq_tree(fd_head,
961 pinfo, reassembled_tvb);
962 pinfo->fragmented = fragment;
963 next_tvb = reassembled_tvb;
966 if (fragment && reassembled_tvb == NULL) {
967 proto_tree_add_text(cotp_tree, tvb, offset, -1,
968 "User data (%u byte%s)", fragment_length,
969 plurality(fragment_length, "", "s"));
974 if (uses_inactive_subset) {
975 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
977 *subdissector_found = TRUE;
979 /* Fill in other Dissectors using inactive subset here */
980 call_dissector(data_handle,next_tvb, pinfo, tree);
984 * We dissect payload if one of the following is TRUE:
986 * - Reassembly option for COTP in preferences is unchecked
987 * - Reassembly option is checked and this packet is the last fragment
989 if ( (!cotp_reassemble) ||
990 ((cotp_reassemble) && (!fragment))) {
991 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
993 *subdissector_found = TRUE;
995 call_dissector(data_handle,next_tvb, pinfo, tree);
1000 offset += tvb_length_remaining(tvb, offset);
1001 /* we dissected all of the containing PDU */
1005 } /* ositp_decode_DT */
1007 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1008 packet_info *pinfo, proto_tree *tree)
1010 proto_tree *cotp_tree = NULL;
1012 gboolean is_extended;
1017 /* ED TPDUs are never fragmented */
1019 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1020 (This means we may misdissect this if the packet is bad and
1021 contains other parameters.) */
1024 case LI_NORMAL_DT_WITH_CHECKSUM :
1025 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1029 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1030 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1031 if ( tpdu_nr & 0x80 )
1032 tpdu_nr = tpdu_nr & 0x7F;
1035 is_extended = FALSE;
1038 case LI_EXTENDED_DT_WITH_CHECKSUM :
1039 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1043 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1044 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1045 if ( tpdu_nr & 0x80000000 )
1046 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1052 default : /* bad TPDU */
1058 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1060 pinfo->destport = dst_ref;
1062 if (check_col(pinfo->cinfo, COL_INFO))
1063 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1067 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1068 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1069 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1070 "Length indicator: %u", li);
1075 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1076 "TPDU code: 0x%x (ED)", tpdu);
1082 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1088 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1089 "TPDU number: 0x%02x", tpdu_nr);
1095 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1096 "TPDU number: 0x%02x", tpdu_nr);
1103 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1106 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1107 call_dissector(data_handle,next_tvb, pinfo, tree);
1109 offset += tvb_length_remaining(tvb, offset);
1110 /* we dissected all of the containing PDU */
1114 } /* ositp_decode_ED */
1116 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1117 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1119 proto_tree *cotp_tree;
1127 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1129 case LI_EXTENDED_RJ :
1130 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1131 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1139 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1141 pinfo->destport = dst_ref;
1143 if (check_col(pinfo->cinfo, COL_INFO))
1144 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1148 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1149 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1150 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1151 "Length indicator: %u", li);
1152 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu,
1153 "TPDU code: 0x%x (RJ)", tpdu);
1154 if (li == LI_NORMAL_RJ)
1155 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1157 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1158 if (li == LI_NORMAL_RJ)
1159 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1160 "Your TPDU number: 0x%02x", tpdu_nr);
1162 proto_tree_add_text(cotp_tree, tvb, offset + 4, 4,
1163 "Your TPDU number: 0x%02x", tpdu_nr);
1164 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1165 "Credit: 0x%02x", credit);
1173 } /* ositp_decode_RJ */
1175 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1176 packet_info *pinfo, proto_tree *tree,
1177 gboolean uses_inactive_subset,
1178 gboolean *subdissector_found)
1181 /* CC & CR decoding in the same function */
1183 proto_tree *cotp_tree = NULL;
1185 guint16 dst_ref, src_ref;
1186 guchar class_option;
1189 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1191 class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1192 if (class_option > 4)
1195 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1196 pinfo->srcport = src_ref;
1197 pinfo->destport = dst_ref;
1198 if (check_col(pinfo->cinfo, COL_INFO))
1199 col_append_fstr(pinfo->cinfo, COL_INFO,
1200 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1201 (tpdu == CR_TPDU) ? "CR" : "CC",
1206 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1207 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1208 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1209 "Length indicator: %u", li);
1214 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1215 "TPDU code: 0x%x (%s)", tpdu,
1216 (tpdu == CR_TPDU) ? "CR" : "CC");
1222 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1227 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1232 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1233 "Class option: 0x%02x", class_option);
1239 ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1242 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1243 if (!uses_inactive_subset){
1244 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1246 *subdissector_found = TRUE;
1248 call_dissector(data_handle,next_tvb, pinfo, tree);
1252 call_dissector(data_handle, next_tvb, pinfo, tree);
1253 offset += tvb_length_remaining(tvb, offset);
1254 /* we dissected all of the containing PDU */
1258 } /* ositp_decode_CC */
1260 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1261 packet_info *pinfo, proto_tree *tree)
1263 proto_tree *cotp_tree = NULL;
1265 guint16 dst_ref, src_ref;
1270 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1271 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1273 pinfo->srcport = src_ref;
1274 pinfo->destport = dst_ref;
1275 if (check_col(pinfo->cinfo, COL_INFO))
1276 col_append_fstr(pinfo->cinfo, COL_INFO,
1277 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1282 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1283 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1284 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1285 "Length indicator: %u", li);
1290 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1291 "TPDU code: 0x%x (DC)", tpdu);
1297 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1302 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1307 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1312 } /* ositp_decode_DC */
1314 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1315 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1317 proto_tree *cotp_tree = NULL;
1326 if (is_LI_NORMAL_AK(li)) {
1328 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1329 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1332 pinfo->destport = dst_ref;
1333 if (check_col(pinfo->cinfo, COL_INFO))
1334 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1338 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1339 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1340 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1341 "Length indicator: %u", li);
1346 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1347 "TPDU code: 0x%x (AK)", tpdu);
1348 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1355 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1360 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1361 "Your TPDU number: 0x%02x", tpdu_nr);
1367 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1370 } else { /* extended format */
1372 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1373 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1374 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1376 if (check_col(pinfo->cinfo, COL_INFO))
1377 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1381 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1382 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1383 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1384 "Length indicator: %u", li);
1389 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1390 "TPDU code: 0x%x (AK)", tpdu);
1396 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1401 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1402 "Your TPDU number: 0x%08x", tpdu_nr);
1408 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1409 "Credit: 0x%04x", cdt_in_ak);
1415 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1418 } /* is_LI_NORMAL_AK */
1422 } /* ositp_decode_AK */
1424 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1425 packet_info *pinfo, proto_tree *tree)
1427 proto_tree *cotp_tree = NULL;
1429 gboolean is_extended;
1436 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1437 (This means we may misdissect this if the packet is bad and
1438 contains other parameters.) */
1441 case LI_NORMAL_EA_WITH_CHECKSUM :
1442 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1443 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1447 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1448 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1449 is_extended = FALSE;
1452 case LI_EXTENDED_EA_WITH_CHECKSUM :
1453 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1454 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1458 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1459 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1463 default : /* bad TPDU */
1469 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1471 pinfo->destport = dst_ref;
1472 if (check_col(pinfo->cinfo, COL_INFO))
1473 col_append_fstr(pinfo->cinfo, COL_INFO,
1474 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1477 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1478 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1479 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1480 "Length indicator: %u", li);
1485 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1486 "TPDU code: 0x%x (EA)", tpdu);
1492 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1498 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1499 "Your TPDU number: 0x%08x", tpdu_nr);
1505 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1506 "Your TPDU number: 0x%02x", tpdu_nr);
1513 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1518 } /* ositp_decode_EA */
1520 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1521 packet_info *pinfo, proto_tree *tree)
1523 proto_tree *cotp_tree;
1531 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1533 str = "Reason not specified";
1536 str = "Invalid parameter code";
1539 str = "Invalid TPDU type";
1542 str = "Invalid parameter value";
1550 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1552 pinfo->destport = dst_ref;
1553 if (check_col(pinfo->cinfo, COL_INFO))
1554 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1557 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1558 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1559 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1560 "Length indicator: %u", li);
1561 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu,
1562 "TPDU code: 0x%x (ER)", tpdu);
1563 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1564 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1565 "Reject cause: %s", str);
1572 } /* ositp_decode_ER */
1574 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1575 packet_info *pinfo, proto_tree *tree)
1578 proto_tree *cltp_tree = NULL;
1581 if (check_col(pinfo->cinfo, COL_INFO))
1582 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1585 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1586 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1587 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1588 "Length indicator: %u", li);
1593 proto_tree_add_uint_format(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu,
1594 "TPDU code: 0x%x (UD)", tpdu);
1600 ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1603 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1604 call_dissector(data_handle,next_tvb, pinfo, tree);
1605 offset += tvb_length_remaining(tvb, offset);
1606 /* we dissected all of the containing PDU */
1610 } /* ositp_decode_UD */
1612 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1615 There doesn't seem to be any way in which the OSI network layer protocol
1616 distinguishes between COTP and CLTP, but the first two octets of both
1617 protocols' headers mean the same thing - length and PDU type - and the
1618 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1619 both of them here. */
1620 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1621 proto_tree *tree, gboolean uses_inactive_subset)
1624 guint8 li, tpdu, cdt;
1625 gboolean first_tpdu = TRUE;
1627 gboolean found_ositp = FALSE;
1628 gboolean is_cltp = FALSE;
1629 gboolean subdissector_found = FALSE;
1631 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_cotp)))
1632 return FALSE; /* COTP has been disabled */
1633 /* XXX - what about CLTP? */
1635 pinfo->current_proto = "COTP";
1637 /* Initialize the COL_INFO field; each of the TPDUs will have its
1638 information appended. */
1639 if (check_col(pinfo->cinfo, COL_INFO))
1640 col_add_str(pinfo->cinfo, COL_INFO, "");
1642 while (tvb_offset_exists(tvb, offset)) {
1644 if (check_col(pinfo->cinfo, COL_INFO))
1645 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1647 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1648 if (check_col(pinfo->cinfo, COL_INFO))
1649 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1651 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1656 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1657 if (tpdu == UD_TPDU)
1658 pinfo->current_proto = "CLTP"; /* connectionless transport */
1659 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1664 new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1665 uses_inactive_subset, &subdissector_found);
1668 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1671 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1672 uses_inactive_subset, &subdissector_found);
1675 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1678 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1681 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1684 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1687 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1690 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1693 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1697 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1698 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1699 new_offset = -1; /* bad PDU type */
1703 if (new_offset == -1) { /* incorrect TPDU */
1705 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1711 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1712 is either COTP or CLTP. */
1713 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1714 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1718 offset = new_offset;
1722 } /* dissect_ositp_internal */
1724 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1726 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1727 call_dissector(data_handle,tvb, pinfo, tree);
1731 * CLNP part / main entry point
1734 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1736 proto_tree *clnp_tree = NULL;
1738 guint8 cnf_proto_id;
1743 char flag_string[6+1];
1744 char *pdu_type_string;
1745 proto_tree *type_tree;
1746 guint16 segment_length;
1748 guint16 segment_offset = 0;
1750 cksum_status_t cksum_status;
1752 guchar src_len, dst_len, nsel, opt_len = 0;
1753 const guint8 *dst_addr, *src_addr;
1756 proto_tree *discpdu_tree;
1757 gboolean save_in_error_pkt;
1758 fragment_data *fd_head;
1760 gboolean update_col_info = TRUE;
1761 gboolean save_fragmented;
1763 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1764 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1765 if (check_col(pinfo->cinfo, COL_INFO))
1766 col_clear(pinfo->cinfo, COL_INFO);
1768 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1769 if (cnf_proto_id == NLPID_NULL) {
1770 if (check_col(pinfo->cinfo, COL_INFO))
1771 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1773 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1774 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1775 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1779 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1780 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1784 /* return if version not known */
1785 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1786 if (cnf_vers != ISO8473_V1) {
1787 call_dissector(data_handle,tvb, pinfo, tree);
1791 /* fixed part decoding */
1792 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1793 opt_len = cnf_hdr_len;
1796 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1797 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1798 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1800 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1802 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1804 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1805 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1807 "Holding Time : %u (%u.%u secs)",
1808 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1811 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1812 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1813 "Unknown (0x%02x)");
1814 flag_string[0] = '\0';
1815 if (cnf_type & CNF_SEG_OK)
1816 strcat(flag_string, "S ");
1817 if (cnf_type & CNF_MORE_SEGS)
1818 strcat(flag_string, "M ");
1819 if (cnf_type & CNF_ERR_OK)
1820 strcat(flag_string, "E ");
1822 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1824 "PDU Type : 0x%02x (%s%s)",
1828 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1829 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1830 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1831 "Segmentation permitted",
1832 "Segmentation not permitted"));
1833 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1834 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1837 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1838 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1839 "Report error if PDU discarded",
1840 "Don't report error if PDU discarded"));
1841 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1842 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1843 npdu_type_vals, "%s"));
1846 /* If we don't have the full header - i.e., not enough to see the
1847 segmentation part and determine whether this datagram is segmented
1848 or not - set the Info column now; we'll get an exception before
1849 we set it otherwise. */
1851 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1852 if (check_col(pinfo->cinfo, COL_INFO))
1853 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1856 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1857 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1858 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1860 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1862 switch (cksum_status) {
1866 * No checksum present, or not enough of the header present to
1869 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1872 "Checksum : 0x%04x",
1878 * Checksum is correct.
1880 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1883 "Checksum : 0x%04x (correct)",
1889 * Checksum is not correct.
1891 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1894 "Checksum : 0x%04x (incorrect)",
1898 opt_len -= 9; /* Fixed part of Hesder */
1903 offset = P_CLNP_ADDRESS_PART;
1904 dst_len = tvb_get_guint8(tvb, offset);
1905 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1906 nsel = tvb_get_guint8(tvb, offset + dst_len);
1907 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1908 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1911 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1913 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1916 print_nsap_net(dst_addr, dst_len));
1917 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1918 offset + 1 + dst_len, 1, src_len);
1919 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1920 offset + dst_len + 2, src_len,
1923 print_nsap_net(src_addr, src_len));
1925 opt_len -= dst_len + src_len +2;
1928 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1929 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1930 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1931 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1933 /* Segmentation Part */
1935 offset += dst_len + src_len + 2;
1937 if (cnf_type & CNF_SEG_OK) {
1938 struct clnp_segment seg; /* XXX - not used */
1939 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1941 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1942 du_id = tvb_get_ntohs(tvb, offset);
1944 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1945 "Data unit identifier: %06u",
1947 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1948 "Segment offset : %6u",
1950 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1951 "Total length : %6u",
1952 tvb_get_ntohs(tvb, offset + 4));
1960 /* To do : decode options */
1962 proto_tree_add_text(clnp_tree, tvb, offset,
1963 cnf_hdr_len - offset,
1964 "Options/Data: <not shown>");
1966 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1968 dissect_osi_options( opt_len,
1969 tvb, offset, clnp_tree );
1972 /* Length of CLNP datagram plus headers above it. */
1973 len = segment_length;
1975 offset = cnf_hdr_len;
1977 /* If clnp_reassemble is on, this is a segment, we have all the
1978 * data in the segment, and the checksum is valid, then just add the
1979 * segment to the hashtable.
1981 save_fragmented = pinfo->fragmented;
1982 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1983 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1984 tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
1985 cksum_status != CKSUM_NOT_OK) {
1986 fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table,
1987 clnp_reassembled_table, segment_offset,
1988 segment_length - cnf_hdr_len,
1989 cnf_type & CNF_MORE_SEGS);
1991 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
1992 fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
1994 /* If this is the first segment, dissect its contents, otherwise
1995 just show it as a segment.
1997 XXX - if we eventually don't save the reassembled contents of all
1998 segmented datagrams, we may want to always reassemble. */
1999 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
2000 /* Not the first segment - don't dissect it. */
2003 /* First segment, or not segmented. Dissect what we have here. */
2005 /* Get a tvbuff for the payload. */
2006 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
2009 * If this is the first segment, but not the only segment,
2010 * tell the next protocol that.
2012 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
2013 pinfo->fragmented = TRUE;
2015 pinfo->fragmented = FALSE;
2019 if (next_tvb == NULL) {
2020 /* Just show this as a segment. */
2021 if (check_col(pinfo->cinfo, COL_INFO))
2022 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
2023 pdu_type_string, flag_string, segment_offset);
2025 /* As we haven't reassembled anything, we haven't changed "pi", so
2026 we don't have to restore it. */
2027 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
2029 pinfo->fragmented = save_fragmented;
2033 if (tvb_offset_exists(tvb, offset)) {
2034 switch (cnf_type & CNF_TYPE) {
2038 /* Continue with COTP if any data.
2039 XXX - if this isn't the first Derived PDU of a segmented Initial
2042 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
2043 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
2044 pinfo->fragmented = save_fragmented;
2045 return; /* yes, it appears to be COTP or CLTP */
2048 if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
2050 pinfo->fragmented = save_fragmented;
2051 return; /* yes, it appears to be COTP or CLTP */
2057 /* The payload is the header and "none, some, or all of the data
2058 part of the discarded PDU", i.e. it's like an ICMP error;
2059 dissect it as a CLNP PDU. */
2060 if (check_col(pinfo->cinfo, COL_INFO))
2061 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2063 next_length = tvb_length_remaining(tvb, offset);
2064 if (next_length != 0) {
2065 /* We have payload; dissect it. */
2066 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2068 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2070 /* Save the current value of the "we're inside an error packet"
2071 flag, and set that flag; subdissectors may treat packets
2072 that are the payload of error packets differently from
2074 save_in_error_pkt = pinfo->in_error_pkt;
2075 pinfo->in_error_pkt = TRUE;
2077 call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
2079 /* Restore the "we're inside an error packet" flag. */
2080 pinfo->in_error_pkt = save_in_error_pkt;
2083 pinfo->fragmented = save_fragmented;
2084 return; /* we're done with this PDU */
2088 /* XXX - dissect this */
2092 if (check_col(pinfo->cinfo, COL_INFO))
2093 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2094 call_dissector(data_handle,next_tvb, pinfo, tree);
2095 pinfo->fragmented = save_fragmented;
2096 } /* dissect_clnp */
2099 clnp_reassemble_init(void)
2101 fragment_table_init(&clnp_segment_table);
2102 reassembled_table_init(&clnp_reassembled_table);
2106 cotp_reassemble_init(void)
2108 fragment_table_init(&cotp_segment_table);
2109 reassembled_table_init(&cotp_reassembled_table);
2112 void proto_register_clnp(void)
2114 static hf_register_info hf[] = {
2116 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2117 VALS(nlpid_vals), 0x0, "", HFILL }},
2120 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2123 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2126 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2129 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2131 { &hf_clnp_pdu_length,
2132 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2134 { &hf_clnp_checksum,
2135 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2137 { &hf_clnp_dest_length,
2138 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2141 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2143 { &hf_clnp_src_length,
2144 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2147 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2149 { &hf_clnp_segment_overlap,
2150 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2151 "Segment overlaps with other segments", HFILL }},
2153 { &hf_clnp_segment_overlap_conflict,
2154 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2155 "Overlapping segments contained conflicting data", HFILL }},
2157 { &hf_clnp_segment_multiple_tails,
2158 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2159 "Several tails were found when reassembling the packet", HFILL }},
2161 { &hf_clnp_segment_too_long_segment,
2162 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2163 "Segment contained data past end of packet", HFILL }},
2165 { &hf_clnp_segment_error,
2166 { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2167 "Reassembly error due to illegal segments", HFILL }},
2170 { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2171 "CLNP Segment", HFILL }},
2173 { &hf_clnp_segments,
2174 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2175 "CLNP Segments", HFILL }},
2177 { &hf_clnp_reassembled_in,
2178 { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2179 "This CLNP packet is reassembled in this frame", HFILL }}
2181 static gint *ett[] = {
2189 module_t *clnp_module;
2191 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2192 proto_register_field_array(proto_clnp, hf, array_length(hf));
2193 proto_register_subtree_array(ett, array_length(ett));
2194 register_dissector("clnp", dissect_clnp, proto_clnp);
2195 register_heur_dissector_list("clnp", &clnp_heur_subdissector_list);
2196 register_init_routine(clnp_reassemble_init);
2197 register_init_routine(cotp_reassemble_init);
2199 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2200 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2201 "NSAP selector for Transport Protocol (last byte in hexa)",
2202 "NSAP selector for Transport Protocol (last byte in hexa)",
2203 16, &tp_nsap_selector);
2204 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2205 "Always try to decode NSDU as transport PDUs",
2206 "Always try to decode NSDU as transport PDUs",
2207 &always_decode_transport);
2208 prefs_register_bool_preference(clnp_module, "reassemble",
2209 "Reassemble segmented CLNP datagrams",
2210 "Whether segmented CLNP datagrams should be reassembled",
2215 proto_reg_handoff_clnp(void)
2217 data_handle = find_dissector("data");
2219 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2220 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2221 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2222 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2225 void proto_register_cotp(void)
2227 static hf_register_info hf[] = {
2229 { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
2230 "Source address reference", HFILL}},
2232 { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
2233 "Destination address reference", HFILL}},
2235 { "COTP PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2236 "COTP PDU Type", HFILL}},
2237 { &hf_cotp_segment_overlap,
2238 { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2239 "Segment overlaps with other segments", HFILL }},
2240 { &hf_cotp_segment_overlap_conflict,
2241 { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2242 "Overlapping segments contained conflicting data", HFILL }},
2243 { &hf_cotp_segment_multiple_tails,
2244 { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2245 "Several tails were found when reassembling the packet", HFILL }},
2246 { &hf_cotp_segment_too_long_segment,
2247 { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2248 "Segment contained data past end of packet", HFILL }},
2249 { &hf_cotp_segment_error,
2250 { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2251 "Reassembly error due to illegal segments", HFILL }},
2253 { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2254 "COTP Segment", HFILL }},
2255 { &hf_cotp_segments,
2256 { "COTP Segments", "cotp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2257 "COTP Segments", HFILL }},
2258 { &hf_cotp_reassembled_in,
2259 { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2260 "This COTP packet is reassembled in this frame", HFILL }},
2263 static gint *ett[] = {
2269 module_t *cotp_module;
2271 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2272 proto_register_field_array(proto_cotp, hf, array_length(hf));
2273 proto_register_subtree_array(ett, array_length(ett));
2274 cotp_module = prefs_register_protocol(proto_cotp, NULL);
2276 prefs_register_bool_preference(cotp_module, "reassemble",
2277 "Reassemble segmented COTP datagrams",
2278 "Whether segmented COTP datagrams should be reassembled",
2281 /* subdissector code in inactive subset */
2282 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2284 /* other COTP/ISO 8473 subdissectors */
2285 register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2287 /* XXX - what about CLTP and proto_cltp? */
2288 register_dissector("ositp", dissect_ositp, proto_cotp);
2291 void proto_register_cltp(void)
2293 static hf_register_info hf[] = {
2295 { "CLTP PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
2296 "CLTP PDU Type", HFILL}},
2298 static gint *ett[] = {
2302 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2303 proto_register_field_array(proto_cltp, hf, array_length(hf));
2304 proto_register_subtree_array(ett, array_length(ett));