/* packet-clnp.c * Routines for ISO/OSI network and transport protocol packet disassembly * * $Id: packet-clnp.c,v 1.86 2004/06/20 01:05:07 guy Exp $ * Laurent Deniel * Ralf Schneider * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "prefs.h" #include #include "reassemble.h" #include "packet-osi.h" #include "packet-osi-options.h" #include "packet-isis.h" #include "packet-esis.h" #include "nlpid.h" #include "ipproto.h" /* protocols and fields */ static int proto_clnp = -1; static gint ett_clnp = -1; static gint ett_clnp_type = -1; static gint ett_clnp_segments = -1; static gint ett_clnp_segment = -1; static gint ett_clnp_disc_pdu = -1; static int hf_clnp_id = -1; static int hf_clnp_length = -1; static int hf_clnp_version = -1; static int hf_clnp_ttl = -1; static int hf_clnp_type = -1; static int hf_clnp_pdu_length = -1; static int hf_clnp_checksum = -1; static int hf_clnp_dest_length = -1; static int hf_clnp_dest = -1; static int hf_clnp_src_length = -1; static int hf_clnp_src = -1; static int hf_clnp_segments = -1; static int hf_clnp_segment = -1; static int hf_clnp_segment_overlap = -1; static int hf_clnp_segment_overlap_conflict = -1; static int hf_clnp_segment_multiple_tails = -1; static int hf_clnp_segment_too_long_segment = -1; static int hf_clnp_segment_error = -1; static int hf_clnp_reassembled_in = -1; static int proto_cotp = -1; static gint ett_cotp = -1; static gint ett_cotp_segments = -1; static gint ett_cotp_segment = -1; static int hf_cotp_srcref = -1; static int hf_cotp_destref = -1; static int hf_cotp_type = -1; static int hf_cotp_segments = -1; static int hf_cotp_segment = -1; static int hf_cotp_segment_overlap = -1; static int hf_cotp_segment_overlap_conflict = -1; static int hf_cotp_segment_multiple_tails = -1; static int hf_cotp_segment_too_long_segment = -1; static int hf_cotp_segment_error = -1; static int hf_cotp_reassembled_in = -1; static int proto_cltp = -1; static gint ett_cltp = -1; static int hf_cltp_type = -1; static const fragment_items clnp_frag_items = { &ett_clnp_segment, &ett_clnp_segments, &hf_clnp_segments, &hf_clnp_segment, &hf_clnp_segment_overlap, &hf_clnp_segment_overlap_conflict, &hf_clnp_segment_multiple_tails, &hf_clnp_segment_too_long_segment, &hf_clnp_segment_error, &hf_clnp_reassembled_in, "segments" }; static const fragment_items cotp_frag_items = { &ett_cotp_segment, &ett_cotp_segments, &hf_cotp_segments, &hf_cotp_segment, &hf_cotp_segment_overlap, &hf_cotp_segment_overlap_conflict, &hf_cotp_segment_multiple_tails, &hf_cotp_segment_too_long_segment, &hf_cotp_segment_error, &hf_cotp_reassembled_in, "segments" }; static dissector_handle_t clnp_handle; static dissector_handle_t data_handle; /* * ISO 8473 OSI CLNP definition (see RFC994) * * _________________________________ * | Fixed Part | * |_________________________________| * | Address Part | * |_________________________________| * | Segmentation Part (optional) | * |_________________________________| * | Options Part (optional) | * |_________________________________| * | Data (optional) | * |_________________________________| */ #define ISO8473_V1 0x01 /* CLNP version 1 */ /* Fixed part */ #define CNF_TYPE 0x1f #define CNF_ERR_OK 0x20 #define CNF_MORE_SEGS 0x40 #define CNF_SEG_OK 0x80 #define DT_NPDU 0x1C #define MD_NPDU 0x1D #define ER_NPDU 0x01 #define ERQ_NPDU 0x1E #define ERP_NPDU 0x1F static const value_string npdu_type_abbrev_vals[] = { { DT_NPDU, "DT" }, { MD_NPDU, "MD" }, { ER_NPDU, "ER" }, { ERQ_NPDU, "ERQ" }, { ERP_NPDU, "ERP" }, { 0, NULL } }; static const value_string npdu_type_vals[] = { { DT_NPDU, "Data" }, { MD_NPDU, "Multicast Data" }, { ER_NPDU, "Error Report" }, { ERQ_NPDU, "Echo Request" }, { ERP_NPDU, "Echo Response" }, { 0, NULL } }; /* field position */ #define P_CLNP_PROTO_ID 0 #define P_CLNP_HDR_LEN 1 #define P_CLNP_VERS 2 #define P_CLNP_TTL 3 #define P_CLNP_TYPE 4 #define P_CLNP_SEGLEN 5 #define P_CLNP_CKSUM 7 #define P_CLNP_ADDRESS_PART 9 /* Segmentation part */ struct clnp_segment { gushort cng_id; /* data unit identifier */ gushort cng_off; /* segment offset */ gushort cng_tot_len; /* total length */ }; /* NSAP selector */ #define NSEL_NET 0x00 #define NSEL_NP 0x20 #define NSEL_TP 0x21 /* * ISO8073 OSI COTP definition (see RFC905) */ /* don't use specific TPDU types to avoid alignment problems & copy overhead */ /* TPDU definition */ #define ED_TPDU 0x1 /* COTP */ #define EA_TPDU 0x2 /* COTP */ #define UD_TPDU 0x4 /* CLTP */ #define RJ_TPDU 0x5 /* COTP */ #define AK_TPDU 0x6 /* COTP */ #define ER_TPDU 0x7 /* COTP */ #define DR_TPDU 0x8 /* COTP */ #define DC_TPDU 0xC /* COTP */ #define CC_TPDU 0xD /* COTP */ #define CR_TPDU 0xE /* COTP */ #define DT_TPDU 0xF /* COTP */ static const value_string cotp_tpdu_type_abbrev_vals[] = { { ED_TPDU, "ED" }, { EA_TPDU, "EA" }, { RJ_TPDU, "RJ" }, { AK_TPDU, "AK" }, { ER_TPDU, "ER" }, { DR_TPDU, "DR" }, { DC_TPDU, "DC" }, { CC_TPDU, "CC" }, { CR_TPDU, "CR" }, { DT_TPDU, "DT" }, { 0, NULL } }; static const value_string cltp_tpdu_type_abbrev_vals[] = { { UD_TPDU, "UD" }, { 0, NULL } }; /* field position */ #define P_LI 0 #define P_TPDU 1 #define P_CDT 1 #define P_DST_REF 2 #define P_SRC_REF 4 #define P_TPDU_NR_0_1 2 #define P_TPDU_NR_234 4 #define P_VAR_PART_NDT 5 #define P_VAR_PART_EDT 8 #define P_VAR_PART_DC 6 #define P_CDT_IN_AK 8 #define P_CDT_IN_RJ 8 #define P_REJECT_ER 4 #define P_REASON_IN_DR 6 #define P_CLASS_OPTION 6 /* TPDU length indicator */ #define LI_NORMAL_DT_CLASS_01 2 #define LI_NORMAL_DT_WITH_CHECKSUM 8 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4 #define LI_EXTENDED_DT_WITH_CHECKSUM 11 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7 #define LI_NORMAL_EA_WITH_CHECKSUM 8 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4 #define LI_EXTENDED_EA_WITH_CHECKSUM 11 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7 #define LI_NORMAL_RJ 4 #define LI_EXTENDED_RJ 9 #define LI_MIN_DR 6 #define LI_MAX_DC 9 #define LI_MAX_AK 27 #define LI_MAX_EA 11 #define LI_MAX_ER 8 /* XXX - can we always decide this based on whether the length indicator is odd or not? What if the variable part has an odd number of octets? */ #define is_LI_NORMAL_AK(p) ( ( p & 0x01 ) == 0 ) /* variant part */ #define VP_ACK_TIME 0x85 #define VP_RES_ERROR 0x86 #define VP_PRIORITY 0x87 #define VP_TRANSIT_DEL 0x88 #define VP_THROUGHPUT 0x89 #define VP_SEQ_NR 0x8A /* in AK */ #define VP_REASSIGNMENT 0x8B #define VP_FLOW_CNTL 0x8C /* in AK */ #define VP_TPDU_SIZE 0xC0 #define VP_SRC_TSAP 0xC1 /* in CR/CC */ #define VP_DST_TSAP 0xC2 #define VP_CHECKSUM 0xC3 #define VP_VERSION_NR 0xC4 #define VP_PROTECTION 0xC5 #define VP_OPT_SEL 0xC6 #define VP_PROTO_CLASS 0xC7 #define VP_PREF_MAX_TPDU_SIZE 0xF0 #define VP_INACTIVITY_TIMER 0xF2 static const value_string tp_vpart_type_vals[] = { { VP_ACK_TIME, "ack time" }, { VP_RES_ERROR, "res error" }, { VP_PRIORITY, "priority" }, { VP_TRANSIT_DEL, "transit delay" }, { VP_THROUGHPUT, "throughput" }, { VP_SEQ_NR, "seq number" }, { VP_REASSIGNMENT, "reassignment" }, { VP_FLOW_CNTL, "flow control" }, { VP_TPDU_SIZE, "tpdu-size" }, { VP_SRC_TSAP, "src-tsap" }, { VP_DST_TSAP, "dst-tsap" }, { VP_CHECKSUM, "checksum" }, { VP_VERSION_NR, "version" }, { VP_PROTECTION, "protection" }, { VP_OPT_SEL, "options" }, { VP_PROTO_CLASS, "proto class" }, { VP_PREF_MAX_TPDU_SIZE, "preferred max TPDU size" }, { 0, NULL } }; static int hf_cotp_vp_src_tsap = -1; static int hf_cotp_vp_dst_tsap = -1; static int hf_cotp_vp_src_tsap_bytes = -1; static int hf_cotp_vp_dst_tsap_bytes = -1; /* misc */ #define EXTRACT_SHORT(p) pntohs(p) #define EXTRACT_LONG(p) pntohl(p) /* global variables */ /* List of dissectors to call for COTP packets put atop the Inactive Subset of CLNP. */ static heur_dissector_list_t cotp_is_heur_subdissector_list; /* List of dissectors to call for COTP packets put atop CLNP */ static heur_dissector_list_t cotp_heur_subdissector_list; /* List of dissectors to call for CLNP packets */ static heur_dissector_list_t clnp_heur_subdissector_list; /* * Reassembly of CLNP. */ static GHashTable *clnp_segment_table = NULL; static GHashTable *clnp_reassembled_table = NULL; /* * Reassembly of COTP. */ static GHashTable *cotp_segment_table = NULL; static GHashTable *cotp_reassembled_table = NULL; #define TSAP_DISPLAY_AUTO 0 #define TSAP_DISPLAY_STRING 1 #define TSAP_DISPLAY_BYTES 2 /* options */ static guint tp_nsap_selector = NSEL_TP; static gboolean always_decode_transport = FALSE; static gboolean clnp_reassemble = FALSE; static gboolean cotp_reassemble = FALSE; static gint32 tsap_display = TSAP_DISPLAY_AUTO; const enum_val_t tsap_display_options[] = { {"auto", "As strings if printable", TSAP_DISPLAY_AUTO}, {"string", "As strings", TSAP_DISPLAY_STRING}, {"bytes", "As bytes", TSAP_DISPLAY_BYTES}, {NULL, NULL, -1} }; /* function definitions */ #define MAX_TSAP_LEN 32 static gboolean is_all_printable(const guchar *stringtocheck, int length) { gboolean allprintable; int i; allprintable=TRUE; for (i=0;i MAX_TSAP_LEN) sprintf(cur, ""); else { allprintable = is_all_printable(tsap,length); if (!allprintable) strcat(cur,"0x"); while (length != 0) { if (allprintable) sprintf(tmp, "%c", *tsap ++); else sprintf(tmp, "%02x", *tsap ++); strcat(cur, tmp); length --; } } return cur; } /* print_tsap */ static gboolean ositp_decode_var_part(tvbuff_t *tvb, int offset, int vp_length, int class_option, proto_tree *tree) { guint8 code, length; guint8 c1; guint16 s, s1,s2,s3,s4; guint32 t1, t2, t3, t4; guint32 pref_max_tpdu_size; while (vp_length != 0) { code = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "Parameter code: 0x%02x (%s)", code, val_to_str(code, tp_vpart_type_vals, "Unknown")); offset += 1; vp_length -= 1; if (vp_length == 0) break; length = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "Parameter length: %u", length); offset += 1; vp_length -= 1; switch (code) { case VP_ACK_TIME: s = tvb_get_ntohs(tvb, offset); proto_tree_add_text(tree, tvb, offset, length, "Ack time (ms): %u", s); offset += length; vp_length -= length; break; case VP_RES_ERROR: proto_tree_add_text(tree, tvb, offset, 1, "Residual error rate, target value: 10^%u", tvb_get_guint8(tvb, offset)); offset += 1; length -= 1; vp_length -= 1; proto_tree_add_text(tree, tvb, offset, 1, "Residual error rate, minimum acceptable: 10^%u", tvb_get_guint8(tvb, offset)); offset += 1; length -= 1; vp_length -= 1; proto_tree_add_text(tree, tvb, offset, 1, "Residual error rate, TSDU size of interest: %u", 1<