2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.62 2002/12/19 11:22:13 sahlberg Exp $
5 * Laurent Deniel <deniel@worldnet.fr>
6 * Ralf Schneider <Ralf.Schneider@t-online.de>
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 data_handle;
92 * ISO 8473 OSI CLNP definition (see RFC994)
94 * _________________________________
96 * |_________________________________|
98 * |_________________________________|
99 * | Segmentation Part (optional) |
100 * |_________________________________|
101 * | Options Part (optional) |
102 * |_________________________________|
103 * | Data (optional) |
104 * |_________________________________|
107 #define ISO8473_V1 0x01 /* CLNP version 1 */
111 #define CNF_TYPE 0x1f
112 #define CNF_ERR_OK 0x20
113 #define CNF_MORE_SEGS 0x40
114 #define CNF_SEG_OK 0x80
119 #define ERQ_NPDU 0x1E
120 #define ERP_NPDU 0x1F
122 static const value_string npdu_type_abbrev_vals[] = {
131 static const value_string npdu_type_vals[] = {
133 { MD_NPDU, "Multicast Data" },
134 { ER_NPDU, "Error Report" },
135 { ERQ_NPDU, "Echo Request" },
136 { ERP_NPDU, "Echo Response" },
142 #define P_CLNP_PROTO_ID 0
143 #define P_CLNP_HDR_LEN 1
144 #define P_CLNP_VERS 2
146 #define P_CLNP_TYPE 4
147 #define P_CLNP_SEGLEN 5
148 #define P_CLNP_CKSUM 7
149 #define P_CLNP_ADDRESS_PART 9
151 /* Segmentation part */
153 struct clnp_segment {
154 gushort cng_id; /* data unit identifier */
155 gushort cng_off; /* segment offset */
156 gushort cng_tot_len; /* total length */
161 #define NSEL_NET 0x00
166 * ISO8073 OSI COTP definition (see RFC905)
169 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
171 /* TPDU definition */
173 #define ED_TPDU 0x1 /* COTP */
174 #define EA_TPDU 0x2 /* COTP */
175 #define UD_TPDU 0x4 /* CLTP */
176 #define RJ_TPDU 0x5 /* COTP */
177 #define AK_TPDU 0x6 /* COTP */
178 #define ER_TPDU 0x7 /* COTP */
179 #define DR_TPDU 0x8 /* COTP */
180 #define DC_TPDU 0xC /* COTP */
181 #define CC_TPDU 0xD /* COTP */
182 #define CR_TPDU 0xE /* COTP */
183 #define DT_TPDU 0xF /* COTP */
192 #define P_TPDU_NR_0_1 2
193 #define P_TPDU_NR_234 4
194 #define P_VAR_PART_NDT 5
195 #define P_VAR_PART_EDT 8
196 #define P_VAR_PART_DC 6
197 #define P_CDT_IN_AK 8
198 #define P_CDT_IN_RJ 8
199 #define P_REJECT_ER 4
200 #define P_REASON_IN_DR 6
201 #define P_CLASS_OPTION 6
203 /* TPDU length indicator */
205 #define LI_NORMAL_DT_CLASS_01 2
206 #define LI_NORMAL_DT_WITH_CHECKSUM 8
207 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
208 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
209 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
210 #define LI_NORMAL_EA_WITH_CHECKSUM 8
211 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
212 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
213 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
214 #define LI_NORMAL_RJ 4
215 #define LI_EXTENDED_RJ 9
221 /* XXX - can we always decide this based on whether the length
222 indicator is odd or not? What if the variable part has an odd
224 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
228 #define VP_ACK_TIME 0x85
229 #define VP_RES_ERROR 0x86
230 #define VP_PRIORITY 0x87
231 #define VP_TRANSIT_DEL 0x88
232 #define VP_THROUGHPUT 0x89
233 #define VP_SEQ_NR 0x8A /* in AK */
234 #define VP_REASSIGNMENT 0x8B
235 #define VP_FLOW_CNTL 0x8C /* in AK */
236 #define VP_TPDU_SIZE 0xC0
237 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
238 #define VP_DST_TSAP 0xC2
239 #define VP_CHECKSUM 0xC3
240 #define VP_VERSION_NR 0xC4
241 #define VP_PROTECTION 0xC5
242 #define VP_OPT_SEL 0xC6
243 #define VP_PROTO_CLASS 0xC7
244 #define VP_PREF_MAX_TPDU_SIZE 0xF0
245 #define VP_INACTIVITY_TIMER 0xF2
247 static const value_string tp_vpart_type_vals[] = {
248 { VP_ACK_TIME, "ack time" },
249 { VP_RES_ERROR, "res error" },
250 { VP_PRIORITY, "priority" },
251 { VP_TRANSIT_DEL, "transit delay" },
252 { VP_THROUGHPUT, "throughput" },
253 { VP_SEQ_NR, "seq number" },
254 { VP_REASSIGNMENT, "reassignment" },
255 { VP_FLOW_CNTL, "flow control" },
256 { VP_TPDU_SIZE, "tpdu-size" },
257 { VP_SRC_TSAP, "src-tsap" },
258 { VP_DST_TSAP, "dst-tsap" },
259 { VP_CHECKSUM, "checksum" },
260 { VP_VERSION_NR, "version" },
261 { VP_PROTECTION, "protection" },
262 { VP_OPT_SEL, "options" },
263 { VP_PROTO_CLASS, "proto class" },
264 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
270 #define EXTRACT_SHORT(p) pntohs(p)
271 #define EXTRACT_LONG(p) pntohl(p)
273 /* global variables */
275 static guchar li, tpdu, cdt; /* common fields */
276 static gushort dst_ref;
278 /* List of dissectors to call for COTP packets put atop the Inactive
280 static heur_dissector_list_t cotp_is_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 osi_decode_tp_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 osi_decode_DR(tvbuff_t *tvb, int offset,
672 packet_info *pinfo, proto_tree *tree)
674 proto_tree *cotp_tree;
683 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
684 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
687 case (128+0): str = "Normal Disconnect"; break;
688 case (128+1): str = "Remote transport entity congestion"; break;
689 case (128+2): str = "Connection negotiation failed"; break;
690 case (128+3): str = "Duplicate source reference"; break;
691 case (128+4): str = "Mismatched references"; break;
692 case (128+5): str = "Protocol error"; break;
693 case (128+7): str = "Reference overflow"; break;
694 case (128+8): str = "Connection requestion refused"; break;
695 case (128+10):str = "Header or parameter length invalid"; break;
696 case (0): str = "Reason not specified"; break;
697 case (1): str = "Congestion at TSAP"; break;
698 case (2): str = "Session entity not attached to TSAP"; break;
699 case (3): str = "Address unknown"; break;
705 if (check_col(pinfo->cinfo, COL_INFO))
706 col_append_fstr(pinfo->cinfo, COL_INFO,
707 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
711 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
712 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
713 proto_tree_add_text(cotp_tree, tvb, offset, 1,
714 "Length indicator: %u", li);
715 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
716 "TPDU code: 0x%x (DR)", tpdu);
717 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
718 "Destination reference: 0x%04x", dst_ref);
719 proto_tree_add_text(cotp_tree, tvb, offset + 4, 2,
720 "Source reference: 0x%04x", src_ref);
721 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
728 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
729 offset += tvb_length_remaining(tvb, offset);
730 /* we dissected all of the containing PDU */
734 } /* osi_decode_DR */
736 static int osi_decode_DT(tvbuff_t *tvb, int offset,
737 packet_info *pinfo, proto_tree *tree,
738 gboolean uses_inactive_subset,
739 gboolean *subdissector_found)
741 proto_tree *cotp_tree = NULL;
743 gboolean is_extended;
744 gboolean is_class_234;
749 /* VP_CHECKSUM is the only parameter allowed in the variable part.
750 (This means we may misdissect this if the packet is bad and
751 contains other parameters.) */
754 case LI_NORMAL_DT_WITH_CHECKSUM :
755 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
759 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
760 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
761 if ( tpdu_nr & 0x80 )
762 tpdu_nr = tpdu_nr & 0x7F;
769 case LI_EXTENDED_DT_WITH_CHECKSUM :
770 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
774 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
775 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
776 if ( tpdu_nr & 0x80000000 )
777 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
784 case LI_NORMAL_DT_CLASS_01 :
785 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
786 if ( tpdu_nr & 0x80 )
787 tpdu_nr = tpdu_nr & 0x7F;
791 is_class_234 = FALSE;
794 default : /* bad TPDU */
800 if (check_col(pinfo->cinfo, COL_INFO))
801 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
804 (fragment)? "(fragment)" : "");
807 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
808 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
809 proto_tree_add_text(cotp_tree, tvb, offset, 1,
810 "Length indicator: %u", li);
815 proto_tree_add_text(cotp_tree, tvb, offset, 1,
816 "TPDU code: 0x%x (DT)", tpdu);
824 proto_tree_add_text(cotp_tree, tvb, offset, 2,
825 "Destination reference: 0x%04x", dst_ref);
833 proto_tree_add_text(cotp_tree, tvb, offset, 4,
834 "TPDU number: 0x%08x (%s)",
836 (fragment)? "fragment":"complete");
842 proto_tree_add_text(cotp_tree, tvb, offset, 1,
843 "TPDU number: 0x%02x (%s)",
845 (fragment)? "fragment":"complete");
852 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
855 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
856 if (uses_inactive_subset){
857 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
859 *subdissector_found = TRUE;
861 /* Fill in other Dissectors using inactive subset here */
862 call_dissector(data_handle,next_tvb, pinfo, tree);
865 call_dissector(data_handle,next_tvb, pinfo, tree);
866 offset += tvb_length_remaining(tvb, offset);
867 /* we dissected all of the containing PDU */
871 } /* osi_decode_DT */
873 static int osi_decode_ED(tvbuff_t *tvb, int offset,
874 packet_info *pinfo, proto_tree *tree)
876 proto_tree *cotp_tree = NULL;
878 gboolean is_extended;
882 /* ED TPDUs are never fragmented */
884 /* VP_CHECKSUM is the only parameter allowed in the variable part.
885 (This means we may misdissect this if the packet is bad and
886 contains other parameters.) */
889 case LI_NORMAL_DT_WITH_CHECKSUM :
890 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
894 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
895 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
896 if ( tpdu_nr & 0x80 )
897 tpdu_nr = tpdu_nr & 0x7F;
903 case LI_EXTENDED_DT_WITH_CHECKSUM :
904 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
908 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
909 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
910 if ( tpdu_nr & 0x80000000 )
911 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
917 default : /* bad TPDU */
923 if (check_col(pinfo->cinfo, COL_INFO))
924 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
928 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
929 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
930 proto_tree_add_text(cotp_tree, tvb, offset, 1,
931 "Length indicator: %u", li);
936 proto_tree_add_text(cotp_tree, tvb, offset, 1,
937 "TPDU code: 0x%x (ED)", tpdu);
943 proto_tree_add_text(cotp_tree, tvb, offset, 2,
944 "Destination reference: 0x%04x", dst_ref);
951 proto_tree_add_text(cotp_tree, tvb, offset, 4,
952 "TPDU number: 0x%02x", tpdu_nr);
958 proto_tree_add_text(cotp_tree, tvb, offset, 1,
959 "TPDU number: 0x%02x", tpdu_nr);
966 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
969 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
970 call_dissector(data_handle,next_tvb, pinfo, tree);
972 offset += tvb_length_remaining(tvb, offset);
973 /* we dissected all of the containing PDU */
977 } /* osi_decode_ED */
979 static int osi_decode_RJ(tvbuff_t *tvb, int offset,
980 packet_info *pinfo, proto_tree *tree)
982 proto_tree *cotp_tree;
989 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
991 case LI_EXTENDED_RJ :
992 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
993 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
1001 if (check_col(pinfo->cinfo, COL_INFO))
1002 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
1006 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1007 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1008 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1009 "Length indicator: %u", li);
1010 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1011 "TPDU code: 0x%x (RJ)", tpdu);
1012 if (li == LI_NORMAL_RJ)
1013 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1015 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1016 "Destination reference: 0x%04x", dst_ref);
1017 if (li == LI_NORMAL_RJ)
1018 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1019 "Your TPDU number: 0x%02x", tpdu_nr);
1021 proto_tree_add_text(cotp_tree, tvb, offset + 4, 4,
1022 "Your TPDU number: 0x%02x", tpdu_nr);
1023 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1024 "Credit: 0x%02x", credit);
1032 } /* osi_decode_RJ */
1034 static int osi_decode_CC(tvbuff_t *tvb, int offset,
1035 packet_info *pinfo, proto_tree *tree)
1038 /* CC & CR decoding in the same function */
1040 proto_tree *cotp_tree = NULL;
1043 guchar class_option;
1045 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1046 class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1047 if (class_option > 4)
1050 if (check_col(pinfo->cinfo, COL_INFO))
1051 col_append_fstr(pinfo->cinfo, COL_INFO,
1052 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1053 (tpdu == CR_TPDU) ? "CR" : "CC",
1058 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1059 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1060 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1061 "Length indicator: %u", li);
1066 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1067 "TPDU code: 0x%x (%s)", tpdu,
1068 (tpdu == CR_TPDU) ? "CR" : "CC");
1074 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1075 "Destination reference: 0x%04x", dst_ref);
1081 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1082 "Source reference: 0x%04x", src_ref);
1088 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1089 "Class option: 0x%02x", class_option);
1095 osi_decode_tp_var_part(tvb, offset, li, class_option, cotp_tree);
1099 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
1100 offset += tvb_length_remaining(tvb, offset);
1101 /* we dissected all of the containing PDU */
1105 } /* osi_decode_CC */
1107 static int osi_decode_DC(tvbuff_t *tvb, int offset,
1108 packet_info *pinfo, proto_tree *tree)
1110 proto_tree *cotp_tree = NULL;
1117 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1119 if (check_col(pinfo->cinfo, COL_INFO))
1120 col_append_fstr(pinfo->cinfo, COL_INFO,
1121 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1126 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1127 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1128 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1129 "Length indicator: %u", li);
1134 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1135 "TPDU code: 0x%x (DC)", tpdu);
1141 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1142 "Destination reference: 0x%04x", dst_ref);
1148 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1149 "Source reference: 0x%04x", src_ref);
1155 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1160 } /* osi_decode_DC */
1162 static int osi_decode_AK(tvbuff_t *tvb, int offset,
1163 packet_info *pinfo, proto_tree *tree)
1165 proto_tree *cotp_tree = NULL;
1173 if (is_LI_NORMAL_AK(li)) {
1175 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1177 if (check_col(pinfo->cinfo, COL_INFO))
1178 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1182 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1183 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1184 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1185 "Length indicator: %u", li);
1190 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1191 "TPDU code: 0x%x (AK)", tpdu);
1192 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1199 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1200 "Destination reference: 0x%04x", dst_ref);
1206 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1207 "Your TPDU number: 0x%02x", tpdu_nr);
1213 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1216 } else { /* extended format */
1218 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1219 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1221 if (check_col(pinfo->cinfo, COL_INFO))
1222 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1226 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1227 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1228 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1229 "Length indicator: %u", li);
1234 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1235 "TPDU code: 0x%x (AK)", tpdu);
1241 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1242 "Destination reference: 0x%04x", dst_ref);
1248 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1249 "Your TPDU number: 0x%08x", tpdu_nr);
1255 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1256 "Credit: 0x%04x", cdt_in_ak);
1262 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1265 } /* is_LI_NORMAL_AK */
1269 } /* osi_decode_AK */
1271 static int osi_decode_EA(tvbuff_t *tvb, int offset,
1272 packet_info *pinfo, proto_tree *tree)
1274 proto_tree *cotp_tree = NULL;
1276 gboolean is_extended;
1282 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1283 (This means we may misdissect this if the packet is bad and
1284 contains other parameters.) */
1287 case LI_NORMAL_EA_WITH_CHECKSUM :
1288 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1289 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1293 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1294 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1295 is_extended = FALSE;
1298 case LI_EXTENDED_EA_WITH_CHECKSUM :
1299 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1300 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1304 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1305 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1309 default : /* bad TPDU */
1315 if (check_col(pinfo->cinfo, COL_INFO))
1316 col_append_fstr(pinfo->cinfo, COL_INFO,
1317 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1320 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1321 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1322 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1323 "Length indicator: %u", li);
1328 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1329 "TPDU code: 0x%x (EA)", tpdu);
1335 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1336 "Destination reference: 0x%04x", dst_ref);
1343 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1344 "Your TPDU number: 0x%08x", tpdu_nr);
1350 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1351 "Your TPDU number: 0x%02x", tpdu_nr);
1358 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1363 } /* osi_decode_EA */
1365 static int osi_decode_ER(tvbuff_t *tvb, int offset,
1366 packet_info *pinfo, proto_tree *tree)
1368 proto_tree *cotp_tree;
1375 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1377 str = "Reason not specified";
1380 str = "Invalid parameter code";
1383 str = "Invalid TPDU type";
1386 str = "Invalid parameter value";
1394 if (check_col(pinfo->cinfo, COL_INFO))
1395 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1398 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1399 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1400 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1401 "Length indicator: %u", li);
1402 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1403 "TPDU code: 0x%x (ER)", tpdu);
1404 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1405 "Destination reference: 0x%04x", dst_ref);
1406 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1407 "Reject cause: %s", str);
1414 } /* osi_decode_ER */
1416 static int osi_decode_UD(tvbuff_t *tvb, int offset,
1417 packet_info *pinfo, proto_tree *tree)
1420 proto_tree *cltp_tree = NULL;
1423 if (check_col(pinfo->cinfo, COL_INFO))
1424 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1427 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1428 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1429 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1430 "Length indicator: %u", li);
1435 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1436 "TPDU code: 0x%x (UD)", tpdu);
1442 osi_decode_tp_var_part(tvb, offset, li, 0, cltp_tree);
1445 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1446 call_dissector(data_handle,next_tvb, pinfo, tree);
1447 offset += tvb_length_remaining(tvb, offset);
1448 /* we dissected all of the containing PDU */
1452 } /* osi_decode_UD */
1454 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1457 There doesn't seem to be any way in which the OSI network layer protocol
1458 distinguishes between COTP and CLTP, but the first two octets of both
1459 protocols' headers mean the same thing - length and PDU type - and the
1460 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1461 both of them here. */
1462 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1463 proto_tree *tree, gboolean uses_inactive_subset)
1466 gboolean first_tpdu = TRUE;
1468 gboolean found_ositp = FALSE;
1469 gboolean is_cltp = FALSE;
1470 gboolean subdissector_found = FALSE;
1472 if (!proto_is_protocol_enabled(proto_cotp))
1473 return FALSE; /* COTP has been disabled */
1474 /* XXX - what about CLTP? */
1476 pinfo->current_proto = "COTP";
1478 /* Initialize the COL_INFO field; each of the TPDUs will have its
1479 information appended. */
1480 if (check_col(pinfo->cinfo, COL_INFO))
1481 col_add_str(pinfo->cinfo, COL_INFO, "");
1483 while (tvb_offset_exists(tvb, offset)) {
1485 if (check_col(pinfo->cinfo, COL_INFO))
1486 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1488 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1489 if (check_col(pinfo->cinfo, COL_INFO))
1490 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1492 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1497 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1498 if (tpdu == UD_TPDU)
1499 pinfo->current_proto = "CLTP"; /* connectionless transport */
1500 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1501 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1506 new_offset = osi_decode_CC(tvb, offset, pinfo, tree);
1509 new_offset = osi_decode_DR(tvb, offset, pinfo, tree);
1512 new_offset = osi_decode_DT(tvb, offset, pinfo, tree,
1513 uses_inactive_subset, &subdissector_found);
1516 new_offset = osi_decode_ED(tvb, offset, pinfo, tree);
1519 new_offset = osi_decode_RJ(tvb, offset, pinfo, tree);
1522 new_offset = osi_decode_DC(tvb, offset, pinfo, tree);
1525 new_offset = osi_decode_AK(tvb, offset, pinfo, tree);
1528 new_offset = osi_decode_EA(tvb, offset, pinfo, tree);
1531 new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
1534 new_offset = osi_decode_UD(tvb, offset, pinfo, tree);
1538 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1539 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1540 new_offset = -1; /* bad PDU type */
1544 if (new_offset == -1) { /* incorrect TPDU */
1546 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1),
1552 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1553 is either COTP or CLTP. */
1554 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1555 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1559 offset = new_offset;
1563 } /* dissect_ositp_internal */
1565 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1567 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1568 call_dissector(data_handle,tvb, pinfo, tree);
1573 * CLNP part / main entry point
1576 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1578 proto_tree *clnp_tree = NULL;
1580 guint8 cnf_proto_id;
1585 char flag_string[6+1];
1586 char *pdu_type_string;
1587 proto_tree *type_tree;
1588 guint16 segment_length;
1590 guint16 segment_offset = 0;
1592 cksum_status_t cksum_status;
1594 guchar src_len, dst_len, nsel, opt_len = 0;
1595 const guint8 *dst_addr, *src_addr;
1598 proto_tree *discpdu_tree;
1599 volatile address save_dl_src;
1600 volatile address save_dl_dst;
1601 volatile address save_net_src;
1602 volatile address save_net_dst;
1603 volatile address save_src;
1604 volatile address save_dst;
1605 gboolean save_in_error_pkt;
1606 fragment_data *fd_head;
1607 tvbuff_t *volatile next_tvb;
1608 gboolean update_col_info = TRUE;
1609 gboolean save_fragmented;
1611 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1612 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1613 if (check_col(pinfo->cinfo, COL_INFO))
1614 col_clear(pinfo->cinfo, COL_INFO);
1616 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1617 if (cnf_proto_id == NLPID_NULL) {
1618 if (check_col(pinfo->cinfo, COL_INFO))
1619 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1621 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1622 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1623 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1627 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1628 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1632 /* return if version not known */
1633 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1634 if (cnf_vers != ISO8473_V1) {
1635 call_dissector(data_handle,tvb, pinfo, tree);
1639 /* fixed part decoding */
1640 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1641 opt_len = cnf_hdr_len;
1644 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1645 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1646 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1648 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1650 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1652 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1653 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1655 "Holding Time : %u (%u.%u secs)",
1656 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1659 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1660 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1661 "Unknown (0x%02x)");
1662 flag_string[0] = '\0';
1663 if (cnf_type & CNF_SEG_OK)
1664 strcat(flag_string, "S ");
1665 if (cnf_type & CNF_MORE_SEGS)
1666 strcat(flag_string, "M ");
1667 if (cnf_type & CNF_ERR_OK)
1668 strcat(flag_string, "E ");
1670 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1672 "PDU Type : 0x%02x (%s%s)",
1676 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1677 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1678 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1679 "Segmentation permitted",
1680 "Segmentation not permitted"));
1681 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1682 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1685 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1686 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1687 "Report error if PDU discarded",
1688 "Don't report error if PDU discarded"));
1689 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1690 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1691 npdu_type_vals, "%s"));
1694 /* If we don't have the full header - i.e., not enough to see the
1695 segmentation part and determine whether this datagram is segmented
1696 or not - set the Info column now; we'll get an exception before
1697 we set it otherwise. */
1699 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1700 if (check_col(pinfo->cinfo, COL_INFO))
1701 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1704 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1705 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1706 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1708 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1710 switch (cksum_status) {
1714 * No checksum present, or not enough of the header present to
1717 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1720 "Checksum : 0x%04x",
1726 * Checksum is correct.
1728 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1731 "Checksum : 0x%04x (correct)",
1737 * Checksum is not correct.
1739 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1742 "Checksum : 0x%04x (incorrect)",
1746 opt_len -= 9; /* Fixed part of Hesder */
1751 offset = P_CLNP_ADDRESS_PART;
1752 dst_len = tvb_get_guint8(tvb, offset);
1753 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1754 nsel = tvb_get_guint8(tvb, offset + dst_len);
1755 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1756 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1759 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1761 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1764 print_nsap_net(dst_addr, dst_len));
1765 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1766 offset + 1 + dst_len, 1, src_len);
1767 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1768 offset + dst_len + 2, src_len,
1771 print_nsap_net(src_addr, src_len));
1773 opt_len -= dst_len + src_len +2;
1776 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1777 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1778 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1779 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1781 /* Segmentation Part */
1783 offset += dst_len + src_len + 2;
1785 if (cnf_type & CNF_SEG_OK) {
1786 struct clnp_segment seg; /* XXX - not used */
1787 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1789 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1790 du_id = tvb_get_ntohs(tvb, offset);
1792 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1793 "Data unit identifier: %06u",
1795 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1796 "Segment offset : %6u",
1798 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1799 "Total length : %6u",
1800 tvb_get_ntohs(tvb, offset + 4));
1808 /* To do : decode options */
1810 proto_tree_add_text(clnp_tree, tvb, offset,
1811 cnf_hdr_len - offset,
1812 "Options/Data: <not shown>");
1814 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1816 dissect_osi_options( opt_len,
1817 tvb, offset, clnp_tree );
1820 /* Length of CLNP datagram plus headers above it. */
1821 len = segment_length;
1823 offset = cnf_hdr_len;
1825 /* If clnp_reassemble is on, and this is a segment, we have all the
1826 * data in the segment, and the checksum is valid, then just add the
1827 * segment to the hashtable.
1829 save_fragmented = pinfo->fragmented;
1830 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1831 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1832 (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1833 cksum_status != CKSUM_NOT_OK) {
1834 fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1835 segment_offset, segment_length - cnf_hdr_len,
1836 cnf_type & CNF_MORE_SEGS);
1838 if (fd_head != NULL) {
1839 /* OK, we have the complete reassembled payload.
1840 Allocate a new tvbuff, referring to the reassembled payload. */
1841 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1844 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1845 were handed refers, so it'll get cleaned up when that tvbuff
1847 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1849 /* Add the defragmented data to the data source list. */
1850 add_new_data_source(pinfo, next_tvb, "Reassembled CLNP");
1852 update_col_info = !show_fragment_tree(fd_head, &clnp_frag_items,
1853 clnp_tree, pinfo, next_tvb);
1855 /* We don't have the complete reassembled payload. */
1859 /* If this is the first segment, dissect its contents, otherwise
1860 just show it as a segment.
1862 XXX - if we eventually don't save the reassembled contents of all
1863 segmented datagrams, we may want to always reassemble. */
1864 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1865 /* Not the first segment - don't dissect it. */
1868 /* First segment, or not segmented. Dissect what we have here. */
1870 /* Get a tvbuff for the payload. */
1871 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1874 * If this is the first segment, but not the only segment,
1875 * tell the next protocol that.
1877 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1878 pinfo->fragmented = TRUE;
1880 pinfo->fragmented = FALSE;
1884 if (next_tvb == NULL) {
1885 /* Just show this as a segment. */
1886 if (check_col(pinfo->cinfo, COL_INFO))
1887 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1888 pdu_type_string, flag_string, segment_offset);
1890 /* As we haven't reassembled anything, we haven't changed "pi", so
1891 we don't have to restore it. */
1892 call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
1894 pinfo->fragmented = save_fragmented;
1898 if (tvb_offset_exists(tvb, offset)) {
1899 switch (cnf_type & CNF_TYPE) {
1903 /* Continue with COTP if any data.
1904 XXX - if this isn't the first Derived PDU of a segmented Initial
1907 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
1908 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1909 pinfo->fragmented = save_fragmented;
1910 return; /* yes, it appears to be COTP or CLTP */
1916 /* The payload is the header and "none, some, or all of the data
1917 part of the discarded PDU", i.e. it's like an ICMP error;
1918 dissect it as a CLNP PDU. */
1919 if (check_col(pinfo->cinfo, COL_INFO))
1920 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1922 next_length = tvb_length_remaining(tvb, offset);
1923 if (next_length != 0) {
1924 /* We have payload; dissect it.
1925 Make the columns non-writable, so the packet isn't shown
1926 in the summary based on what the discarded PDU's contents
1928 col_set_writable(pinfo->cinfo, FALSE);
1930 /* Also, save the current values of the addresses, and restore
1931 them when we're finished dissecting the contained packet, so
1932 that the address columns in the summary don't reflect the
1933 contained packet, but reflect this packet instead. */
1934 save_dl_src = pinfo->dl_src;
1935 save_dl_dst = pinfo->dl_dst;
1936 save_net_src = pinfo->net_src;
1937 save_net_dst = pinfo->net_dst;
1938 save_src = pinfo->src;
1939 save_dst = pinfo->dst;
1941 /* Save the current value of the "we're inside an error packet"
1942 flag, and set that flag; subdissectors may treat packets
1943 that are the payload of error packets differently from
1945 save_in_error_pkt = pinfo->in_error_pkt;
1946 pinfo->in_error_pkt = TRUE;
1948 /* Dissect the contained packet.
1949 Catch ReportedBoundsError, and do nothing if we see it,
1950 because it's not an error if the contained packet is short;
1951 there's no guarantee that all of it was included.
1953 XXX - should catch BoundsError, and re-throw it after cleaning
1955 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
1957 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
1959 dissect_clnp(next_tvb, pinfo, discpdu_tree);
1961 CATCH(ReportedBoundsError) {
1966 /* Restore the "we're inside an error packet" flag. */
1967 pinfo->in_error_pkt = save_in_error_pkt;
1969 /* Restore the addresses. */
1970 pinfo->dl_src = save_dl_src;
1971 pinfo->dl_dst = save_dl_dst;
1972 pinfo->net_src = save_net_src;
1973 pinfo->net_dst = save_net_dst;
1974 pinfo->src = save_src;
1975 pinfo->dst = save_dst;
1978 pinfo->fragmented = save_fragmented;
1979 return; /* we're done with this PDU */
1983 /* XXX - dissect this */
1987 if (check_col(pinfo->cinfo, COL_INFO))
1988 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1989 call_dissector(data_handle,next_tvb, pinfo, tree);
1990 pinfo->fragmented = save_fragmented;
1991 } /* dissect_clnp */
1994 clnp_reassemble_init(void)
1996 fragment_table_init(&clnp_segment_table);
1999 void proto_register_clnp(void)
2001 static hf_register_info hf[] = {
2003 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2004 VALS(nlpid_vals), 0x0, "", HFILL }},
2007 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2010 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2013 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2016 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2018 { &hf_clnp_pdu_length,
2019 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2021 { &hf_clnp_checksum,
2022 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2024 { &hf_clnp_dest_length,
2025 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2028 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2030 { &hf_clnp_src_length,
2031 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2034 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2036 { &hf_clnp_segment_overlap,
2037 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2038 "Segment overlaps with other segments", HFILL }},
2040 { &hf_clnp_segment_overlap_conflict,
2041 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2042 "Overlapping segments contained conflicting data", HFILL }},
2044 { &hf_clnp_segment_multiple_tails,
2045 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2046 "Several tails were found when reassembling the packet", HFILL }},
2048 { &hf_clnp_segment_too_long_segment,
2049 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2050 "Segment contained data past end of packet", HFILL }},
2052 { &hf_clnp_segment_error,
2053 { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2054 "Reassembly error due to illegal segments", HFILL }},
2057 { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2058 "CLNP Segment", HFILL }},
2060 { &hf_clnp_segments,
2061 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2062 "CLNP Segments", HFILL }},
2064 static gint *ett[] = {
2072 module_t *clnp_module;
2074 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2075 proto_register_field_array(proto_clnp, hf, array_length(hf));
2076 proto_register_subtree_array(ett, array_length(ett));
2078 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2079 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2080 "NSAP selector for Transport Protocol (last byte in hexa)",
2081 "NSAP selector for Transport Protocol (last byte in hexa)",
2082 16, &tp_nsap_selector);
2083 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2084 "Always try to decode NSDU as transport PDUs",
2085 "Always try to decode NSDU as transport PDUs",
2086 &always_decode_transport);
2087 prefs_register_bool_preference(clnp_module, "reassemble",
2088 "Reassemble segmented CLNP datagrams",
2089 "Whether segmented CLNP datagrams should be reassembled",
2093 void proto_register_cotp(void)
2095 /* static hf_register_info hf[] = {
2097 { "Name", "cotp.abbreviation", TYPE, VALS_POINTER }},
2099 static gint *ett[] = {
2103 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2104 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2105 proto_register_subtree_array(ett, array_length(ett));
2107 /* subdissector code */
2108 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2110 /* XXX - what about CLTP? */
2111 register_dissector("ositp", dissect_ositp, proto_cotp);
2114 void proto_register_cltp(void)
2116 /* static hf_register_info hf[] = {
2118 { "Name", "cltp.abbreviation", TYPE, VALS_POINTER }},
2120 static gint *ett[] = {
2124 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2125 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2126 proto_register_subtree_array(ett, array_length(ett));
2127 register_init_routine(clnp_reassemble_init);
2131 proto_reg_handoff_clnp(void)
2133 dissector_handle_t clnp_handle;
2135 data_handle = find_dissector("data");
2137 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2138 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2139 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2140 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);