2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.66 2003/02/04 21:43:56 deniel Exp $
5 * Laurent Deniel <laurent.deniel@free.fr>
6 * Ralf Schneider <Ralf.Schneider@t-online.de>
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.
36 #include <epan/packet.h>
37 #include "reassemble.h"
38 #include "packet-osi.h"
39 #include "packet-osi-options.h"
40 #include "packet-isis.h"
41 #include "packet-esis.h"
44 /* protocols and fields */
46 static int proto_clnp = -1;
47 static gint ett_clnp = -1;
48 static gint ett_clnp_type = -1;
49 static gint ett_clnp_segments = -1;
50 static gint ett_clnp_segment = -1;
51 static gint ett_clnp_disc_pdu = -1;
52 static int proto_cotp = -1;
53 static gint ett_cotp = -1;
54 static int proto_cltp = -1;
55 static gint ett_cltp = -1;
57 static int hf_clnp_id = -1;
58 static int hf_clnp_length = -1;
59 static int hf_clnp_version = -1;
60 static int hf_clnp_ttl = -1;
61 static int hf_clnp_type = -1;
62 static int hf_clnp_pdu_length = -1;
63 static int hf_clnp_checksum = -1;
64 static int hf_clnp_dest_length = -1;
65 static int hf_clnp_dest = -1;
66 static int hf_clnp_src_length = -1;
67 static int hf_clnp_src = -1;
68 static int hf_clnp_segments = -1;
69 static int hf_clnp_segment = -1;
70 static int hf_clnp_segment_overlap = -1;
71 static int hf_clnp_segment_overlap_conflict = -1;
72 static int hf_clnp_segment_multiple_tails = -1;
73 static int hf_clnp_segment_too_long_segment = -1;
74 static int hf_clnp_segment_error = -1;
76 static const fragment_items clnp_frag_items = {
81 &hf_clnp_segment_overlap,
82 &hf_clnp_segment_overlap_conflict,
83 &hf_clnp_segment_multiple_tails,
84 &hf_clnp_segment_too_long_segment,
85 &hf_clnp_segment_error,
89 static dissector_handle_t clnp_handle;
90 static dissector_handle_t data_handle;
93 * ISO 8473 OSI CLNP definition (see RFC994)
95 * _________________________________
97 * |_________________________________|
99 * |_________________________________|
100 * | Segmentation Part (optional) |
101 * |_________________________________|
102 * | Options Part (optional) |
103 * |_________________________________|
104 * | Data (optional) |
105 * |_________________________________|
108 #define ISO8473_V1 0x01 /* CLNP version 1 */
112 #define CNF_TYPE 0x1f
113 #define CNF_ERR_OK 0x20
114 #define CNF_MORE_SEGS 0x40
115 #define CNF_SEG_OK 0x80
120 #define ERQ_NPDU 0x1E
121 #define ERP_NPDU 0x1F
123 static const value_string npdu_type_abbrev_vals[] = {
132 static const value_string npdu_type_vals[] = {
134 { MD_NPDU, "Multicast Data" },
135 { ER_NPDU, "Error Report" },
136 { ERQ_NPDU, "Echo Request" },
137 { ERP_NPDU, "Echo Response" },
143 #define P_CLNP_PROTO_ID 0
144 #define P_CLNP_HDR_LEN 1
145 #define P_CLNP_VERS 2
147 #define P_CLNP_TYPE 4
148 #define P_CLNP_SEGLEN 5
149 #define P_CLNP_CKSUM 7
150 #define P_CLNP_ADDRESS_PART 9
152 /* Segmentation part */
154 struct clnp_segment {
155 gushort cng_id; /* data unit identifier */
156 gushort cng_off; /* segment offset */
157 gushort cng_tot_len; /* total length */
162 #define NSEL_NET 0x00
167 * ISO8073 OSI COTP definition (see RFC905)
170 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
172 /* TPDU definition */
174 #define ED_TPDU 0x1 /* COTP */
175 #define EA_TPDU 0x2 /* COTP */
176 #define UD_TPDU 0x4 /* CLTP */
177 #define RJ_TPDU 0x5 /* COTP */
178 #define AK_TPDU 0x6 /* COTP */
179 #define ER_TPDU 0x7 /* COTP */
180 #define DR_TPDU 0x8 /* COTP */
181 #define DC_TPDU 0xC /* COTP */
182 #define CC_TPDU 0xD /* COTP */
183 #define CR_TPDU 0xE /* COTP */
184 #define DT_TPDU 0xF /* COTP */
193 #define P_TPDU_NR_0_1 2
194 #define P_TPDU_NR_234 4
195 #define P_VAR_PART_NDT 5
196 #define P_VAR_PART_EDT 8
197 #define P_VAR_PART_DC 6
198 #define P_CDT_IN_AK 8
199 #define P_CDT_IN_RJ 8
200 #define P_REJECT_ER 4
201 #define P_REASON_IN_DR 6
202 #define P_CLASS_OPTION 6
204 /* TPDU length indicator */
206 #define LI_NORMAL_DT_CLASS_01 2
207 #define LI_NORMAL_DT_WITH_CHECKSUM 8
208 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
209 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
210 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
211 #define LI_NORMAL_EA_WITH_CHECKSUM 8
212 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
213 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
214 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
215 #define LI_NORMAL_RJ 4
216 #define LI_EXTENDED_RJ 9
222 /* XXX - can we always decide this based on whether the length
223 indicator is odd or not? What if the variable part has an odd
225 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
229 #define VP_ACK_TIME 0x85
230 #define VP_RES_ERROR 0x86
231 #define VP_PRIORITY 0x87
232 #define VP_TRANSIT_DEL 0x88
233 #define VP_THROUGHPUT 0x89
234 #define VP_SEQ_NR 0x8A /* in AK */
235 #define VP_REASSIGNMENT 0x8B
236 #define VP_FLOW_CNTL 0x8C /* in AK */
237 #define VP_TPDU_SIZE 0xC0
238 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
239 #define VP_DST_TSAP 0xC2
240 #define VP_CHECKSUM 0xC3
241 #define VP_VERSION_NR 0xC4
242 #define VP_PROTECTION 0xC5
243 #define VP_OPT_SEL 0xC6
244 #define VP_PROTO_CLASS 0xC7
245 #define VP_PREF_MAX_TPDU_SIZE 0xF0
246 #define VP_INACTIVITY_TIMER 0xF2
248 static const value_string tp_vpart_type_vals[] = {
249 { VP_ACK_TIME, "ack time" },
250 { VP_RES_ERROR, "res error" },
251 { VP_PRIORITY, "priority" },
252 { VP_TRANSIT_DEL, "transit delay" },
253 { VP_THROUGHPUT, "throughput" },
254 { VP_SEQ_NR, "seq number" },
255 { VP_REASSIGNMENT, "reassignment" },
256 { VP_FLOW_CNTL, "flow control" },
257 { VP_TPDU_SIZE, "tpdu-size" },
258 { VP_SRC_TSAP, "src-tsap" },
259 { VP_DST_TSAP, "dst-tsap" },
260 { VP_CHECKSUM, "checksum" },
261 { VP_VERSION_NR, "version" },
262 { VP_PROTECTION, "protection" },
263 { VP_OPT_SEL, "options" },
264 { VP_PROTO_CLASS, "proto class" },
265 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
271 #define EXTRACT_SHORT(p) pntohs(p)
272 #define EXTRACT_LONG(p) pntohl(p)
274 /* global variables */
276 /* List of dissectors to call for COTP packets put atop the Inactive
278 static heur_dissector_list_t cotp_is_heur_subdissector_list;
279 /* List of dissectors to call for COTP packets put atop CLNP */
280 static heur_dissector_list_t cotp_heur_subdissector_list;
283 * Reassembly of CLNP.
285 static GHashTable *clnp_segment_table = NULL;
288 static guint tp_nsap_selector = NSEL_TP;
289 static gboolean always_decode_transport = FALSE;
290 static gboolean clnp_reassemble = FALSE;
292 /* function definitions */
294 #define MAX_TSAP_LEN 32
295 static gchar *print_tsap(const guchar *tsap, int length)
298 static gchar str[3][MAX_TSAP_LEN * 2 + 1];
301 gboolean allprintable;
304 if (cur == &str[0][0]) {
306 } else if (cur == &str[1][0]) {
314 if (length <= 0 || length > MAX_TSAP_LEN)
315 sprintf(cur, "<unsupported TSAP length>");
318 for (i=0;i<length;i++) {
319 /* If any byte is not printable ASCII, display the TSAP as a
320 series of hex byte values rather than as a string; this
321 means that, for example, accented letters will cause it
322 to be displayed as hex, but it also means that byte values
323 such as 0xff and 0xfe, which *are* printable ISO 8859/x
324 characters, won't be treated as printable - 0xfffffffe
325 is probably binary, not text. */
326 if (!(isascii(tsap[i]) && isprint(tsap[i]))) {
334 while (length != 0) {
336 sprintf(tmp, "%c", *tsap ++);
338 sprintf(tmp, "%02x", *tsap ++);
347 static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset,
348 int vp_length, int class_option,
353 guint16 s, s1,s2,s3,s4;
354 guint32 t1, t2, t3, t4;
355 guint32 pref_max_tpdu_size;
357 while (vp_length != 0) {
358 code = tvb_get_guint8(tvb, offset);
359 proto_tree_add_text(tree, tvb, offset, 1,
360 "Parameter code: 0x%02x (%s)",
362 val_to_str(code, tp_vpart_type_vals, "Unknown"));
368 length = tvb_get_guint8(tvb, offset);
369 proto_tree_add_text(tree, tvb, offset, 1,
370 "Parameter length: %u", length);
377 s = tvb_get_ntohs(tvb, offset);
378 proto_tree_add_text(tree, tvb, offset, length,
379 "Ack time (ms): %u", s);
385 proto_tree_add_text(tree, tvb, offset, 1,
386 "Residual error rate, target value: 10^%u",
387 tvb_get_guint8(tvb, offset));
392 proto_tree_add_text(tree, tvb, offset, 1,
393 "Residual error rate, minimum acceptable: 10^%u",
394 tvb_get_guint8(tvb, offset));
400 proto_tree_add_text(tree, tvb, offset, 1,
401 "Residual error rate, TSDU size of interest: %u",
402 1<<tvb_get_guint8(tvb, offset));
410 s = tvb_get_ntohs(tvb, offset);
411 proto_tree_add_text(tree, tvb, offset, length,
418 s1 = tvb_get_ntohs(tvb, offset);
419 proto_tree_add_text(tree, tvb, offset, 2,
420 "Transit delay, target value, calling-called: %u ms", s1);
425 s2 = tvb_get_ntohs(tvb, offset);
426 proto_tree_add_text(tree, tvb, offset, 2,
427 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
432 s3 = tvb_get_ntohs(tvb, offset);
433 proto_tree_add_text(tree, tvb, offset, 2,
434 "Transit delay, target value, called-calling: %u ms", s3);
439 s4 = tvb_get_ntohs(tvb, offset);
440 proto_tree_add_text(tree, tvb, offset, 2,
441 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
448 t1 = tvb_get_ntoh24(tvb, offset);
449 proto_tree_add_text(tree, tvb, offset, 3,
450 "Maximum throughput, target value, calling-called: %u o/s", t1);
455 t2 = tvb_get_ntoh24(tvb, offset);
456 proto_tree_add_text(tree, tvb, offset, 3,
457 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
462 t3 = tvb_get_ntoh24(tvb, offset);
463 proto_tree_add_text(tree, tvb, offset, 3,
464 "Maximum throughput, target value, called-calling: %u o/s", t3);
469 t4 = tvb_get_ntoh24(tvb, offset);
470 proto_tree_add_text(tree, tvb, offset, 3,
471 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
476 if (length != 0) { /* XXX - should be 0 or 12 */
477 t1 = tvb_get_ntoh24(tvb, offset);
478 proto_tree_add_text(tree, tvb, offset, 3,
479 "Average throughput, target value, calling-called: %u o/s", t1);
484 t2 = tvb_get_ntoh24(tvb, offset);
485 proto_tree_add_text(tree, tvb, offset, 3,
486 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
491 t3 = tvb_get_ntoh24(tvb, offset);
492 proto_tree_add_text(tree, tvb, offset, 3,
493 "Average throughput, target value, called-calling: %u o/s", t3);
498 t4 = tvb_get_ntoh24(tvb, offset);
499 proto_tree_add_text(tree, tvb, offset, 3,
500 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
508 proto_tree_add_text(tree, tvb, offset, 2,
509 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
514 case VP_REASSIGNMENT:
515 proto_tree_add_text(tree, tvb, offset, 2,
516 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
522 proto_tree_add_text(tree, tvb, offset, 4,
523 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
528 proto_tree_add_text(tree, tvb, offset, 2,
529 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
534 proto_tree_add_text(tree, tvb, offset, 2,
535 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
543 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
544 proto_tree_add_text(tree, tvb, offset, length,
545 "TPDU size: %u", 1 << c1);
551 proto_tree_add_text(tree, tvb, offset, length,
553 print_tsap(tvb_get_ptr(tvb, offset, length), length));
559 proto_tree_add_text(tree, tvb, offset, length,
561 print_tsap(tvb_get_ptr(tvb, offset, length), length));
567 proto_tree_add_text(tree, tvb, offset, length,
568 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
574 c1 = tvb_get_guint8(tvb, offset);
575 proto_tree_add_text(tree, tvb, offset, length,
582 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
583 switch (class_option) {
587 proto_tree_add_text(tree, tvb, offset, 1,
588 "Use of network expedited data");
590 proto_tree_add_text(tree, tvb, offset, 1,
591 "Non use of network expedited data");
593 proto_tree_add_text(tree, tvb, offset, 1,
594 "Use of Receipt confirmation");
596 proto_tree_add_text(tree, tvb, offset, 1,
597 "Use of explicit AK variant");
602 proto_tree_add_text(tree, tvb, offset, 1,
603 "Non-use 16 bit checksum in class 4");
605 proto_tree_add_text(tree, tvb, offset, 1,
606 "Use 16 bit checksum ");
610 proto_tree_add_text(tree, tvb, offset, 1,
611 "Use of transport expedited data transfer");
613 proto_tree_add_text(tree, tvb, offset, 1,
614 "Non-use of transport expedited data transfer");
619 case VP_PREF_MAX_TPDU_SIZE:
623 pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
627 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
631 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
635 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
639 proto_tree_add_text(tree, tvb, offset, length,
640 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
644 proto_tree_add_text(tree, tvb, offset, length,
645 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
650 case VP_INACTIVITY_TIMER:
651 proto_tree_add_text(tree, tvb, offset, length,
652 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
657 case VP_PROTECTION: /* user-defined */
658 case VP_PROTO_CLASS: /* todo */
659 default: /* unknown, no decoding */
660 proto_tree_add_text(tree, tvb, offset, length,
661 "Parameter value: <not shown>");
671 static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
672 packet_info *pinfo, proto_tree *tree)
674 proto_tree *cotp_tree;
676 guint16 dst_ref, src_ref;
683 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
684 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
685 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
688 case (128+0): str = "Normal Disconnect"; break;
689 case (128+1): str = "Remote transport entity congestion"; break;
690 case (128+2): str = "Connection negotiation failed"; break;
691 case (128+3): str = "Duplicate source reference"; break;
692 case (128+4): str = "Mismatched references"; break;
693 case (128+5): str = "Protocol error"; break;
694 case (128+7): str = "Reference overflow"; break;
695 case (128+8): str = "Connection requestion refused"; break;
696 case (128+10):str = "Header or parameter length invalid"; break;
697 case (0): str = "Reason not specified"; break;
698 case (1): str = "Congestion at TSAP"; break;
699 case (2): str = "Session entity not attached to TSAP"; break;
700 case (3): str = "Address unknown"; break;
706 if (check_col(pinfo->cinfo, COL_INFO))
707 col_append_fstr(pinfo->cinfo, COL_INFO,
708 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
712 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
713 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
714 proto_tree_add_text(cotp_tree, tvb, offset, 1,
715 "Length indicator: %u", li);
716 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
717 "TPDU code: 0x%x (DR)", tpdu);
718 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
719 "Destination reference: 0x%04x", dst_ref);
720 proto_tree_add_text(cotp_tree, tvb, offset + 4, 2,
721 "Source reference: 0x%04x", src_ref);
722 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
729 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
730 offset += tvb_length_remaining(tvb, offset);
731 /* we dissected all of the containing PDU */
735 } /* ositp_decode_DR */
737 static int ositp_decode_DT(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
738 packet_info *pinfo, proto_tree *tree,
739 gboolean uses_inactive_subset,
740 gboolean *subdissector_found)
742 proto_tree *cotp_tree = NULL;
744 gboolean is_extended;
745 gboolean is_class_234;
751 /* VP_CHECKSUM is the only parameter allowed in the variable part.
752 (This means we may misdissect this if the packet is bad and
753 contains other parameters.) */
756 case LI_NORMAL_DT_WITH_CHECKSUM :
757 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
761 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
762 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
763 if ( tpdu_nr & 0x80 )
764 tpdu_nr = tpdu_nr & 0x7F;
769 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
772 case LI_EXTENDED_DT_WITH_CHECKSUM :
773 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
777 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
778 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
779 if ( tpdu_nr & 0x80000000 )
780 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
785 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
788 case LI_NORMAL_DT_CLASS_01 :
789 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
790 if ( tpdu_nr & 0x80 )
791 tpdu_nr = tpdu_nr & 0x7F;
795 is_class_234 = FALSE;
799 default : /* bad TPDU */
805 if (check_col(pinfo->cinfo, COL_INFO)) {
807 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
810 (fragment)? "(fragment)" : "");
812 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) %s",
814 (fragment)? "(fragment)" : "");
819 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
820 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
821 proto_tree_add_text(cotp_tree, tvb, offset, 1,
822 "Length indicator: %u", li);
827 proto_tree_add_text(cotp_tree, tvb, offset, 1,
828 "TPDU code: 0x%x (DT)", tpdu);
836 proto_tree_add_text(cotp_tree, tvb, offset, 2,
837 "Destination reference: 0x%04x", dst_ref);
845 proto_tree_add_text(cotp_tree, tvb, offset, 4,
846 "TPDU number: 0x%08x (%s)",
848 (fragment)? "fragment":"complete");
854 proto_tree_add_text(cotp_tree, tvb, offset, 1,
855 "TPDU number: 0x%02x (%s)",
857 (fragment)? "fragment":"complete");
864 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
867 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
868 if (uses_inactive_subset){
869 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
871 *subdissector_found = TRUE;
873 /* Fill in other Dissectors using inactive subset here */
874 call_dissector(data_handle,next_tvb, pinfo, tree);
877 if (dissector_try_heuristic(cotp_heur_subdissector_list, next_tvb,
879 *subdissector_found = TRUE;
881 call_dissector(data_handle,next_tvb, pinfo, tree);
884 offset += tvb_length_remaining(tvb, offset);
885 /* we dissected all of the containing PDU */
889 } /* ositp_decode_DT */
891 static int ositp_decode_ED(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
892 packet_info *pinfo, proto_tree *tree)
894 proto_tree *cotp_tree = NULL;
896 gboolean is_extended;
901 /* ED TPDUs are never fragmented */
903 /* VP_CHECKSUM is the only parameter allowed in the variable part.
904 (This means we may misdissect this if the packet is bad and
905 contains other parameters.) */
908 case LI_NORMAL_DT_WITH_CHECKSUM :
909 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
913 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
914 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
915 if ( tpdu_nr & 0x80 )
916 tpdu_nr = tpdu_nr & 0x7F;
922 case LI_EXTENDED_DT_WITH_CHECKSUM :
923 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
927 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
928 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
929 if ( tpdu_nr & 0x80000000 )
930 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
936 default : /* bad TPDU */
942 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
943 if (check_col(pinfo->cinfo, COL_INFO))
944 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
948 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
949 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
950 proto_tree_add_text(cotp_tree, tvb, offset, 1,
951 "Length indicator: %u", li);
956 proto_tree_add_text(cotp_tree, tvb, offset, 1,
957 "TPDU code: 0x%x (ED)", tpdu);
963 proto_tree_add_text(cotp_tree, tvb, offset, 2,
964 "Destination reference: 0x%04x", dst_ref);
971 proto_tree_add_text(cotp_tree, tvb, offset, 4,
972 "TPDU number: 0x%02x", tpdu_nr);
978 proto_tree_add_text(cotp_tree, tvb, offset, 1,
979 "TPDU number: 0x%02x", tpdu_nr);
986 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
989 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
990 call_dissector(data_handle,next_tvb, pinfo, tree);
992 offset += tvb_length_remaining(tvb, offset);
993 /* we dissected all of the containing PDU */
997 } /* ositp_decode_ED */
999 static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1000 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1002 proto_tree *cotp_tree;
1010 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1012 case LI_EXTENDED_RJ :
1013 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1014 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1022 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1023 if (check_col(pinfo->cinfo, COL_INFO))
1024 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1028 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1029 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1030 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1031 "Length indicator: %u", li);
1032 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1033 "TPDU code: 0x%x (RJ)", tpdu);
1034 if (li == LI_NORMAL_RJ)
1035 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1037 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1038 "Destination reference: 0x%04x", dst_ref);
1039 if (li == LI_NORMAL_RJ)
1040 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1041 "Your TPDU number: 0x%02x", tpdu_nr);
1043 proto_tree_add_text(cotp_tree, tvb, offset + 4, 4,
1044 "Your TPDU number: 0x%02x", tpdu_nr);
1045 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1046 "Credit: 0x%02x", credit);
1054 } /* ositp_decode_RJ */
1056 static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1057 packet_info *pinfo, proto_tree *tree)
1060 /* CC & CR decoding in the same function */
1062 proto_tree *cotp_tree = NULL;
1064 guint16 dst_ref, src_ref;
1065 guchar class_option;
1067 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1068 class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1069 if (class_option > 4)
1072 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1073 if (check_col(pinfo->cinfo, COL_INFO))
1074 col_append_fstr(pinfo->cinfo, COL_INFO,
1075 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1076 (tpdu == CR_TPDU) ? "CR" : "CC",
1081 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1082 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1083 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1084 "Length indicator: %u", li);
1089 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1090 "TPDU code: 0x%x (%s)", tpdu,
1091 (tpdu == CR_TPDU) ? "CR" : "CC");
1097 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1098 "Destination reference: 0x%04x", dst_ref);
1104 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1105 "Source reference: 0x%04x", src_ref);
1111 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1112 "Class option: 0x%02x", class_option);
1118 ositp_decode_var_part(tvb, offset, li, class_option, cotp_tree);
1122 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
1123 offset += tvb_length_remaining(tvb, offset);
1124 /* we dissected all of the containing PDU */
1128 } /* ositp_decode_CC */
1130 static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1131 packet_info *pinfo, proto_tree *tree)
1133 proto_tree *cotp_tree = NULL;
1135 guint16 dst_ref, src_ref;
1140 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1141 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1143 if (check_col(pinfo->cinfo, COL_INFO))
1144 col_append_fstr(pinfo->cinfo, COL_INFO,
1145 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1150 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1151 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1152 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1153 "Length indicator: %u", li);
1158 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1159 "TPDU code: 0x%x (DC)", tpdu);
1165 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1166 "Destination reference: 0x%04x", dst_ref);
1172 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1173 "Source reference: 0x%04x", src_ref);
1179 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1184 } /* ositp_decode_DC */
1186 static int ositp_decode_AK(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1187 guint8 cdt, packet_info *pinfo, proto_tree *tree)
1189 proto_tree *cotp_tree = NULL;
1198 if (is_LI_NORMAL_AK(li)) {
1200 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1201 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1203 if (check_col(pinfo->cinfo, COL_INFO))
1204 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1208 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1209 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1210 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1211 "Length indicator: %u", li);
1216 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1217 "TPDU code: 0x%x (AK)", tpdu);
1218 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1225 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1226 "Destination reference: 0x%04x", dst_ref);
1232 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1233 "Your TPDU number: 0x%02x", tpdu_nr);
1239 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1242 } else { /* extended format */
1244 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1245 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1246 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1248 if (check_col(pinfo->cinfo, COL_INFO))
1249 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1253 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1254 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1255 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1256 "Length indicator: %u", li);
1261 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1262 "TPDU code: 0x%x (AK)", tpdu);
1268 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1269 "Destination reference: 0x%04x", dst_ref);
1275 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1276 "Your TPDU number: 0x%08x", tpdu_nr);
1282 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1283 "Credit: 0x%04x", cdt_in_ak);
1289 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1292 } /* is_LI_NORMAL_AK */
1296 } /* ositp_decode_AK */
1298 static int ositp_decode_EA(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1299 packet_info *pinfo, proto_tree *tree)
1301 proto_tree *cotp_tree = NULL;
1303 gboolean is_extended;
1310 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1311 (This means we may misdissect this if the packet is bad and
1312 contains other parameters.) */
1315 case LI_NORMAL_EA_WITH_CHECKSUM :
1316 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1317 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1321 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1322 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1323 is_extended = FALSE;
1326 case LI_EXTENDED_EA_WITH_CHECKSUM :
1327 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1328 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1332 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1333 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1337 default : /* bad TPDU */
1343 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1344 if (check_col(pinfo->cinfo, COL_INFO))
1345 col_append_fstr(pinfo->cinfo, COL_INFO,
1346 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1349 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1350 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1351 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1352 "Length indicator: %u", li);
1357 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1358 "TPDU code: 0x%x (EA)", tpdu);
1364 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1365 "Destination reference: 0x%04x", dst_ref);
1372 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1373 "Your TPDU number: 0x%08x", tpdu_nr);
1379 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1380 "Your TPDU number: 0x%02x", tpdu_nr);
1387 ositp_decode_var_part(tvb, offset, li, 4, cotp_tree);
1392 } /* ositp_decode_EA */
1394 static int ositp_decode_ER(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1395 packet_info *pinfo, proto_tree *tree)
1397 proto_tree *cotp_tree;
1405 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1407 str = "Reason not specified";
1410 str = "Invalid parameter code";
1413 str = "Invalid TPDU type";
1416 str = "Invalid parameter value";
1424 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1425 if (check_col(pinfo->cinfo, COL_INFO))
1426 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1429 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1430 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1431 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1432 "Length indicator: %u", li);
1433 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1434 "TPDU code: 0x%x (ER)", tpdu);
1435 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1436 "Destination reference: 0x%04x", dst_ref);
1437 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1438 "Reject cause: %s", str);
1445 } /* ositp_decode_ER */
1447 static int ositp_decode_UD(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu,
1448 packet_info *pinfo, proto_tree *tree)
1451 proto_tree *cltp_tree = NULL;
1454 if (check_col(pinfo->cinfo, COL_INFO))
1455 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1458 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1459 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1460 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1461 "Length indicator: %u", li);
1466 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1467 "TPDU code: 0x%x (UD)", tpdu);
1473 ositp_decode_var_part(tvb, offset, li, 0, cltp_tree);
1476 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1477 call_dissector(data_handle,next_tvb, pinfo, tree);
1478 offset += tvb_length_remaining(tvb, offset);
1479 /* we dissected all of the containing PDU */
1483 } /* ositp_decode_UD */
1485 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1488 There doesn't seem to be any way in which the OSI network layer protocol
1489 distinguishes between COTP and CLTP, but the first two octets of both
1490 protocols' headers mean the same thing - length and PDU type - and the
1491 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1492 both of them here. */
1493 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1494 proto_tree *tree, gboolean uses_inactive_subset)
1497 guint8 li, tpdu, cdt;
1498 gboolean first_tpdu = TRUE;
1500 gboolean found_ositp = FALSE;
1501 gboolean is_cltp = FALSE;
1502 gboolean subdissector_found = FALSE;
1504 if (!proto_is_protocol_enabled(proto_cotp))
1505 return FALSE; /* COTP has been disabled */
1506 /* XXX - what about CLTP? */
1508 pinfo->current_proto = "COTP";
1510 /* Initialize the COL_INFO field; each of the TPDUs will have its
1511 information appended. */
1512 if (check_col(pinfo->cinfo, COL_INFO))
1513 col_add_str(pinfo->cinfo, COL_INFO, "");
1515 while (tvb_offset_exists(tvb, offset)) {
1517 if (check_col(pinfo->cinfo, COL_INFO))
1518 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1520 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1521 if (check_col(pinfo->cinfo, COL_INFO))
1522 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1524 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1529 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1530 if (tpdu == UD_TPDU)
1531 pinfo->current_proto = "CLTP"; /* connectionless transport */
1532 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1537 new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree);
1540 new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree);
1543 new_offset = ositp_decode_DT(tvb, offset, li, tpdu, pinfo, tree,
1544 uses_inactive_subset, &subdissector_found);
1547 new_offset = ositp_decode_ED(tvb, offset, li, tpdu, pinfo, tree);
1550 new_offset = ositp_decode_RJ(tvb, offset, li, tpdu, cdt, pinfo, tree);
1553 new_offset = ositp_decode_DC(tvb, offset, li, tpdu, pinfo, tree);
1556 new_offset = ositp_decode_AK(tvb, offset, li, tpdu, cdt, pinfo, tree);
1559 new_offset = ositp_decode_EA(tvb, offset, li, tpdu, pinfo, tree);
1562 new_offset = ositp_decode_ER(tvb, offset, li, tpdu, pinfo, tree);
1565 new_offset = ositp_decode_UD(tvb, offset, li, tpdu, pinfo, tree);
1569 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1570 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1571 new_offset = -1; /* bad PDU type */
1575 if (new_offset == -1) { /* incorrect TPDU */
1577 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1583 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1584 is either COTP or CLTP. */
1585 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1586 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1590 offset = new_offset;
1594 } /* dissect_ositp_internal */
1596 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1598 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1599 call_dissector(data_handle,tvb, pinfo, tree);
1603 * CLNP part / main entry point
1606 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1608 proto_tree *clnp_tree = NULL;
1610 guint8 cnf_proto_id;
1615 char flag_string[6+1];
1616 char *pdu_type_string;
1617 proto_tree *type_tree;
1618 guint16 segment_length;
1620 guint16 segment_offset = 0;
1622 cksum_status_t cksum_status;
1624 guchar src_len, dst_len, nsel, opt_len = 0;
1625 const guint8 *dst_addr, *src_addr;
1628 proto_tree *discpdu_tree;
1629 gboolean save_in_error_pkt;
1630 fragment_data *fd_head;
1632 gboolean update_col_info = TRUE;
1633 gboolean save_fragmented;
1635 signal(SIGSEGV, SIG_DFL);
1637 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1638 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1639 if (check_col(pinfo->cinfo, COL_INFO))
1640 col_clear(pinfo->cinfo, COL_INFO);
1642 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1643 if (cnf_proto_id == NLPID_NULL) {
1644 if (check_col(pinfo->cinfo, COL_INFO))
1645 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1647 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1648 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1649 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1653 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1654 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1658 /* return if version not known */
1659 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1660 if (cnf_vers != ISO8473_V1) {
1661 call_dissector(data_handle,tvb, pinfo, tree);
1665 /* fixed part decoding */
1666 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1667 opt_len = cnf_hdr_len;
1670 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1671 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1672 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1674 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1676 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1678 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1679 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1681 "Holding Time : %u (%u.%u secs)",
1682 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1685 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1686 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1687 "Unknown (0x%02x)");
1688 flag_string[0] = '\0';
1689 if (cnf_type & CNF_SEG_OK)
1690 strcat(flag_string, "S ");
1691 if (cnf_type & CNF_MORE_SEGS)
1692 strcat(flag_string, "M ");
1693 if (cnf_type & CNF_ERR_OK)
1694 strcat(flag_string, "E ");
1696 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1698 "PDU Type : 0x%02x (%s%s)",
1702 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1703 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1704 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1705 "Segmentation permitted",
1706 "Segmentation not permitted"));
1707 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1708 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1711 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1712 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1713 "Report error if PDU discarded",
1714 "Don't report error if PDU discarded"));
1715 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1716 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1717 npdu_type_vals, "%s"));
1720 /* If we don't have the full header - i.e., not enough to see the
1721 segmentation part and determine whether this datagram is segmented
1722 or not - set the Info column now; we'll get an exception before
1723 we set it otherwise. */
1725 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1726 if (check_col(pinfo->cinfo, COL_INFO))
1727 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1730 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1731 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1732 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1734 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1736 switch (cksum_status) {
1740 * No checksum present, or not enough of the header present to
1743 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1746 "Checksum : 0x%04x",
1752 * Checksum is correct.
1754 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1757 "Checksum : 0x%04x (correct)",
1763 * Checksum is not correct.
1765 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1768 "Checksum : 0x%04x (incorrect)",
1772 opt_len -= 9; /* Fixed part of Hesder */
1777 offset = P_CLNP_ADDRESS_PART;
1778 dst_len = tvb_get_guint8(tvb, offset);
1779 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1780 nsel = tvb_get_guint8(tvb, offset + dst_len);
1781 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1782 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1785 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1787 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1790 print_nsap_net(dst_addr, dst_len));
1791 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1792 offset + 1 + dst_len, 1, src_len);
1793 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1794 offset + dst_len + 2, src_len,
1797 print_nsap_net(src_addr, src_len));
1799 opt_len -= dst_len + src_len +2;
1802 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1803 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1804 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1805 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1807 /* Segmentation Part */
1809 offset += dst_len + src_len + 2;
1811 if (cnf_type & CNF_SEG_OK) {
1812 struct clnp_segment seg; /* XXX - not used */
1813 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1815 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1816 du_id = tvb_get_ntohs(tvb, offset);
1818 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1819 "Data unit identifier: %06u",
1821 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1822 "Segment offset : %6u",
1824 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1825 "Total length : %6u",
1826 tvb_get_ntohs(tvb, offset + 4));
1834 /* To do : decode options */
1836 proto_tree_add_text(clnp_tree, tvb, offset,
1837 cnf_hdr_len - offset,
1838 "Options/Data: <not shown>");
1840 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1842 dissect_osi_options( opt_len,
1843 tvb, offset, clnp_tree );
1846 /* Length of CLNP datagram plus headers above it. */
1847 len = segment_length;
1849 offset = cnf_hdr_len;
1851 /* If clnp_reassemble is on, and this is a segment, we have all the
1852 * data in the segment, and the checksum is valid, then just add the
1853 * segment to the hashtable.
1855 save_fragmented = pinfo->fragmented;
1856 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1857 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1858 (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1859 cksum_status != CKSUM_NOT_OK) {
1860 fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1861 segment_offset, segment_length - cnf_hdr_len,
1862 cnf_type & CNF_MORE_SEGS);
1864 if (fd_head != NULL) {
1865 /* OK, we have the complete reassembled payload.
1866 Allocate a new tvbuff, referring to the reassembled payload. */
1867 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1870 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1871 were handed refers, so it'll get cleaned up when that tvbuff
1873 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1875 /* Add the defragmented data to the data source list. */
1876 add_new_data_source(pinfo, next_tvb, "Reassembled CLNP");
1878 update_col_info = !show_fragment_tree(fd_head, &clnp_frag_items,
1879 clnp_tree, pinfo, next_tvb);
1881 /* We don't have the complete reassembled payload. */
1885 /* If this is the first segment, dissect its contents, otherwise
1886 just show it as a segment.
1888 XXX - if we eventually don't save the reassembled contents of all
1889 segmented datagrams, we may want to always reassemble. */
1890 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1891 /* Not the first segment - don't dissect it. */
1894 /* First segment, or not segmented. Dissect what we have here. */
1896 /* Get a tvbuff for the payload. */
1897 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1900 * If this is the first segment, but not the only segment,
1901 * tell the next protocol that.
1903 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1904 pinfo->fragmented = TRUE;
1906 pinfo->fragmented = FALSE;
1910 if (next_tvb == NULL) {
1911 /* Just show this as a segment. */
1912 if (check_col(pinfo->cinfo, COL_INFO))
1913 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1914 pdu_type_string, flag_string, segment_offset);
1916 /* As we haven't reassembled anything, we haven't changed "pi", so
1917 we don't have to restore it. */
1918 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
1920 pinfo->fragmented = save_fragmented;
1924 if (tvb_offset_exists(tvb, offset)) {
1925 switch (cnf_type & CNF_TYPE) {
1929 /* Continue with COTP if any data.
1930 XXX - if this isn't the first Derived PDU of a segmented Initial
1933 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
1934 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1935 pinfo->fragmented = save_fragmented;
1936 return; /* yes, it appears to be COTP or CLTP */
1942 /* The payload is the header and "none, some, or all of the data
1943 part of the discarded PDU", i.e. it's like an ICMP error;
1944 dissect it as a CLNP PDU. */
1945 if (check_col(pinfo->cinfo, COL_INFO))
1946 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1948 next_length = tvb_length_remaining(tvb, offset);
1949 if (next_length != 0) {
1950 /* We have payload; dissect it. */
1951 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
1953 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
1955 /* Save the current value of the "we're inside an error packet"
1956 flag, and set that flag; subdissectors may treat packets
1957 that are the payload of error packets differently from
1959 save_in_error_pkt = pinfo->in_error_pkt;
1960 pinfo->in_error_pkt = TRUE;
1962 call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
1964 /* Restore the "we're inside an error packet" flag. */
1965 pinfo->in_error_pkt = save_in_error_pkt;
1968 pinfo->fragmented = save_fragmented;
1969 return; /* we're done with this PDU */
1973 /* XXX - dissect this */
1977 if (check_col(pinfo->cinfo, COL_INFO))
1978 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1979 call_dissector(data_handle,next_tvb, pinfo, tree);
1980 pinfo->fragmented = save_fragmented;
1981 } /* dissect_clnp */
1984 clnp_reassemble_init(void)
1986 fragment_table_init(&clnp_segment_table);
1989 void proto_register_clnp(void)
1991 static hf_register_info hf[] = {
1993 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
1994 VALS(nlpid_vals), 0x0, "", HFILL }},
1997 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2000 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2003 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2006 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2008 { &hf_clnp_pdu_length,
2009 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2011 { &hf_clnp_checksum,
2012 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2014 { &hf_clnp_dest_length,
2015 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2018 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2020 { &hf_clnp_src_length,
2021 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2024 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2026 { &hf_clnp_segment_overlap,
2027 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2028 "Segment overlaps with other segments", HFILL }},
2030 { &hf_clnp_segment_overlap_conflict,
2031 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2032 "Overlapping segments contained conflicting data", HFILL }},
2034 { &hf_clnp_segment_multiple_tails,
2035 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2036 "Several tails were found when reassembling the packet", HFILL }},
2038 { &hf_clnp_segment_too_long_segment,
2039 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2040 "Segment contained data past end of packet", HFILL }},
2042 { &hf_clnp_segment_error,
2043 { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2044 "Reassembly error due to illegal segments", HFILL }},
2047 { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2048 "CLNP Segment", HFILL }},
2050 { &hf_clnp_segments,
2051 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2052 "CLNP Segments", HFILL }},
2054 static gint *ett[] = {
2062 module_t *clnp_module;
2064 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2065 proto_register_field_array(proto_clnp, hf, array_length(hf));
2066 proto_register_subtree_array(ett, array_length(ett));
2067 register_dissector("clnp", dissect_clnp, proto_clnp);
2069 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2070 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2071 "NSAP selector for Transport Protocol (last byte in hexa)",
2072 "NSAP selector for Transport Protocol (last byte in hexa)",
2073 16, &tp_nsap_selector);
2074 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2075 "Always try to decode NSDU as transport PDUs",
2076 "Always try to decode NSDU as transport PDUs",
2077 &always_decode_transport);
2078 prefs_register_bool_preference(clnp_module, "reassemble",
2079 "Reassemble segmented CLNP datagrams",
2080 "Whether segmented CLNP datagrams should be reassembled",
2084 void proto_register_cotp(void)
2086 /* static hf_register_info hf[] = {
2088 { "Name", "cotp.abbreviation", TYPE, VALS_POINTER }},
2090 static gint *ett[] = {
2094 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2095 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2096 proto_register_subtree_array(ett, array_length(ett));
2098 /* subdissector code in inactive subset */
2099 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2101 /* other COTP/ISO 8473 subdissectors */
2102 register_heur_dissector_list("cotp", &cotp_heur_subdissector_list);
2104 /* XXX - what about CLTP and proto_cltp? */
2105 register_dissector("ositp", dissect_ositp, proto_cotp);
2108 void proto_register_cltp(void)
2110 /* static hf_register_info hf[] = {
2112 { "Name", "cltp.abbreviation", TYPE, VALS_POINTER }},
2114 static gint *ett[] = {
2118 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2119 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2120 proto_register_subtree_array(ett, array_length(ett));
2121 register_init_routine(clnp_reassemble_init);
2125 proto_reg_handoff_clnp(void)
2127 data_handle = find_dissector("data");
2129 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2130 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2131 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2132 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);