2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.78 2003/10/06 20:46:50 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);
937 fd_head = fragment_add_seq_check(next_tvb, 0, pinfo, dst_ref,
939 cotp_reassembled_table,
941 fragment_length, fragment);
944 /* This is the last packet */
945 reassembled_tvb = tvb_new_real_data(fd_head->data,
948 tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
949 add_new_data_source(pinfo, reassembled_tvb, "Reassembled COTP");
951 show_fragment_seq_tree(fd_head,
954 pinfo, reassembled_tvb);
955 pinfo->fragmented = fragment;
956 next_tvb = reassembled_tvb;
959 if (fragment && reassembled_tvb == NULL) {
960 proto_tree_add_text(cotp_tree, tvb, offset, -1,
961 "User data (%u byte%s)", fragment_length,
962 plurality(fragment_length, "", "s"));
967 if (uses_inactive_subset) {
968 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
970 *subdissector_found = TRUE;
972 /* Fill in other Dissectors using inactive subset here */
973 call_dissector(data_handle,next_tvb, pinfo, tree);
977 * We dissect payload if one of the following is TRUE:
979 * - Reassembly option for COTP in preferences is unchecked
980 * - Reassembly option is checked and this packet is the last fragment
982 if ( (!cotp_reassemble) ||
983 ((cotp_reassemble) && (!fragment))) {
984 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
986 *subdissector_found = TRUE;
988 call_dissector(data_handle,next_tvb, pinfo, tree);
993 offset += tvb_length_remaining(tvb, offset);
994 /* we dissected all of the containing PDU */
998 } /* ositp_decode_DT */
1000 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1001 packet_info *pinfo, proto_tree *tree)
1003 proto_tree *cotp_tree = NULL;
1005 gboolean is_extended;
1010 /* ED TPDUs are never fragmented */
1012 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1013 (This means we may misdissect this if the packet is bad and
1014 contains other parameters.) */
1017 case LI_NORMAL_DT_WITH_CHECKSUM :
1018 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
1022 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
1023 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1024 if ( tpdu_nr & 0x80 )
1025 tpdu_nr = tpdu_nr & 0x7F;
1028 is_extended = FALSE;
1031 case LI_EXTENDED_DT_WITH_CHECKSUM :
1032 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
1036 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
1037 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1038 if ( tpdu_nr & 0x80000000 )
1039 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
1045 default : /* bad TPDU */
1051 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1053 pinfo->destport = dst_ref;
1055 if (check_col(pinfo->cinfo, COL_INFO))
1056 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
1060 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1061 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1062 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1063 "Length indicator: %u", li);
1068 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1069 "TPDU code: 0x%x (ED)", tpdu);
1075 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1081 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1082 "TPDU number: 0x%02x", tpdu_nr);
1088 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1089 "TPDU number: 0x%02x", tpdu_nr);
1096 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1099 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1100 call_dissector(data_handle,next_tvb, pinfo, tree);
1102 offset += tvb_length_remaining(tvb, offset);
1103 /* we dissected all of the containing PDU */
1107 } /* ositp_decode_ED */
1109 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1110 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1112 proto_tree *cotp_tree;
1120 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1122 case LI_EXTENDED_RJ :
1123 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1124 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1132 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1134 pinfo->destport = dst_ref;
1136 if (check_col(pinfo->cinfo, COL_INFO))
1137 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1141 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1142 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1143 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1144 "Length indicator: %u", li);
1145 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu,
1146 "TPDU code: 0x%x (RJ)", tpdu);
1147 if (li == LI_NORMAL_RJ)
1148 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1150 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1151 if (li == LI_NORMAL_RJ)
1152 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1153 "Your TPDU number: 0x%02x", tpdu_nr);
1155 proto_tree_add_text(cotp_tree, tvb, offset + 4, 4,
1156 "Your TPDU number: 0x%02x", tpdu_nr);
1157 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1158 "Credit: 0x%02x", credit);
1166 } /* ositp_decode_RJ */
1168 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1169 packet_info *pinfo, proto_tree *tree,
1170 gboolean uses_inactive_subset,
1171 gboolean *subdissector_found)
1174 /* CC & CR decoding in the same function */
1176 proto_tree *cotp_tree = NULL;
1178 guint16 dst_ref, src_ref;
1179 guchar class_option;
1182 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1184 class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1185 if (class_option > 4)
1188 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1189 pinfo->srcport = src_ref;
1190 pinfo->destport = dst_ref;
1191 if (check_col(pinfo->cinfo, COL_INFO))
1192 col_append_fstr(pinfo->cinfo, COL_INFO,
1193 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1194 (tpdu == CR_TPDU) ? "CR" : "CC",
1199 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1200 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1201 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1202 "Length indicator: %u", li);
1207 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1208 "TPDU code: 0x%x (%s)", tpdu,
1209 (tpdu == CR_TPDU) ? "CR" : "CC");
1215 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1220 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1225 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1226 "Class option: 0x%02x", class_option);
1232 ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1235 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1236 if (!uses_inactive_subset){
1237 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
1239 *subdissector_found = TRUE;
1241 call_dissector(data_handle,next_tvb, pinfo, tree);
1245 call_dissector(data_handle, next_tvb, pinfo, tree);
1246 offset += tvb_length_remaining(tvb, offset);
1247 /* we dissected all of the containing PDU */
1251 } /* ositp_decode_CC */
1253 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1254 packet_info *pinfo, proto_tree *tree)
1256 proto_tree *cotp_tree = NULL;
1258 guint16 dst_ref, src_ref;
1263 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1264 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1266 pinfo->srcport = src_ref;
1267 pinfo->destport = dst_ref;
1268 if (check_col(pinfo->cinfo, COL_INFO))
1269 col_append_fstr(pinfo->cinfo, COL_INFO,
1270 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1275 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1276 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1277 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1278 "Length indicator: %u", li);
1283 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1284 "TPDU code: 0x%x (DC)", tpdu);
1290 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1295 proto_tree_add_uint(cotp_tree, hf_cotp_srcref, tvb, offset, 2, src_ref);
1300 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1305 } /* ositp_decode_DC */
1307 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1308 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1310 proto_tree *cotp_tree = NULL;
1319 if (is_LI_NORMAL_AK(li)) {
1321 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1322 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1325 pinfo->destport = dst_ref;
1326 if (check_col(pinfo->cinfo, COL_INFO))
1327 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1331 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1332 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1333 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1334 "Length indicator: %u", li);
1339 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1340 "TPDU code: 0x%x (AK)", tpdu);
1341 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1348 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1353 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1354 "Your TPDU number: 0x%02x", tpdu_nr);
1360 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1363 } else { /* extended format */
1365 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1366 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1367 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1369 if (check_col(pinfo->cinfo, COL_INFO))
1370 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1374 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1375 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1376 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1377 "Length indicator: %u", li);
1382 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1383 "TPDU code: 0x%x (AK)", tpdu);
1389 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1394 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1395 "Your TPDU number: 0x%08x", tpdu_nr);
1401 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1402 "Credit: 0x%04x", cdt_in_ak);
1408 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1411 } /* is_LI_NORMAL_AK */
1415 } /* ositp_decode_AK */
1417 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1418 packet_info *pinfo, proto_tree *tree)
1420 proto_tree *cotp_tree = NULL;
1422 gboolean is_extended;
1429 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1430 (This means we may misdissect this if the packet is bad and
1431 contains other parameters.) */
1434 case LI_NORMAL_EA_WITH_CHECKSUM :
1435 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1436 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1440 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1441 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1442 is_extended = FALSE;
1445 case LI_EXTENDED_EA_WITH_CHECKSUM :
1446 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1447 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1451 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1452 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1456 default : /* bad TPDU */
1462 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1464 pinfo->destport = dst_ref;
1465 if (check_col(pinfo->cinfo, COL_INFO))
1466 col_append_fstr(pinfo->cinfo, COL_INFO,
1467 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1470 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1471 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1472 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1473 "Length indicator: %u", li);
1478 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu,
1479 "TPDU code: 0x%x (EA)", tpdu);
1485 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset, 2, dst_ref);
1491 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1492 "Your TPDU number: 0x%08x", tpdu_nr);
1498 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1499 "Your TPDU number: 0x%02x", tpdu_nr);
1506 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1511 } /* ositp_decode_EA */
1513 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1514 packet_info *pinfo, proto_tree *tree)
1516 proto_tree *cotp_tree;
1524 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1526 str = "Reason not specified";
1529 str = "Invalid parameter code";
1532 str = "Invalid TPDU type";
1535 str = "Invalid parameter value";
1543 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1545 pinfo->destport = dst_ref;
1546 if (check_col(pinfo->cinfo, COL_INFO))
1547 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1550 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1551 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1552 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1553 "Length indicator: %u", li);
1554 proto_tree_add_uint_format(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu,
1555 "TPDU code: 0x%x (ER)", tpdu);
1556 proto_tree_add_uint(cotp_tree, hf_cotp_destref, tvb, offset + 2, 2, dst_ref);
1557 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1558 "Reject cause: %s", str);
1565 } /* ositp_decode_ER */
1567 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1568 packet_info *pinfo, proto_tree *tree)
1571 proto_tree *cltp_tree = NULL;
1574 if (check_col(pinfo->cinfo, COL_INFO))
1575 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1578 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1579 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1580 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1581 "Length indicator: %u", li);
1586 proto_tree_add_uint_format(cltp_tree, hf_cltp_type, tvb, offset, 1, tpdu,
1587 "TPDU code: 0x%x (UD)", tpdu);
1593 ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1596 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1597 call_dissector(data_handle,next_tvb, pinfo, tree);
1598 offset += tvb_length_remaining(tvb, offset);
1599 /* we dissected all of the containing PDU */
1603 } /* ositp_decode_UD */
1605 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1608 There doesn't seem to be any way in which the OSI network layer protocol
1609 distinguishes between COTP and CLTP, but the first two octets of both
1610 protocols' headers mean the same thing - length and PDU type - and the
1611 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1612 both of them here. */
1613 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1614 proto_tree *tree, gboolean uses_inactive_subset)
1617 guint8 li, tpdu, cdt;
1618 gboolean first_tpdu = TRUE;
1620 gboolean found_ositp = FALSE;
1621 gboolean is_cltp = FALSE;
1622 gboolean subdissector_found = FALSE;
1624 if (!proto_is_protocol_enabled(proto_cotp))
1625 return FALSE; /* COTP has been disabled */
1626 /* XXX - what about CLTP? */
1628 pinfo->current_proto = "COTP";
1630 /* Initialize the COL_INFO field; each of the TPDUs will have its
1631 information appended. */
1632 if (check_col(pinfo->cinfo, COL_INFO))
1633 col_add_str(pinfo->cinfo, COL_INFO, "");
1635 while (tvb_offset_exists(tvb, offset)) {
1637 if (check_col(pinfo->cinfo, COL_INFO))
1638 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1640 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1641 if (check_col(pinfo->cinfo, COL_INFO))
1642 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1644 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1649 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1650 if (tpdu == UD_TPDU)
1651 pinfo->current_proto = "CLTP"; /* connectionless transport */
1652 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1657 new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree,
1658 uses_inactive_subset, &subdissector_found);
1661 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1664 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1665 uses_inactive_subset, &subdissector_found);
1668 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1671 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1674 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1677 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1680 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1683 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1686 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1690 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1691 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1692 new_offset = -1; /* bad PDU type */
1696 if (new_offset == -1) { /* incorrect TPDU */
1698 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1704 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1705 is either COTP or CLTP. */
1706 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1707 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1711 offset = new_offset;
1715 } /* dissect_ositp_internal */
1717 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1719 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1720 call_dissector(data_handle,tvb, pinfo, tree);
1724 * CLNP part / main entry point
1727 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1729 proto_tree *clnp_tree = NULL;
1731 guint8 cnf_proto_id;
1736 char flag_string[6+1];
1737 char *pdu_type_string;
1738 proto_tree *type_tree;
1739 guint16 segment_length;
1741 guint16 segment_offset = 0;
1743 cksum_status_t cksum_status;
1745 guchar src_len, dst_len, nsel, opt_len = 0;
1746 const guint8 *dst_addr, *src_addr;
1749 proto_tree *discpdu_tree;
1750 gboolean save_in_error_pkt;
1751 fragment_data *fd_head;
1753 gboolean update_col_info = TRUE;
1754 gboolean save_fragmented;
1756 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1757 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1758 if (check_col(pinfo->cinfo, COL_INFO))
1759 col_clear(pinfo->cinfo, COL_INFO);
1761 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1762 if (cnf_proto_id == NLPID_NULL) {
1763 if (check_col(pinfo->cinfo, COL_INFO))
1764 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1766 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1767 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1768 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1772 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1773 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1777 /* return if version not known */
1778 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1779 if (cnf_vers != ISO8473_V1) {
1780 call_dissector(data_handle,tvb, pinfo, tree);
1784 /* fixed part decoding */
1785 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1786 opt_len = cnf_hdr_len;
1789 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1790 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1791 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1793 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1795 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1797 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1798 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1800 "Holding Time : %u (%u.%u secs)",
1801 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1804 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1805 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1806 "Unknown (0x%02x)");
1807 flag_string[0] = '\0';
1808 if (cnf_type & CNF_SEG_OK)
1809 strcat(flag_string, "S ");
1810 if (cnf_type & CNF_MORE_SEGS)
1811 strcat(flag_string, "M ");
1812 if (cnf_type & CNF_ERR_OK)
1813 strcat(flag_string, "E ");
1815 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1817 "PDU Type : 0x%02x (%s%s)",
1821 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1822 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1823 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1824 "Segmentation permitted",
1825 "Segmentation not permitted"));
1826 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1827 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1830 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1831 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1832 "Report error if PDU discarded",
1833 "Don't report error if PDU discarded"));
1834 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1835 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1836 npdu_type_vals, "%s"));
1839 /* If we don't have the full header - i.e., not enough to see the
1840 segmentation part and determine whether this datagram is segmented
1841 or not - set the Info column now; we'll get an exception before
1842 we set it otherwise. */
1844 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1845 if (check_col(pinfo->cinfo, COL_INFO))
1846 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1849 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1850 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1851 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1853 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1855 switch (cksum_status) {
1859 * No checksum present, or not enough of the header present to
1862 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1865 "Checksum : 0x%04x",
1871 * Checksum is correct.
1873 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1876 "Checksum : 0x%04x (correct)",
1882 * Checksum is not correct.
1884 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1887 "Checksum : 0x%04x (incorrect)",
1891 opt_len -= 9; /* Fixed part of Hesder */
1896 offset = P_CLNP_ADDRESS_PART;
1897 dst_len = tvb_get_guint8(tvb, offset);
1898 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1899 nsel = tvb_get_guint8(tvb, offset + dst_len);
1900 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1901 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1904 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1906 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1909 print_nsap_net(dst_addr, dst_len));
1910 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1911 offset + 1 + dst_len, 1, src_len);
1912 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1913 offset + dst_len + 2, src_len,
1916 print_nsap_net(src_addr, src_len));
1918 opt_len -= dst_len + src_len +2;
1921 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1922 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1923 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1924 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1926 /* Segmentation Part */
1928 offset += dst_len + src_len + 2;
1930 if (cnf_type & CNF_SEG_OK) {
1931 struct clnp_segment seg; /* XXX - not used */
1932 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1934 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1935 du_id = tvb_get_ntohs(tvb, offset);
1937 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1938 "Data unit identifier: %06u",
1940 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1941 "Segment offset : %6u",
1943 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1944 "Total length : %6u",
1945 tvb_get_ntohs(tvb, offset + 4));
1953 /* To do : decode options */
1955 proto_tree_add_text(clnp_tree, tvb, offset,
1956 cnf_hdr_len - offset,
1957 "Options/Data: <not shown>");
1959 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1961 dissect_osi_options( opt_len,
1962 tvb, offset, clnp_tree );
1965 /* Length of CLNP datagram plus headers above it. */
1966 len = segment_length;
1968 offset = cnf_hdr_len;
1970 /* If clnp_reassemble is on, this is a segment, we have all the
1971 * data in the segment, and the checksum is valid, then just add the
1972 * segment to the hashtable.
1974 save_fragmented = pinfo->fragmented;
1975 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1976 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1977 tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
1978 cksum_status != CKSUM_NOT_OK) {
1979 fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table,
1980 clnp_reassembled_table, segment_offset,
1981 segment_length - cnf_hdr_len,
1982 cnf_type & CNF_MORE_SEGS);
1984 next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
1985 fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
1987 /* If this is the first segment, dissect its contents, otherwise
1988 just show it as a segment.
1990 XXX - if we eventually don't save the reassembled contents of all
1991 segmented datagrams, we may want to always reassemble. */
1992 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1993 /* Not the first segment - don't dissect it. */
1996 /* First segment, or not segmented. Dissect what we have here. */
1998 /* Get a tvbuff for the payload. */
1999 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
2002 * If this is the first segment, but not the only segment,
2003 * tell the next protocol that.
2005 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
2006 pinfo->fragmented = TRUE;
2008 pinfo->fragmented = FALSE;
2012 if (next_tvb == NULL) {
2013 /* Just show this as a segment. */
2014 if (check_col(pinfo->cinfo, COL_INFO))
2015 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
2016 pdu_type_string, flag_string, segment_offset);
2018 /* As we haven't reassembled anything, we haven't changed "pi", so
2019 we don't have to restore it. */
2020 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
2022 pinfo->fragmented = save_fragmented;
2026 if (tvb_offset_exists(tvb, offset)) {
2027 switch (cnf_type & CNF_TYPE) {
2031 /* Continue with COTP if any data.
2032 XXX - if this isn't the first Derived PDU of a segmented Initial
2035 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
2036 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
2037 pinfo->fragmented = save_fragmented;
2038 return; /* yes, it appears to be COTP or CLTP */
2041 if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
2043 pinfo->fragmented = save_fragmented;
2044 return; /* yes, it appears to be COTP or CLTP */
2050 /* The payload is the header and "none, some, or all of the data
2051 part of the discarded PDU", i.e. it's like an ICMP error;
2052 dissect it as a CLNP PDU. */
2053 if (check_col(pinfo->cinfo, COL_INFO))
2054 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2056 next_length = tvb_length_remaining(tvb, offset);
2057 if (next_length != 0) {
2058 /* We have payload; dissect it. */
2059 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2061 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2063 /* Save the current value of the "we're inside an error packet"
2064 flag, and set that flag; subdissectors may treat packets
2065 that are the payload of error packets differently from
2067 save_in_error_pkt = pinfo->in_error_pkt;
2068 pinfo->in_error_pkt = TRUE;
2070 call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
2072 /* Restore the "we're inside an error packet" flag. */
2073 pinfo->in_error_pkt = save_in_error_pkt;
2076 pinfo->fragmented = save_fragmented;
2077 return; /* we're done with this PDU */
2081 /* XXX - dissect this */
2085 if (check_col(pinfo->cinfo, COL_INFO))
2086 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2087 call_dissector(data_handle,next_tvb, pinfo, tree);
2088 pinfo->fragmented = save_fragmented;
2089 } /* dissect_clnp */
2092 clnp_reassemble_init(void)
2094 fragment_table_init(&clnp_segment_table);
2095 reassembled_table_init(&clnp_reassembled_table);
2099 cotp_reassemble_init(void)
2101 fragment_table_init(&cotp_segment_table);
2102 reassembled_table_init(&cotp_reassembled_table);
2105 void proto_register_clnp(void)
2107 static hf_register_info hf[] = {
2109 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2110 VALS(nlpid_vals), 0x0, "", HFILL }},
2113 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2116 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2119 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2122 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2124 { &hf_clnp_pdu_length,
2125 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2127 { &hf_clnp_checksum,
2128 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2130 { &hf_clnp_dest_length,
2131 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2134 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2136 { &hf_clnp_src_length,
2137 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2140 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2142 { &hf_clnp_segment_overlap,
2143 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2144 "Segment overlaps with other segments", HFILL }},
2146 { &hf_clnp_segment_overlap_conflict,
2147 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2148 "Overlapping segments contained conflicting data", HFILL }},
2150 { &hf_clnp_segment_multiple_tails,
2151 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2152 "Several tails were found when reassembling the packet", HFILL }},
2154 { &hf_clnp_segment_too_long_segment,
2155 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2156 "Segment contained data past end of packet", HFILL }},
2158 { &hf_clnp_segment_error,
2159 { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2160 "Reassembly error due to illegal segments", HFILL }},
2163 { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2164 "CLNP Segment", HFILL }},
2166 { &hf_clnp_segments,
2167 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2168 "CLNP Segments", HFILL }},
2170 { &hf_clnp_reassembled_in,
2171 { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2172 "This CLNP packet is reassembled in this frame", HFILL }}
2174 static gint *ett[] = {
2182 module_t *clnp_module;
2184 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2185 proto_register_field_array(proto_clnp, hf, array_length(hf));
2186 proto_register_subtree_array(ett, array_length(ett));
2187 register_dissector("clnp", dissect_clnp, proto_clnp);
2188 register_heur_dissector_list("clnp", &clnp_heur_subdissector_list);
2189 register_init_routine(clnp_reassemble_init);
2190 register_init_routine(cotp_reassemble_init);
2192 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2193 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2194 "NSAP selector for Transport Protocol (last byte in hexa)",
2195 "NSAP selector for Transport Protocol (last byte in hexa)",
2196 16, &tp_nsap_selector);
2197 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2198 "Always try to decode NSDU as transport PDUs",
2199 "Always try to decode NSDU as transport PDUs",
2200 &always_decode_transport);
2201 prefs_register_bool_preference(clnp_module, "reassemble",
2202 "Reassemble segmented CLNP datagrams",
2203 "Whether segmented CLNP datagrams should be reassembled",
2208 proto_reg_handoff_clnp(void)
2210 data_handle = find_dissector("data");
2212 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2213 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2214 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2215 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
2218 void proto_register_cotp(void)
2220 static hf_register_info hf[] = {
2222 { "Source reference", "cotp.srcref", FT_UINT16, BASE_HEX, NULL, 0x0,
2223 "Source address reference", HFILL}},
2225 { "Destination reference", "cotp.destref", FT_UINT16, BASE_HEX, NULL, 0x0,
2226 "Destination address reference", HFILL}},
2228 { "COTP PDU Type", "cotp.type", FT_UINT8, BASE_HEX, VALS(cotp_tpdu_type_abbrev_vals), 0x0,
2229 "COTP PDU Type", HFILL}},
2230 { &hf_cotp_segment_overlap,
2231 { "Segment overlap", "cotp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2232 "Segment overlaps with other segments", HFILL }},
2233 { &hf_cotp_segment_overlap_conflict,
2234 { "Conflicting data in segment overlap", "cotp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2235 "Overlapping segments contained conflicting data", HFILL }},
2236 { &hf_cotp_segment_multiple_tails,
2237 { "Multiple tail segments found", "cotp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2238 "Several tails were found when reassembling the packet", HFILL }},
2239 { &hf_cotp_segment_too_long_segment,
2240 { "Segment too long", "cotp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2241 "Segment contained data past end of packet", HFILL }},
2242 { &hf_cotp_segment_error,
2243 { "Reassembly error", "cotp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2244 "Reassembly error due to illegal segments", HFILL }},
2246 { "COTP Segment", "cotp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2247 "COTP Segment", HFILL }},
2248 { &hf_cotp_segments,
2249 { "COTP Segments", "cotp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2250 "COTP Segments", HFILL }},
2251 { &hf_cotp_reassembled_in,
2252 { "Reassembled COTP in frame", "cotp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2253 "This COTP packet is reassembled in this frame", HFILL }},
2256 static gint *ett[] = {
2262 module_t *cotp_module;
2264 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2265 proto_register_field_array(proto_cotp, hf, array_length(hf));
2266 proto_register_subtree_array(ett, array_length(ett));
2267 cotp_module = prefs_register_protocol(proto_cotp, NULL);
2269 prefs_register_bool_preference(cotp_module, "reassemble",
2270 "Reassemble segmented COTP datagrams",
2271 "Whether segmented COTP datagrams should be reassembled",
2274 /* subdissector code in inactive subset */
2275 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2277 /* other COTP/ISO 8473 subdissectors */
2278 register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2280 /* XXX - what about CLTP and proto_cltp? */
2281 register_dissector("ositp", dissect_ositp, proto_cotp);
2284 void proto_register_cltp(void)
2286 static hf_register_info hf[] = {
2288 { "CLTP PDU Type", "cltp.type", FT_UINT8, BASE_HEX, VALS(cltp_tpdu_type_abbrev_vals), 0x0,
2289 "CLTP PDU Type", HFILL}},
2291 static gint *ett[] = {
2295 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2296 proto_register_field_array(proto_cltp, hf, array_length(hf));
2297 proto_register_subtree_array(ett, array_length(ett));