2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.50 2002/02/27 05:45:48 guy 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.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
40 #include <epan/packet.h>
41 #include "reassemble.h"
42 #include "packet-osi.h"
43 #include "packet-osi-options.h"
44 #include "packet-isis.h"
45 #include "packet-esis.h"
48 /* protocols and fields */
50 static int proto_clnp = -1;
51 static gint ett_clnp = -1;
52 static gint ett_clnp_type = -1;
53 static gint ett_clnp_segments = -1;
54 static gint ett_clnp_segment = -1;
55 static gint ett_clnp_disc_pdu = -1;
56 static int proto_cotp = -1;
57 static gint ett_cotp = -1;
58 static int proto_cltp = -1;
59 static gint ett_cltp = -1;
61 static int hf_clnp_id = -1;
62 static int hf_clnp_length = -1;
63 static int hf_clnp_version = -1;
64 static int hf_clnp_ttl = -1;
65 static int hf_clnp_type = -1;
66 static int hf_clnp_pdu_length = -1;
67 static int hf_clnp_checksum = -1;
68 static int hf_clnp_dest_length = -1;
69 static int hf_clnp_dest = -1;
70 static int hf_clnp_src_length = -1;
71 static int hf_clnp_src = -1;
72 static int hf_clnp_segments = -1;
73 static int hf_clnp_segment = -1;
74 static int hf_clnp_segment_overlap = -1;
75 static int hf_clnp_segment_overlap_conflict = -1;
76 static int hf_clnp_segment_multiple_tails = -1;
77 static int hf_clnp_segment_too_long_segment = -1;
78 static int hf_clnp_segment_error = -1;
80 static dissector_handle_t data_handle;
83 * ISO 8473 OSI CLNP definition (see RFC994)
85 * _________________________________
87 * |_________________________________|
89 * |_________________________________|
90 * | Segmentation Part (optional) |
91 * |_________________________________|
92 * | Options Part (optional) |
93 * |_________________________________|
95 * |_________________________________|
98 #define ISO8473_V1 0x01 /* CLNP version 1 */
102 #define CNF_TYPE 0x1f
103 #define CNF_ERR_OK 0x20
104 #define CNF_MORE_SEGS 0x40
105 #define CNF_SEG_OK 0x80
110 #define ERQ_NPDU 0x1E
111 #define ERP_NPDU 0x1F
113 static const value_string npdu_type_abbrev_vals[] = {
122 static const value_string npdu_type_vals[] = {
124 { MD_NPDU, "Multicast Data" },
125 { ER_NPDU, "Error Report" },
126 { ERQ_NPDU, "Echo Request" },
127 { ERP_NPDU, "Echo Response" },
133 #define P_CLNP_PROTO_ID 0
134 #define P_CLNP_HDR_LEN 1
135 #define P_CLNP_VERS 2
137 #define P_CLNP_TYPE 4
138 #define P_CLNP_SEGLEN 5
139 #define P_CLNP_CKSUM 7
140 #define P_CLNP_ADDRESS_PART 9
142 /* Segmentation part */
144 struct clnp_segment {
145 u_short cng_id; /* data unit identifier */
146 u_short cng_off; /* segment offset */
147 u_short cng_tot_len; /* total length */
152 #define NSEL_NET 0x00
157 * ISO8073 OSI COTP definition (see RFC905)
160 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
162 /* TPDU definition */
164 #define ED_TPDU 0x1 /* COTP */
165 #define EA_TPDU 0x2 /* COTP */
166 #define UD_TPDU 0x4 /* CLTP */
167 #define RJ_TPDU 0x5 /* COTP */
168 #define AK_TPDU 0x6 /* COTP */
169 #define ER_TPDU 0x7 /* COTP */
170 #define DR_TPDU 0x8 /* COTP */
171 #define DC_TPDU 0xC /* COTP */
172 #define CC_TPDU 0xD /* COTP */
173 #define CR_TPDU 0xE /* COTP */
174 #define DT_TPDU 0xF /* COTP */
183 #define P_TPDU_NR_0_1 2
184 #define P_TPDU_NR_234 4
185 #define P_VAR_PART_NDT 5
186 #define P_VAR_PART_EDT 8
187 #define P_VAR_PART_DC 6
188 #define P_CDT_IN_AK 8
189 #define P_CDT_IN_RJ 8
190 #define P_REJECT_ER 4
191 #define P_REASON_IN_DR 6
192 #define P_CLASS_OPTION 6
194 /* TPDU length indicator */
196 #define LI_NORMAL_DT_CLASS_01 2
197 #define LI_NORMAL_DT_WITH_CHECKSUM 8
198 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
199 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
200 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
201 #define LI_NORMAL_EA_WITH_CHECKSUM 8
202 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
203 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
204 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
205 #define LI_NORMAL_RJ 4
206 #define LI_EXTENDED_RJ 9
212 /* XXX - can we always decide this based on whether the length
213 indicator is odd or not? What if the variable part has an odd
215 #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 )
219 #define VP_ACK_TIME 0x85
220 #define VP_RES_ERROR 0x86
221 #define VP_PRIORITY 0x87
222 #define VP_TRANSIT_DEL 0x88
223 #define VP_THROUGHPUT 0x89
224 #define VP_SEQ_NR 0x8A /* in AK */
225 #define VP_REASSIGNMENT 0x8B
226 #define VP_FLOW_CNTL 0x8C /* in AK */
227 #define VP_TPDU_SIZE 0xC0
228 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
229 #define VP_DST_TSAP 0xC2
230 #define VP_CHECKSUM 0xC3
231 #define VP_VERSION_NR 0xC4
232 #define VP_PROTECTION 0xC5
233 #define VP_OPT_SEL 0xC6
234 #define VP_PROTO_CLASS 0xC7
235 #define VP_PREF_MAX_TPDU_SIZE 0xF0
236 #define VP_INACTIVITY_TIMER 0xF2
238 static const value_string tp_vpart_type_vals[] = {
239 { VP_ACK_TIME, "ack time" },
240 { VP_RES_ERROR, "res error" },
241 { VP_PRIORITY, "priority" },
242 { VP_TRANSIT_DEL, "transit delay" },
243 { VP_THROUGHPUT, "throughput" },
244 { VP_SEQ_NR, "seq number" },
245 { VP_REASSIGNMENT, "reassignment" },
246 { VP_FLOW_CNTL, "flow control" },
247 { VP_TPDU_SIZE, "tpdu-size" },
248 { VP_SRC_TSAP, "src-tsap" },
249 { VP_DST_TSAP, "dst-tsap" },
250 { VP_CHECKSUM, "checksum" },
251 { VP_VERSION_NR, "version" },
252 { VP_PROTECTION, "protection" },
253 { VP_OPT_SEL, "options" },
254 { VP_PROTO_CLASS, "proto class" },
255 { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" },
261 #define EXTRACT_SHORT(p) pntohs(p)
262 #define EXTRACT_LONG(p) pntohl(p)
264 /* global variables */
266 static u_char li, tpdu, cdt; /* common fields */
267 static u_short dst_ref;
269 /* List of dissectors to call for COTP packets put atop the Inactive
271 static heur_dissector_list_t cotp_is_heur_subdissector_list;
274 * Reassembly of CLNP.
276 static GHashTable *clnp_segment_table = NULL;
279 static guint tp_nsap_selector = NSEL_TP;
280 static gboolean always_decode_transport = FALSE;
281 static gboolean clnp_reassemble = FALSE;
283 /* function definitions */
285 #define MAX_TSAP_LEN 32
286 static gchar *print_tsap(const u_char *tsap, int length)
289 static gchar str[3][MAX_TSAP_LEN * 2 + 1];
292 gboolean allprintable;
295 if (cur == &str[0][0]) {
297 } else if (cur == &str[1][0]) {
305 if (length <= 0 || length > MAX_TSAP_LEN)
306 sprintf(cur, "<unsupported TSAP length>");
309 for (i=0;i<length;i++) {
310 /* If any byte is not printable ASCII, display the TSAP as a
311 series of hex byte values rather than as a string; this
312 means that, for example, accented letters will cause it
313 to be displayed as hex, but it also means that byte values
314 such as 0xff and 0xfe, which *are* printable ISO 8859/x
315 characters, won't be treated as printable - 0xfffffffe
316 is probably binary, not text. */
317 if (!(isascii(tsap[i]) && isprint(tsap[i]))) {
325 while (length != 0) {
327 sprintf(tmp, "%c", *tsap ++);
329 sprintf(tmp, "%02x", *tsap ++);
338 static gboolean osi_decode_tp_var_part(tvbuff_t *tvb, int offset,
339 int vp_length, int class_option,
344 guint16 s, s1,s2,s3,s4;
345 guint32 t1, t2, t3, t4;
346 guint32 pref_max_tpdu_size;
348 while (vp_length != 0) {
349 code = tvb_get_guint8(tvb, offset);
350 proto_tree_add_text(tree, tvb, offset, 1,
351 "Parameter code: 0x%02x (%s)",
353 val_to_str(code, tp_vpart_type_vals, "Unknown"));
359 length = tvb_get_guint8(tvb, offset);
360 proto_tree_add_text(tree, tvb, offset, 1,
361 "Parameter length: %u", length);
368 s = tvb_get_ntohs(tvb, offset);
369 proto_tree_add_text(tree, tvb, offset, length,
370 "Ack time (ms): %u", s);
376 proto_tree_add_text(tree, tvb, offset, 1,
377 "Residual error rate, target value: 10^%u",
378 tvb_get_guint8(tvb, offset));
383 proto_tree_add_text(tree, tvb, offset, 1,
384 "Residual error rate, minimum acceptable: 10^%u",
385 tvb_get_guint8(tvb, offset));
391 proto_tree_add_text(tree, tvb, offset, 1,
392 "Residual error rate, TSDU size of interest: %u",
393 1<<tvb_get_guint8(tvb, offset));
401 s = tvb_get_ntohs(tvb, offset);
402 proto_tree_add_text(tree, tvb, offset, length,
409 s1 = tvb_get_ntohs(tvb, offset);
410 proto_tree_add_text(tree, tvb, offset, 2,
411 "Transit delay, target value, calling-called: %u ms", s1);
416 s2 = tvb_get_ntohs(tvb, offset);
417 proto_tree_add_text(tree, tvb, offset, 2,
418 "Transit delay, maximum acceptable, calling-called: %u ms", s2);
423 s3 = tvb_get_ntohs(tvb, offset);
424 proto_tree_add_text(tree, tvb, offset, 2,
425 "Transit delay, target value, called-calling: %u ms", s3);
430 s4 = tvb_get_ntohs(tvb, offset);
431 proto_tree_add_text(tree, tvb, offset, 2,
432 "Transit delay, maximum acceptable, called-calling: %u ms", s4);
439 t1 = tvb_get_ntoh24(tvb, offset);
440 proto_tree_add_text(tree, tvb, offset, 3,
441 "Maximum throughput, target value, calling-called: %u o/s", t1);
446 t2 = tvb_get_ntoh24(tvb, offset);
447 proto_tree_add_text(tree, tvb, offset, 3,
448 "Maximum throughput, minimum acceptable, calling-called: %u o/s", t2);
453 t3 = tvb_get_ntoh24(tvb, offset);
454 proto_tree_add_text(tree, tvb, offset, 3,
455 "Maximum throughput, target value, called-calling: %u o/s", t3);
460 t4 = tvb_get_ntoh24(tvb, offset);
461 proto_tree_add_text(tree, tvb, offset, 3,
462 "Maximum throughput, minimum acceptable, called-calling: %u o/s", t4);
467 if (length != 0) { /* XXX - should be 0 or 12 */
468 t1 = tvb_get_ntoh24(tvb, offset);
469 proto_tree_add_text(tree, tvb, offset, 3,
470 "Average throughput, target value, calling-called: %u o/s", t1);
475 t2 = tvb_get_ntoh24(tvb, offset);
476 proto_tree_add_text(tree, tvb, offset, 3,
477 "Average throughput, minimum acceptable, calling-called: %u o/s", t2);
482 t3 = tvb_get_ntoh24(tvb, offset);
483 proto_tree_add_text(tree, tvb, offset, 3,
484 "Average throughput, target value, called-calling: %u o/s", t3);
489 t4 = tvb_get_ntoh24(tvb, offset);
490 proto_tree_add_text(tree, tvb, offset, 3,
491 "Average throughput, minimum acceptable, called-calling: %u o/s", t4);
499 proto_tree_add_text(tree, tvb, offset, 2,
500 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
505 case VP_REASSIGNMENT:
506 proto_tree_add_text(tree, tvb, offset, 2,
507 "Reassignment time: %u secs", tvb_get_ntohs(tvb, offset));
513 proto_tree_add_text(tree, tvb, offset, 4,
514 "Lower window edge: 0x%08x", tvb_get_ntohl(tvb, offset));
519 proto_tree_add_text(tree, tvb, offset, 2,
520 "Sequence number: 0x%04x", tvb_get_ntohs(tvb, offset));
525 proto_tree_add_text(tree, tvb, offset, 2,
526 "Credit: 0x%04x", tvb_get_ntohs(tvb, offset));
534 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
535 proto_tree_add_text(tree, tvb, offset, length,
536 "TPDU size: %u", 1 << c1);
542 proto_tree_add_text(tree, tvb, offset, length,
544 print_tsap(tvb_get_ptr(tvb, offset, length), length));
550 proto_tree_add_text(tree, tvb, offset, length,
552 print_tsap(tvb_get_ptr(tvb, offset, length), length));
558 proto_tree_add_text(tree, tvb, offset, length,
559 "Checksum: 0x%04x", tvb_get_ntohs(tvb, offset));
565 c1 = tvb_get_guint8(tvb, offset);
566 proto_tree_add_text(tree, tvb, offset, length,
573 c1 = tvb_get_guint8(tvb, offset) & 0x0F;
574 switch (class_option) {
578 proto_tree_add_text(tree, tvb, offset, 1,
579 "Use of network expedited data");
581 proto_tree_add_text(tree, tvb, offset, 1,
582 "Non use of network expedited data");
584 proto_tree_add_text(tree, tvb, offset, 1,
585 "Use of Receipt confirmation");
587 proto_tree_add_text(tree, tvb, offset, 1,
588 "Use of explicit AK variant");
593 proto_tree_add_text(tree, tvb, offset, 1,
594 "Non-use 16 bit checksum in class 4");
596 proto_tree_add_text(tree, tvb, offset, 1,
597 "Use 16 bit checksum ");
601 proto_tree_add_text(tree, tvb, offset, 1,
602 "Use of transport expedited data transfer\n");
604 proto_tree_add_text(tree, tvb, offset, 1,
605 "Non-use of transport expedited data transfer");
610 case VP_PREF_MAX_TPDU_SIZE:
614 pref_max_tpdu_size = tvb_get_guint8(tvb, offset);
618 pref_max_tpdu_size = tvb_get_ntohs(tvb, offset);
622 pref_max_tpdu_size = tvb_get_ntoh24(tvb, offset);
626 pref_max_tpdu_size = tvb_get_ntohl(tvb, offset);
630 proto_tree_add_text(tree, tvb, offset, length,
631 "Preferred maximum TPDU size: bogus length %u (not 1, 2, 3, or 4)",
635 proto_tree_add_text(tree, tvb, offset, length,
636 "Preferred maximum TPDU size: %u", pref_max_tpdu_size*128);
641 case VP_INACTIVITY_TIMER:
642 proto_tree_add_text(tree, tvb, offset, length,
643 "Inactivity timer: %u ms", tvb_get_ntohl(tvb, offset));
648 case VP_PROTECTION: /* user-defined */
649 case VP_PROTO_CLASS: /* todo */
650 default: /* unknown, no decoding */
651 proto_tree_add_text(tree, tvb, offset, length,
652 "Parameter value: <not shown>");
662 static int osi_decode_DR(tvbuff_t *tvb, int offset,
663 packet_info *pinfo, proto_tree *tree)
665 proto_tree *cotp_tree;
674 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
675 reason = tvb_get_guint8(tvb, offset + P_REASON_IN_DR);
678 case (128+0): str = "Normal Disconnect"; break;
679 case (128+1): str = "Remote transport entity congestion"; break;
680 case (128+2): str = "Connection negotiation failed"; break;
681 case (128+3): str = "Duplicate source reference"; break;
682 case (128+4): str = "Mismatched references"; break;
683 case (128+5): str = "Protocol error"; break;
684 case (128+7): str = "Reference overflow"; break;
685 case (128+8): str = "Connection requestion refused"; break;
686 case (128+10):str = "Header or parameter length invalid"; break;
687 case (0): str = "Reason not specified"; break;
688 case (1): str = "Congestion at TSAP"; break;
689 case (2): str = "Session entity not attached to TSAP"; break;
690 case (3): str = "Address unknown"; break;
696 if (check_col(pinfo->cinfo, COL_INFO))
697 col_append_fstr(pinfo->cinfo, COL_INFO,
698 "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
702 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
703 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
704 proto_tree_add_text(cotp_tree, tvb, offset, 1,
705 "Length indicator: %u", li);
706 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
707 "TPDU code: 0x%x (DR)", tpdu);
708 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
709 "Destination reference: 0x%04x", dst_ref);
710 proto_tree_add_text(cotp_tree, tvb, offset + 4, 2,
711 "Source reference: 0x%04x", src_ref);
712 proto_tree_add_text(cotp_tree, tvb, offset + 6, 1,
719 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
720 offset += tvb_length_remaining(tvb, offset);
721 /* we dissected all of the containing PDU */
725 } /* osi_decode_DR */
727 static int osi_decode_DT(tvbuff_t *tvb, int offset,
728 packet_info *pinfo, proto_tree *tree,
729 gboolean uses_inactive_subset,
730 gboolean *subdissector_found)
732 proto_tree *cotp_tree = NULL;
734 gboolean is_extended;
735 gboolean is_class_234;
740 /* VP_CHECKSUM is the only parameter allowed in the variable part.
741 (This means we may misdissect this if the packet is bad and
742 contains other parameters.) */
745 case LI_NORMAL_DT_WITH_CHECKSUM :
746 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
750 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
751 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
752 if ( tpdu_nr & 0x80 )
753 tpdu_nr = tpdu_nr & 0x7F;
760 case LI_EXTENDED_DT_WITH_CHECKSUM :
761 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
765 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
766 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
767 if ( tpdu_nr & 0x80000000 )
768 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
775 case LI_NORMAL_DT_CLASS_01 :
776 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_0_1);
777 if ( tpdu_nr & 0x80 )
778 tpdu_nr = tpdu_nr & 0x7F;
782 is_class_234 = FALSE;
785 default : /* bad TPDU */
791 if (check_col(pinfo->cinfo, COL_INFO))
792 col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
795 (fragment)? "(fragment)" : "");
798 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
799 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
800 proto_tree_add_text(cotp_tree, tvb, offset, 1,
801 "Length indicator: %u", li);
806 proto_tree_add_text(cotp_tree, tvb, offset, 1,
807 "TPDU code: 0x%x (DT)", tpdu);
815 proto_tree_add_text(cotp_tree, tvb, offset, 2,
816 "Destination reference: 0x%04x", dst_ref);
824 proto_tree_add_text(cotp_tree, tvb, offset, 4,
825 "TPDU number: 0x%08x (%s)",
827 (fragment)? "fragment":"complete");
833 proto_tree_add_text(cotp_tree, tvb, offset, 1,
834 "TPDU number: 0x%02x (%s)",
836 (fragment)? "fragment":"complete");
843 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
846 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
847 if (uses_inactive_subset){
848 if (dissector_try_heuristic(cotp_is_heur_subdissector_list, next_tvb,
850 *subdissector_found = TRUE;
852 /* Fill in other Dissectors using inactive subset here */
853 call_dissector(data_handle,next_tvb, pinfo, tree);
856 call_dissector(data_handle,next_tvb, pinfo, tree);
857 offset += tvb_length_remaining(tvb, offset);
858 /* we dissected all of the containing PDU */
862 } /* osi_decode_DT */
864 static int osi_decode_ED(tvbuff_t *tvb, int offset,
865 packet_info *pinfo, proto_tree *tree)
867 proto_tree *cotp_tree = NULL;
869 gboolean is_extended;
873 /* ED TPDUs are never fragmented */
875 /* VP_CHECKSUM is the only parameter allowed in the variable part.
876 (This means we may misdissect this if the packet is bad and
877 contains other parameters.) */
880 case LI_NORMAL_DT_WITH_CHECKSUM :
881 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM)
885 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
886 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
887 if ( tpdu_nr & 0x80 )
888 tpdu_nr = tpdu_nr & 0x7F;
894 case LI_EXTENDED_DT_WITH_CHECKSUM :
895 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM)
899 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
900 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
901 if ( tpdu_nr & 0x80000000 )
902 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
908 default : /* bad TPDU */
914 if (check_col(pinfo->cinfo, COL_INFO))
915 col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
919 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
920 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
921 proto_tree_add_text(cotp_tree, tvb, offset, 1,
922 "Length indicator: %u", li);
927 proto_tree_add_text(cotp_tree, tvb, offset, 1,
928 "TPDU code: 0x%x (ED)", tpdu);
934 proto_tree_add_text(cotp_tree, tvb, offset, 2,
935 "Destination reference: 0x%04x", dst_ref);
942 proto_tree_add_text(cotp_tree, tvb, offset, 4,
943 "TPDU number: 0x%02x", tpdu_nr);
949 proto_tree_add_text(cotp_tree, tvb, offset, 1,
950 "TPDU number: 0x%02x", tpdu_nr);
957 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
960 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
961 call_dissector(data_handle,next_tvb, pinfo, tree);
963 offset += tvb_length_remaining(tvb, offset);
964 /* we dissected all of the containing PDU */
968 } /* osi_decode_ED */
970 static int osi_decode_RJ(tvbuff_t *tvb, int offset,
971 packet_info *pinfo, proto_tree *tree)
973 proto_tree *cotp_tree;
980 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
982 case LI_EXTENDED_RJ :
983 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
984 credit = tvb_get_ntohs(tvb, offset + P_CDT_IN_RJ);
992 if (check_col(pinfo->cinfo, COL_INFO))
993 col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
997 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
998 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
999 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1000 "Length indicator: %u", li);
1001 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1002 "TPDU code: 0x%x (RJ)", tpdu);
1003 if (li == LI_NORMAL_RJ)
1004 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1006 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1007 "Destination reference: 0x%04x", dst_ref);
1008 if (li == LI_NORMAL_RJ)
1009 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1010 "Your TPDU number: 0x%02x", tpdu_nr);
1012 proto_tree_add_text(cotp_tree, tvb, offset + 4, 4,
1013 "Your TPDU number: 0x%02x", tpdu_nr);
1014 proto_tree_add_text(cotp_tree, tvb, offset + 8, 2,
1015 "Credit: 0x%02x", credit);
1023 } /* osi_decode_RJ */
1025 static int osi_decode_CC(tvbuff_t *tvb, int offset,
1026 packet_info *pinfo, proto_tree *tree)
1029 /* CC & CR decoding in the same function */
1031 proto_tree *cotp_tree = NULL;
1034 u_char class_option;
1036 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1037 class_option = (tvb_get_guint8(tvb, offset + P_CLASS_OPTION) >> 4 ) & 0x0F;
1038 if (class_option > 4)
1041 if (check_col(pinfo->cinfo, COL_INFO))
1042 col_append_fstr(pinfo->cinfo, COL_INFO,
1043 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1044 (tpdu == CR_TPDU) ? "CR" : "CC",
1049 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1050 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1051 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1052 "Length indicator: %u", li);
1057 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1058 "TPDU code: 0x%x (%s)", tpdu,
1059 (tpdu == CR_TPDU) ? "CR" : "CC");
1065 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1066 "Destination reference: 0x%04x", dst_ref);
1072 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1073 "Source reference: 0x%04x", src_ref);
1079 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1080 "Class option: 0x%02x", class_option);
1086 osi_decode_tp_var_part(tvb, offset, li, class_option, cotp_tree);
1090 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1091 offset += tvb_length_remaining(tvb, offset);
1092 /* we dissected all of the containing PDU */
1096 } /* osi_decode_CC */
1098 static int osi_decode_DC(tvbuff_t *tvb, int offset,
1099 packet_info *pinfo, proto_tree *tree)
1101 proto_tree *cotp_tree = NULL;
1108 src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
1110 if (check_col(pinfo->cinfo, COL_INFO))
1111 col_append_fstr(pinfo->cinfo, COL_INFO,
1112 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
1117 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1118 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1119 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1120 "Length indicator: %u", li);
1125 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1126 "TPDU code: 0x%x (DC)", tpdu);
1132 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1133 "Destination reference: 0x%04x", dst_ref);
1139 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1140 "Source reference: 0x%04x", src_ref);
1146 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1151 } /* osi_decode_DC */
1153 static int osi_decode_AK(tvbuff_t *tvb, int offset,
1154 packet_info *pinfo, proto_tree *tree)
1156 proto_tree *cotp_tree = NULL;
1164 if (is_LI_NORMAL_AK(li)) {
1166 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1168 if (check_col(pinfo->cinfo, COL_INFO))
1169 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1173 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1174 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1175 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1176 "Length indicator: %u", li);
1181 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1182 "TPDU code: 0x%x (AK)", tpdu);
1183 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1190 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1191 "Destination reference: 0x%04x", dst_ref);
1197 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1198 "Your TPDU number: 0x%02x", tpdu_nr);
1204 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1207 } else { /* extended format */
1209 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1210 cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
1212 if (check_col(pinfo->cinfo, COL_INFO))
1213 col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1217 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1218 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1219 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1220 "Length indicator: %u", li);
1225 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1226 "TPDU code: 0x%x (AK)", tpdu);
1232 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1233 "Destination reference: 0x%04x", dst_ref);
1239 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1240 "Your TPDU number: 0x%08x", tpdu_nr);
1246 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1247 "Credit: 0x%04x", cdt_in_ak);
1253 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1256 } /* is_LI_NORMAL_AK */
1260 } /* osi_decode_AK */
1262 static int osi_decode_EA(tvbuff_t *tvb, int offset,
1263 packet_info *pinfo, proto_tree *tree)
1265 proto_tree *cotp_tree = NULL;
1267 gboolean is_extended;
1273 /* VP_CHECKSUM is the only parameter allowed in the variable part.
1274 (This means we may misdissect this if the packet is bad and
1275 contains other parameters.) */
1278 case LI_NORMAL_EA_WITH_CHECKSUM :
1279 if (tvb_get_guint8(tvb, offset + P_VAR_PART_NDT) != VP_CHECKSUM ||
1280 tvb_get_guint8(tvb, offset + P_VAR_PART_NDT + 1) != 2)
1284 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1285 tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
1286 is_extended = FALSE;
1289 case LI_EXTENDED_EA_WITH_CHECKSUM :
1290 if (tvb_get_guint8(tvb, offset + P_VAR_PART_EDT) != VP_CHECKSUM ||
1291 tvb_get_guint8(tvb, offset + P_VAR_PART_EDT + 1) != 2)
1295 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1296 tpdu_nr = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
1300 default : /* bad TPDU */
1306 if (check_col(pinfo->cinfo, COL_INFO))
1307 col_append_fstr(pinfo->cinfo, COL_INFO,
1308 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1311 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1312 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1313 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1314 "Length indicator: %u", li);
1319 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1320 "TPDU code: 0x%x (EA)", tpdu);
1326 proto_tree_add_text(cotp_tree, tvb, offset, 2,
1327 "Destination reference: 0x%04x", dst_ref);
1334 proto_tree_add_text(cotp_tree, tvb, offset, 4,
1335 "Your TPDU number: 0x%08x", tpdu_nr);
1341 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1342 "Your TPDU number: 0x%02x", tpdu_nr);
1349 osi_decode_tp_var_part(tvb, offset, li, 4, cotp_tree);
1354 } /* osi_decode_EA */
1356 static int osi_decode_ER(tvbuff_t *tvb, int offset,
1357 packet_info *pinfo, proto_tree *tree)
1359 proto_tree *cotp_tree;
1366 switch(tvb_get_guint8(tvb, offset + P_REJECT_ER)) {
1368 str = "Reason not specified";
1371 str = "Invalid parameter code";
1374 str = "Invalid TPDU type";
1377 str = "Invalid parameter value";
1385 if (check_col(pinfo->cinfo, COL_INFO))
1386 col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1389 ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
1390 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1391 proto_tree_add_text(cotp_tree, tvb, offset, 1,
1392 "Length indicator: %u", li);
1393 proto_tree_add_text(cotp_tree, tvb, offset + 1, 1,
1394 "TPDU code: 0x%x (ER)", tpdu);
1395 proto_tree_add_text(cotp_tree, tvb, offset + 2, 2,
1396 "Destination reference: 0x%04x", dst_ref);
1397 proto_tree_add_text(cotp_tree, tvb, offset + 4, 1,
1398 "Reject cause: %s", str);
1405 } /* osi_decode_ER */
1407 static int osi_decode_UD(tvbuff_t *tvb, int offset,
1408 packet_info *pinfo, proto_tree *tree,
1409 gboolean *subdissector_found)
1412 proto_tree *cltp_tree = NULL;
1415 if (check_col(pinfo->cinfo, COL_INFO))
1416 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1419 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1420 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1421 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1422 "Length indicator: %u", li);
1427 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1428 "TPDU code: 0x%x (UD)", tpdu);
1434 osi_decode_tp_var_part(tvb, offset, li, 0, cltp_tree);
1437 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1438 call_dissector(data_handle,next_tvb, pinfo, tree);
1439 offset += tvb_length_remaining(tvb, offset);
1440 /* we dissected all of the containing PDU */
1444 } /* osi_decode_UD */
1446 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1449 There doesn't seem to be any way in which the OSI network layer protocol
1450 distinguishes between COTP and CLTP, but the first two octets of both
1451 protocols' headers mean the same thing - length and PDU type - and the
1452 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1453 both of them here. */
1454 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1455 proto_tree *tree, gboolean uses_inactive_subset)
1458 gboolean first_tpdu = TRUE;
1460 gboolean found_ositp = FALSE;
1461 gboolean is_cltp = FALSE;
1462 gboolean subdissector_found = FALSE;
1464 if (!proto_is_protocol_enabled(proto_cotp))
1465 return FALSE; /* COTP has been disabled */
1466 /* XXX - what about CLTP? */
1468 pinfo->current_proto = "COTP";
1470 /* Initialize the COL_INFO field; each of the TPDUs will have its
1471 information appended. */
1472 if (check_col(pinfo->cinfo, COL_INFO))
1473 col_add_str(pinfo->cinfo, COL_INFO, "");
1475 while (tvb_offset_exists(tvb, offset)) {
1477 if (check_col(pinfo->cinfo, COL_INFO))
1478 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1480 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1481 if (check_col(pinfo->cinfo, COL_INFO))
1482 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1484 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1488 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1489 if (tpdu == UD_TPDU)
1490 pinfo->current_proto = "CLTP"; /* connectionless transport */
1491 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1492 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1497 new_offset = osi_decode_CC(tvb, offset, pinfo, tree);
1500 new_offset = osi_decode_DR(tvb, offset, pinfo, tree);
1503 new_offset = osi_decode_DT(tvb, offset, pinfo, tree,
1504 uses_inactive_subset, &subdissector_found);
1507 new_offset = osi_decode_ED(tvb, offset, pinfo, tree);
1510 new_offset = osi_decode_RJ(tvb, offset, pinfo, tree);
1513 new_offset = osi_decode_DC(tvb, offset, pinfo, tree);
1516 new_offset = osi_decode_AK(tvb, offset, pinfo, tree);
1519 new_offset = osi_decode_EA(tvb, offset, pinfo, tree);
1522 new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
1525 new_offset = osi_decode_UD(tvb, offset, pinfo, tree,
1526 &subdissector_found);
1530 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1531 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1532 new_offset = -1; /* bad PDU type */
1536 if (new_offset == -1) { /* incorrect TPDU */
1538 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1543 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1544 is either COTP or CLTP. */
1545 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1546 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1550 offset = new_offset;
1554 } /* dissect_ositp_internal */
1556 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1558 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1559 call_dissector(data_handle,tvb, pinfo, tree);
1564 * CLNP part / main entry point
1567 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1569 proto_tree *clnp_tree = NULL;
1571 guint8 cnf_proto_id;
1576 char flag_string[6+1];
1577 char *pdu_type_string;
1578 proto_tree *type_tree;
1579 guint16 segment_length;
1581 guint16 segment_offset = 0;
1583 cksum_status_t cksum_status;
1585 u_char src_len, dst_len, nsel, opt_len = 0;
1586 const guint8 *dst_addr, *src_addr;
1589 proto_tree *discpdu_tree;
1590 volatile address save_dl_src;
1591 volatile address save_dl_dst;
1592 volatile address save_net_src;
1593 volatile address save_net_dst;
1594 volatile address save_src;
1595 volatile address save_dst;
1596 gboolean save_in_error_pkt;
1597 fragment_data *fd_head;
1598 tvbuff_t *volatile next_tvb;
1599 gboolean update_col_info = TRUE;
1600 gboolean save_fragmented;
1602 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1603 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1604 if (check_col(pinfo->cinfo, COL_INFO))
1605 col_clear(pinfo->cinfo, COL_INFO);
1607 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1608 if (cnf_proto_id == NLPID_NULL) {
1609 if (check_col(pinfo->cinfo, COL_INFO))
1610 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1612 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1613 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1614 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1618 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1619 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1623 /* return if version not known */
1624 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1625 if (cnf_vers != ISO8473_V1) {
1626 call_dissector(data_handle,tvb, pinfo, tree);
1630 /* fixed part decoding */
1631 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1632 opt_len = cnf_hdr_len;
1635 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1636 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1637 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1639 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1641 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1643 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1644 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1646 "Holding Time : %u (%u.%u secs)",
1647 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1650 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1651 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1652 "Unknown (0x%02x)");
1653 flag_string[0] = '\0';
1654 if (cnf_type & CNF_SEG_OK)
1655 strcat(flag_string, "S ");
1656 if (cnf_type & CNF_MORE_SEGS)
1657 strcat(flag_string, "M ");
1658 if (cnf_type & CNF_ERR_OK)
1659 strcat(flag_string, "E ");
1661 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1663 "PDU Type : 0x%02x (%s%s)",
1667 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1668 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1669 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1670 "Segmentation permitted",
1671 "Segmentation not permitted"));
1672 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1673 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1676 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1677 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1678 "Report error if PDU discarded",
1679 "Don't report error if PDU discarded"));
1680 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1681 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1682 npdu_type_vals, "%s"));
1685 /* If we don't have the full header - i.e., not enough to see the
1686 segmentation part and determine whether this datagram is segmented
1687 or not - set the Info column now; we'll get an exception before
1688 we set it otherwise. */
1690 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1691 if (check_col(pinfo->cinfo, COL_INFO))
1692 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1695 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1696 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1697 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1699 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1701 switch (cksum_status) {
1705 * No checksum present, or not enough of the header present to
1708 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1711 "Checksum : 0x%04x",
1717 * Checksum is correct.
1719 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1722 "Checksum : 0x%04x (correct)",
1728 * Checksum is not correct.
1730 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1733 "Checksum : 0x%04x (incorrect)",
1737 opt_len -= 9; /* Fixed part of Hesder */
1742 offset = P_CLNP_ADDRESS_PART;
1743 dst_len = tvb_get_guint8(tvb, offset);
1744 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1745 nsel = tvb_get_guint8(tvb, offset + dst_len);
1746 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1747 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1750 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1752 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1755 print_nsap_net(dst_addr, dst_len));
1756 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1757 offset + 1 + dst_len, 1, src_len);
1758 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1759 offset + dst_len + 2, src_len,
1762 print_nsap_net(src_addr, src_len));
1764 opt_len -= dst_len + src_len +2;
1767 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1768 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1769 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1770 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1772 /* Segmentation Part */
1774 offset += dst_len + src_len + 2;
1776 if (cnf_type & CNF_SEG_OK) {
1777 struct clnp_segment seg; /* XXX - not used */
1778 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1780 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1781 du_id = tvb_get_ntohs(tvb, offset);
1783 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1784 "Data unit identifier: %06u",
1786 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1787 "Segment offset : %6u",
1789 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1790 "Total length : %6u",
1791 tvb_get_ntohs(tvb, offset + 4));
1799 /* To do : decode options */
1801 proto_tree_add_text(clnp_tree, tvb, offset,
1802 cnf_hdr_len - offset,
1803 "Options/Data: <not shown>");
1805 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1807 dissect_osi_options( 0xff,
1809 tvb, offset, pinfo, clnp_tree );
1812 /* Length of CLNP datagram plus headers above it. */
1813 len = segment_length;
1815 offset = cnf_hdr_len;
1817 /* If clnp_reassemble is on, and this is a segment, we have all the
1818 * data in the segment, and the checksum is valid, then just add the
1819 * segment to the hashtable.
1821 save_fragmented = pinfo->fragmented;
1822 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1823 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1824 (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1825 cksum_status != CKSUM_NOT_OK) {
1826 fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1827 segment_offset, segment_length - cnf_hdr_len,
1828 cnf_type & CNF_MORE_SEGS);
1830 if (fd_head != NULL) {
1832 proto_tree *ft=NULL;
1833 proto_item *fi=NULL;
1835 /* OK, we have the complete reassembled payload. */
1836 /* show all segments */
1837 fi = proto_tree_add_item(clnp_tree, hf_clnp_segments,
1839 ft = proto_item_add_subtree(fi, ett_clnp_segments);
1840 for (fd = fd_head->next; fd != NULL; fd = fd->next){
1841 if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
1842 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1843 /* this segment has some flags set, create a subtree
1844 * for it and display the flags.
1846 proto_tree *fet = NULL;
1847 proto_item *fei = NULL;
1850 if (fd->flags & (FD_OVERLAPCONFLICT
1851 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1852 hf = hf_clnp_segment_error;
1854 hf = hf_clnp_segment;
1856 fei = proto_tree_add_none_format(ft, hf,
1858 "Frame:%u payload:%u-%u",
1861 fd->offset+fd->len-1
1863 fet = proto_item_add_subtree(fei, ett_clnp_segment);
1864 if (fd->flags&FD_OVERLAP) {
1865 proto_tree_add_boolean(fet,
1866 hf_clnp_segment_overlap, tvb, 0, 0,
1869 if (fd->flags&FD_OVERLAPCONFLICT) {
1870 proto_tree_add_boolean(fet,
1871 hf_clnp_segment_overlap_conflict, tvb, 0, 0,
1874 if (fd->flags&FD_MULTIPLETAILS) {
1875 proto_tree_add_boolean(fet,
1876 hf_clnp_segment_multiple_tails, tvb, 0, 0,
1879 if (fd->flags&FD_TOOLONGFRAGMENT) {
1880 proto_tree_add_boolean(fet,
1881 hf_clnp_segment_too_long_segment, tvb, 0, 0,
1885 /* nothing of interest for this segment */
1886 proto_tree_add_none_format(ft, hf_clnp_segment,
1888 "Frame:%u payload:%u-%u",
1891 fd->offset+fd->len-1
1895 if (fd_head->flags & (FD_OVERLAPCONFLICT
1896 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1897 if (check_col(pinfo->cinfo, COL_INFO)) {
1898 col_set_str(pinfo->cinfo, COL_INFO, "[Illegal segments]");
1899 update_col_info = FALSE;
1903 /* Allocate a new tvbuff, referring to the reassembled payload. */
1904 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1907 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1908 were handed refers, so it'll get cleaned up when that tvbuff
1910 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1912 /* Add the defragmented data to the data source list. */
1913 add_new_data_source(pinfo->fd, next_tvb, "Reassembled CLNP");
1915 /* It's not fragmented. */
1916 pinfo->fragmented = FALSE;
1918 /* We don't have the complete reassembled payload. */
1922 /* If this is the first segment, dissect its contents, otherwise
1923 just show it as a segment.
1925 XXX - if we eventually don't save the reassembled contents of all
1926 segmented datagrams, we may want to always reassemble. */
1927 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1928 /* Not the first segment - don't dissect it. */
1931 /* First segment, or not segmented. Dissect what we have here. */
1933 /* Get a tvbuff for the payload. */
1934 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1937 * If this is the first segment, but not the only segment,
1938 * tell the next protocol that.
1940 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1941 pinfo->fragmented = TRUE;
1943 pinfo->fragmented = FALSE;
1947 if (next_tvb == NULL) {
1948 /* Just show this as a segment. */
1949 if (check_col(pinfo->cinfo, COL_INFO))
1950 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1951 pdu_type_string, flag_string, segment_offset);
1953 /* As we haven't reassembled anything, we haven't changed "pi", so
1954 we don't have to restore it. */
1955 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1956 pinfo->fragmented = save_fragmented;
1960 if (tvb_offset_exists(tvb, offset)) {
1961 switch (cnf_type & CNF_TYPE) {
1965 /* Continue with COTP if any data.
1966 XXX - if this isn't the first Derived PDU of a segmented Initial
1969 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
1970 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1971 pinfo->fragmented = save_fragmented;
1972 return; /* yes, it appears to be COTP or CLTP */
1978 /* The payload is the header and "none, some, or all of the data
1979 part of the discarded PDU", i.e. it's like an ICMP error;
1980 dissect it as a CLNP PDU. */
1981 if (check_col(pinfo->cinfo, COL_INFO))
1982 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1984 next_length = tvb_length_remaining(tvb, offset);
1985 if (next_length != 0) {
1986 /* We have payload; dissect it.
1987 Make the columns non-writable, so the packet isn't shown
1988 in the summary based on what the discarded PDU's contents
1990 col_set_writable(pinfo->cinfo, FALSE);
1992 /* Also, save the current values of the addresses, and restore
1993 them when we're finished dissecting the contained packet, so
1994 that the address columns in the summary don't reflect the
1995 contained packet, but reflect this packet instead. */
1996 save_dl_src = pinfo->dl_src;
1997 save_dl_dst = pinfo->dl_dst;
1998 save_net_src = pinfo->net_src;
1999 save_net_dst = pinfo->net_dst;
2000 save_src = pinfo->src;
2001 save_dst = pinfo->dst;
2003 /* Save the current value of the "we're inside an error packet"
2004 flag, and set that flag; subdissectors may treat packets
2005 that are the payload of error packets differently from
2007 save_in_error_pkt = pinfo->in_error_pkt;
2008 pinfo->in_error_pkt = TRUE;
2010 /* Dissect the contained packet.
2011 Catch ReportedBoundsError, and do nothing if we see it,
2012 because it's not an error if the contained packet is short;
2013 there's no guarantee that all of it was included.
2015 XXX - should catch BoundsError, and re-throw it after cleaning
2017 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2019 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2021 dissect_clnp(next_tvb, pinfo, discpdu_tree);
2023 CATCH(ReportedBoundsError) {
2028 /* Restore the "we're inside an error packet" flag. */
2029 pinfo->in_error_pkt = save_in_error_pkt;
2031 /* Restore the addresses. */
2032 pinfo->dl_src = save_dl_src;
2033 pinfo->dl_dst = save_dl_dst;
2034 pinfo->net_src = save_net_src;
2035 pinfo->net_dst = save_net_dst;
2036 pinfo->src = save_src;
2037 pinfo->dst = save_dst;
2040 pinfo->fragmented = save_fragmented;
2041 return; /* we're done with this PDU */
2045 /* XXX - dissect this */
2049 if (check_col(pinfo->cinfo, COL_INFO))
2050 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2051 call_dissector(data_handle,next_tvb, pinfo, tree);
2052 pinfo->fragmented = save_fragmented;
2053 } /* dissect_clnp */
2056 clnp_reassemble_init(void)
2058 fragment_table_init(&clnp_segment_table);
2061 void proto_register_clnp(void)
2063 static hf_register_info hf[] = {
2065 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2066 VALS(nlpid_vals), 0x0, "", HFILL }},
2069 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2072 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2075 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2078 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2080 { &hf_clnp_pdu_length,
2081 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2083 { &hf_clnp_checksum,
2084 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2086 { &hf_clnp_dest_length,
2087 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2090 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2092 { &hf_clnp_src_length,
2093 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2096 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2098 { &hf_clnp_segment_overlap,
2099 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2100 "Segment overlaps with other segments", HFILL }},
2102 { &hf_clnp_segment_overlap_conflict,
2103 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2104 "Overlapping segments contained conflicting data", HFILL }},
2106 { &hf_clnp_segment_multiple_tails,
2107 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2108 "Several tails were found when reassembling the packet", HFILL }},
2110 { &hf_clnp_segment_too_long_segment,
2111 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2112 "Segment contained data past end of packet", HFILL }},
2114 { &hf_clnp_segment_error,
2115 { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0,
2116 "Reassembly error due to illegal segments", HFILL }},
2119 { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0,
2120 "CLNP Segment", HFILL }},
2122 { &hf_clnp_segments,
2123 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2124 "CLNP Segments", HFILL }},
2126 static gint *ett[] = {
2134 module_t *clnp_module;
2136 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2137 proto_register_field_array(proto_clnp, hf, array_length(hf));
2138 proto_register_subtree_array(ett, array_length(ett));
2140 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2141 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2142 "NSAP selector for Transport Protocol (last byte in hexa)",
2143 "NSAP selector for Transport Protocol (last byte in hexa)",
2144 16, &tp_nsap_selector);
2145 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2146 "Always try to decode NSDU as transport PDUs",
2147 "Always try to decode NSDU as transport PDUs",
2148 &always_decode_transport);
2149 prefs_register_bool_preference(clnp_module, "reassemble",
2150 "Reassemble segmented CLNP datagrams",
2151 "Whether segmented CLNP datagrams should be reassembled",
2155 void proto_register_cotp(void)
2157 /* static hf_register_info hf[] = {
2159 { "Name", "cotp.abbreviation", TYPE, VALS_POINTER }},
2161 static gint *ett[] = {
2165 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2166 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2167 proto_register_subtree_array(ett, array_length(ett));
2169 /* subdissector code */
2170 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2172 /* XXX - what about CLTP? */
2173 register_dissector("ositp", dissect_ositp, proto_cotp);
2176 void proto_register_cltp(void)
2178 /* static hf_register_info hf[] = {
2180 { "Name", "cltp.abbreviation", TYPE, VALS_POINTER }},
2182 static gint *ett[] = {
2186 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2187 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2188 proto_register_subtree_array(ett, array_length(ett));
2189 register_init_routine(clnp_reassemble_init);
2193 proto_reg_handoff_clnp(void)
2195 dissector_handle_t clnp_handle;
2197 data_handle = find_dissector("data");
2199 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2200 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2201 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2202 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);