2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.53 2002/04/07 21:54: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)
1411 proto_tree *cltp_tree = NULL;
1414 if (check_col(pinfo->cinfo, COL_INFO))
1415 col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
1418 ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
1419 cltp_tree = proto_item_add_subtree(ti, ett_cltp);
1420 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1421 "Length indicator: %u", li);
1426 proto_tree_add_text(cltp_tree, tvb, offset, 1,
1427 "TPDU code: 0x%x (UD)", tpdu);
1433 osi_decode_tp_var_part(tvb, offset, li, 0, cltp_tree);
1436 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1437 call_dissector(data_handle,next_tvb, pinfo, tree);
1438 offset += tvb_length_remaining(tvb, offset);
1439 /* we dissected all of the containing PDU */
1443 } /* osi_decode_UD */
1445 /* Returns TRUE if we found at least one valid COTP or CLTP PDU, FALSE
1448 There doesn't seem to be any way in which the OSI network layer protocol
1449 distinguishes between COTP and CLTP, but the first two octets of both
1450 protocols' headers mean the same thing - length and PDU type - and the
1451 only valid CLTP PDU type is not a valid COTP PDU type, so we'll handle
1452 both of them here. */
1453 static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
1454 proto_tree *tree, gboolean uses_inactive_subset)
1457 gboolean first_tpdu = TRUE;
1459 gboolean found_ositp = FALSE;
1460 gboolean is_cltp = FALSE;
1461 gboolean subdissector_found = FALSE;
1463 if (!proto_is_protocol_enabled(proto_cotp))
1464 return FALSE; /* COTP has been disabled */
1465 /* XXX - what about CLTP? */
1467 pinfo->current_proto = "COTP";
1469 /* Initialize the COL_INFO field; each of the TPDUs will have its
1470 information appended. */
1471 if (check_col(pinfo->cinfo, COL_INFO))
1472 col_add_str(pinfo->cinfo, COL_INFO, "");
1474 while (tvb_offset_exists(tvb, offset)) {
1476 if (check_col(pinfo->cinfo, COL_INFO))
1477 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1479 if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
1480 if (check_col(pinfo->cinfo, COL_INFO))
1481 col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
1483 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1487 tpdu = (tvb_get_guint8(tvb, offset + P_TPDU) >> 4) & 0x0F;
1488 if (tpdu == UD_TPDU)
1489 pinfo->current_proto = "CLTP"; /* connectionless transport */
1490 cdt = tvb_get_guint8(tvb, offset + P_CDT) & 0x0F;
1491 dst_ref = tvb_get_ntohs(tvb, offset + P_DST_REF);
1496 new_offset = osi_decode_CC(tvb, offset, pinfo, tree);
1499 new_offset = osi_decode_DR(tvb, offset, pinfo, tree);
1502 new_offset = osi_decode_DT(tvb, offset, pinfo, tree,
1503 uses_inactive_subset, &subdissector_found);
1506 new_offset = osi_decode_ED(tvb, offset, pinfo, tree);
1509 new_offset = osi_decode_RJ(tvb, offset, pinfo, tree);
1512 new_offset = osi_decode_DC(tvb, offset, pinfo, tree);
1515 new_offset = osi_decode_AK(tvb, offset, pinfo, tree);
1518 new_offset = osi_decode_EA(tvb, offset, pinfo, tree);
1521 new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
1524 new_offset = osi_decode_UD(tvb, offset, pinfo, tree);
1528 if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
1529 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1530 new_offset = -1; /* bad PDU type */
1534 if (new_offset == -1) { /* incorrect TPDU */
1536 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1541 /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
1542 is either COTP or CLTP. */
1543 if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
1544 col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
1548 offset = new_offset;
1552 } /* dissect_ositp_internal */
1554 static void dissect_ositp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1556 if (!dissect_ositp_internal(tvb, pinfo, tree, FALSE))
1557 call_dissector(data_handle,tvb, pinfo, tree);
1562 * CLNP part / main entry point
1565 static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1567 proto_tree *clnp_tree = NULL;
1569 guint8 cnf_proto_id;
1574 char flag_string[6+1];
1575 char *pdu_type_string;
1576 proto_tree *type_tree;
1577 guint16 segment_length;
1579 guint16 segment_offset = 0;
1581 cksum_status_t cksum_status;
1583 u_char src_len, dst_len, nsel, opt_len = 0;
1584 const guint8 *dst_addr, *src_addr;
1587 proto_tree *discpdu_tree;
1588 volatile address save_dl_src;
1589 volatile address save_dl_dst;
1590 volatile address save_net_src;
1591 volatile address save_net_dst;
1592 volatile address save_src;
1593 volatile address save_dst;
1594 gboolean save_in_error_pkt;
1595 fragment_data *fd_head;
1596 tvbuff_t *volatile next_tvb;
1597 gboolean update_col_info = TRUE;
1598 gboolean save_fragmented;
1600 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1601 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
1602 if (check_col(pinfo->cinfo, COL_INFO))
1603 col_clear(pinfo->cinfo, COL_INFO);
1605 cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
1606 if (cnf_proto_id == NLPID_NULL) {
1607 if (check_col(pinfo->cinfo, COL_INFO))
1608 col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
1610 ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
1611 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1612 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1616 next_tvb = tvb_new_subset(tvb, 1, -1, -1);
1617 dissect_ositp_internal(next_tvb, pinfo, tree, TRUE);
1621 /* return if version not known */
1622 cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS);
1623 if (cnf_vers != ISO8473_V1) {
1624 call_dissector(data_handle,tvb, pinfo, tree);
1628 /* fixed part decoding */
1629 cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN);
1630 opt_len = cnf_hdr_len;
1633 ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, FALSE);
1634 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1635 proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
1637 proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
1639 proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
1641 cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL);
1642 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
1644 "Holding Time : %u (%u.%u secs)",
1645 cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
1648 cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE);
1649 pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
1650 "Unknown (0x%02x)");
1651 flag_string[0] = '\0';
1652 if (cnf_type & CNF_SEG_OK)
1653 strcat(flag_string, "S ");
1654 if (cnf_type & CNF_MORE_SEGS)
1655 strcat(flag_string, "M ");
1656 if (cnf_type & CNF_ERR_OK)
1657 strcat(flag_string, "E ");
1659 ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
1661 "PDU Type : 0x%02x (%s%s)",
1665 type_tree = proto_item_add_subtree(ti, ett_clnp_type);
1666 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1667 decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8,
1668 "Segmentation permitted",
1669 "Segmentation not permitted"));
1670 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1671 decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8,
1674 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1675 decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8,
1676 "Report error if PDU discarded",
1677 "Don't report error if PDU discarded"));
1678 proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s",
1679 decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8,
1680 npdu_type_vals, "%s"));
1683 /* If we don't have the full header - i.e., not enough to see the
1684 segmentation part and determine whether this datagram is segmented
1685 or not - set the Info column now; we'll get an exception before
1686 we set it otherwise. */
1688 if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
1689 if (check_col(pinfo->cinfo, COL_INFO))
1690 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1693 segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
1694 cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
1695 cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum);
1697 proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
1699 switch (cksum_status) {
1703 * No checksum present, or not enough of the header present to
1706 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1709 "Checksum : 0x%04x",
1715 * Checksum is correct.
1717 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1720 "Checksum : 0x%04x (correct)",
1726 * Checksum is not correct.
1728 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb,
1731 "Checksum : 0x%04x (incorrect)",
1735 opt_len -= 9; /* Fixed part of Hesder */
1740 offset = P_CLNP_ADDRESS_PART;
1741 dst_len = tvb_get_guint8(tvb, offset);
1742 dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len);
1743 nsel = tvb_get_guint8(tvb, offset + dst_len);
1744 src_len = tvb_get_guint8(tvb, offset + dst_len + 1);
1745 src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len);
1748 proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
1750 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len,
1753 print_nsap_net(dst_addr, dst_len));
1754 proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
1755 offset + 1 + dst_len, 1, src_len);
1756 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb,
1757 offset + dst_len + 2, src_len,
1760 print_nsap_net(src_addr, src_len));
1762 opt_len -= dst_len + src_len +2;
1765 SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr);
1766 SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr);
1767 SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr);
1768 SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr);
1770 /* Segmentation Part */
1772 offset += dst_len + src_len + 2;
1774 if (cnf_type & CNF_SEG_OK) {
1775 struct clnp_segment seg; /* XXX - not used */
1776 tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */
1778 segment_offset = tvb_get_ntohs(tvb, offset + 2);
1779 du_id = tvb_get_ntohs(tvb, offset);
1781 proto_tree_add_text(clnp_tree, tvb, offset, 2,
1782 "Data unit identifier: %06u",
1784 proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2,
1785 "Segment offset : %6u",
1787 proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2,
1788 "Total length : %6u",
1789 tvb_get_ntohs(tvb, offset + 4));
1797 /* To do : decode options */
1799 proto_tree_add_text(clnp_tree, tvb, offset,
1800 cnf_hdr_len - offset,
1801 "Options/Data: <not shown>");
1803 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1805 dissect_osi_options( 0xff,
1807 tvb, offset, clnp_tree );
1810 /* Length of CLNP datagram plus headers above it. */
1811 len = segment_length;
1813 offset = cnf_hdr_len;
1815 /* If clnp_reassemble is on, and this is a segment, we have all the
1816 * data in the segment, and the checksum is valid, then just add the
1817 * segment to the hashtable.
1819 save_fragmented = pinfo->fragmented;
1820 if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
1821 ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
1822 (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
1823 cksum_status != CKSUM_NOT_OK) {
1824 fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
1825 segment_offset, segment_length - cnf_hdr_len,
1826 cnf_type & CNF_MORE_SEGS);
1828 if (fd_head != NULL) {
1830 proto_tree *ft=NULL;
1831 proto_item *fi=NULL;
1833 /* OK, we have the complete reassembled payload.
1834 Allocate a new tvbuff, referring to the reassembled payload. */
1835 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
1838 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
1839 were handed refers, so it'll get cleaned up when that tvbuff
1841 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1843 /* Add the defragmented data to the data source list. */
1844 add_new_data_source(pinfo->fd, next_tvb, "Reassembled CLNP");
1846 /* It's not fragmented. */
1847 pinfo->fragmented = FALSE;
1849 /* show all segments */
1850 fi = proto_tree_add_item(clnp_tree, hf_clnp_segments,
1851 next_tvb, 0, -1, FALSE);
1852 ft = proto_item_add_subtree(fi, ett_clnp_segments);
1853 for (fd = fd_head->next; fd != NULL; fd = fd->next){
1854 if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
1855 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1856 /* this segment has some flags set, create a subtree
1857 * for it and display the flags.
1859 proto_tree *fet = NULL;
1860 proto_item *fei = NULL;
1863 if (fd->flags & (FD_OVERLAPCONFLICT
1864 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1865 hf = hf_clnp_segment_error;
1867 hf = hf_clnp_segment;
1869 fei = proto_tree_add_none_format(ft, hf,
1870 next_tvb, fd->offset, fd->len,
1871 "Frame:%u payload:%u-%u",
1874 fd->offset+fd->len-1
1876 fet = proto_item_add_subtree(fei, ett_clnp_segment);
1877 if (fd->flags&FD_OVERLAP) {
1878 proto_tree_add_boolean(fet,
1879 hf_clnp_segment_overlap, next_tvb, 0, 0,
1882 if (fd->flags&FD_OVERLAPCONFLICT) {
1883 proto_tree_add_boolean(fet,
1884 hf_clnp_segment_overlap_conflict, next_tvb, 0, 0,
1887 if (fd->flags&FD_MULTIPLETAILS) {
1888 proto_tree_add_boolean(fet,
1889 hf_clnp_segment_multiple_tails, next_tvb, 0, 0,
1892 if (fd->flags&FD_TOOLONGFRAGMENT) {
1893 proto_tree_add_boolean(fet,
1894 hf_clnp_segment_too_long_segment, next_tvb, 0, 0,
1898 /* nothing of interest for this segment */
1899 proto_tree_add_none_format(ft, hf_clnp_segment,
1900 next_tvb, fd->offset, fd->len,
1901 "Frame:%u payload:%u-%u",
1904 fd->offset+fd->len-1
1908 if (fd_head->flags & (FD_OVERLAPCONFLICT
1909 |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1910 if (check_col(pinfo->cinfo, COL_INFO)) {
1911 col_set_str(pinfo->cinfo, COL_INFO, "[Illegal segments]");
1912 update_col_info = FALSE;
1916 /* We don't have the complete reassembled payload. */
1920 /* If this is the first segment, dissect its contents, otherwise
1921 just show it as a segment.
1923 XXX - if we eventually don't save the reassembled contents of all
1924 segmented datagrams, we may want to always reassemble. */
1925 if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1926 /* Not the first segment - don't dissect it. */
1929 /* First segment, or not segmented. Dissect what we have here. */
1931 /* Get a tvbuff for the payload. */
1932 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1935 * If this is the first segment, but not the only segment,
1936 * tell the next protocol that.
1938 if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
1939 pinfo->fragmented = TRUE;
1941 pinfo->fragmented = FALSE;
1945 if (next_tvb == NULL) {
1946 /* Just show this as a segment. */
1947 if (check_col(pinfo->cinfo, COL_INFO))
1948 col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1949 pdu_type_string, flag_string, segment_offset);
1951 /* As we haven't reassembled anything, we haven't changed "pi", so
1952 we don't have to restore it. */
1953 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
1954 pinfo->fragmented = save_fragmented;
1958 if (tvb_offset_exists(tvb, offset)) {
1959 switch (cnf_type & CNF_TYPE) {
1963 /* Continue with COTP if any data.
1964 XXX - if this isn't the first Derived PDU of a segmented Initial
1967 if (nsel == (char)tp_nsap_selector || always_decode_transport) {
1968 if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
1969 pinfo->fragmented = save_fragmented;
1970 return; /* yes, it appears to be COTP or CLTP */
1976 /* The payload is the header and "none, some, or all of the data
1977 part of the discarded PDU", i.e. it's like an ICMP error;
1978 dissect it as a CLNP PDU. */
1979 if (check_col(pinfo->cinfo, COL_INFO))
1980 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1982 next_length = tvb_length_remaining(tvb, offset);
1983 if (next_length != 0) {
1984 /* We have payload; dissect it.
1985 Make the columns non-writable, so the packet isn't shown
1986 in the summary based on what the discarded PDU's contents
1988 col_set_writable(pinfo->cinfo, FALSE);
1990 /* Also, save the current values of the addresses, and restore
1991 them when we're finished dissecting the contained packet, so
1992 that the address columns in the summary don't reflect the
1993 contained packet, but reflect this packet instead. */
1994 save_dl_src = pinfo->dl_src;
1995 save_dl_dst = pinfo->dl_dst;
1996 save_net_src = pinfo->net_src;
1997 save_net_dst = pinfo->net_dst;
1998 save_src = pinfo->src;
1999 save_dst = pinfo->dst;
2001 /* Save the current value of the "we're inside an error packet"
2002 flag, and set that flag; subdissectors may treat packets
2003 that are the payload of error packets differently from
2005 save_in_error_pkt = pinfo->in_error_pkt;
2006 pinfo->in_error_pkt = TRUE;
2008 /* Dissect the contained packet.
2009 Catch ReportedBoundsError, and do nothing if we see it,
2010 because it's not an error if the contained packet is short;
2011 there's no guarantee that all of it was included.
2013 XXX - should catch BoundsError, and re-throw it after cleaning
2015 ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length,
2017 discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu);
2019 dissect_clnp(next_tvb, pinfo, discpdu_tree);
2021 CATCH(ReportedBoundsError) {
2026 /* Restore the "we're inside an error packet" flag. */
2027 pinfo->in_error_pkt = save_in_error_pkt;
2029 /* Restore the addresses. */
2030 pinfo->dl_src = save_dl_src;
2031 pinfo->dl_dst = save_dl_dst;
2032 pinfo->net_src = save_net_src;
2033 pinfo->net_dst = save_net_dst;
2034 pinfo->src = save_src;
2035 pinfo->dst = save_dst;
2038 pinfo->fragmented = save_fragmented;
2039 return; /* we're done with this PDU */
2043 /* XXX - dissect this */
2047 if (check_col(pinfo->cinfo, COL_INFO))
2048 col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
2049 call_dissector(data_handle,next_tvb, pinfo, tree);
2050 pinfo->fragmented = save_fragmented;
2051 } /* dissect_clnp */
2054 clnp_reassemble_init(void)
2056 fragment_table_init(&clnp_segment_table);
2059 void proto_register_clnp(void)
2061 static hf_register_info hf[] = {
2063 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
2064 VALS(nlpid_vals), 0x0, "", HFILL }},
2067 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2070 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2073 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2076 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2078 { &hf_clnp_pdu_length,
2079 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2081 { &hf_clnp_checksum,
2082 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2084 { &hf_clnp_dest_length,
2085 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2088 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2090 { &hf_clnp_src_length,
2091 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2094 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
2096 { &hf_clnp_segment_overlap,
2097 { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2098 "Segment overlaps with other segments", HFILL }},
2100 { &hf_clnp_segment_overlap_conflict,
2101 { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2102 "Overlapping segments contained conflicting data", HFILL }},
2104 { &hf_clnp_segment_multiple_tails,
2105 { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2106 "Several tails were found when reassembling the packet", HFILL }},
2108 { &hf_clnp_segment_too_long_segment,
2109 { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2110 "Segment contained data past end of packet", HFILL }},
2112 { &hf_clnp_segment_error,
2113 { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0,
2114 "Reassembly error due to illegal segments", HFILL }},
2117 { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0,
2118 "CLNP Segment", HFILL }},
2120 { &hf_clnp_segments,
2121 { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0,
2122 "CLNP Segments", HFILL }},
2124 static gint *ett[] = {
2132 module_t *clnp_module;
2134 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
2135 proto_register_field_array(proto_clnp, hf, array_length(hf));
2136 proto_register_subtree_array(ett, array_length(ett));
2138 clnp_module = prefs_register_protocol(proto_clnp, NULL);
2139 prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
2140 "NSAP selector for Transport Protocol (last byte in hexa)",
2141 "NSAP selector for Transport Protocol (last byte in hexa)",
2142 16, &tp_nsap_selector);
2143 prefs_register_bool_preference(clnp_module, "always_decode_transport",
2144 "Always try to decode NSDU as transport PDUs",
2145 "Always try to decode NSDU as transport PDUs",
2146 &always_decode_transport);
2147 prefs_register_bool_preference(clnp_module, "reassemble",
2148 "Reassemble segmented CLNP datagrams",
2149 "Whether segmented CLNP datagrams should be reassembled",
2153 void proto_register_cotp(void)
2155 /* static hf_register_info hf[] = {
2157 { "Name", "cotp.abbreviation", TYPE, VALS_POINTER }},
2159 static gint *ett[] = {
2163 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "COTP", "cotp");
2164 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2165 proto_register_subtree_array(ett, array_length(ett));
2167 /* subdissector code */
2168 register_heur_dissector_list("cotp_is", &cotp_is_heur_subdissector_list);
2170 /* XXX - what about CLTP? */
2171 register_dissector("ositp", dissect_ositp, proto_cotp);
2174 void proto_register_cltp(void)
2176 /* static hf_register_info hf[] = {
2178 { "Name", "cltp.abbreviation", TYPE, VALS_POINTER }},
2180 static gint *ett[] = {
2184 proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp");
2185 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
2186 proto_register_subtree_array(ett, array_length(ett));
2187 register_init_routine(clnp_reassemble_init);
2191 proto_reg_handoff_clnp(void)
2193 dissector_handle_t clnp_handle;
2195 data_handle = find_dissector("data");
2197 clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
2198 dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
2199 dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
2200 dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);