/* packet-ositp.c * Routines for ISO/OSI transport protocol packet disassembly * * $Id$ * Laurent Deniel * Ralf Schneider * * Wireshark - 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 #include #include #include "packet-frame.h" #include "packet-osi.h" #include "packet-osi-options.h" #include "packet-isis.h" #include "packet-esis.h" #include #include #include #include /* protocols and fields */ static int proto_clnp; 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_li = -1; static int hf_cotp_type = -1; static int hf_cotp_srcref = -1; static int hf_cotp_destref = -1; static int hf_cotp_class = -1; static int hf_cotp_opts_extended_formats = -1; static int hf_cotp_opts_no_explicit_flow_control = -1; static int hf_cotp_tpdu_number = -1; static int hf_cotp_tpdu_number_extended = -1; static int hf_cotp_next_tpdu_number = -1; static int hf_cotp_next_tpdu_number_extended = -1; static int hf_cotp_eot = -1; static int hf_cotp_eot_extended = -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 hf_cotp_reassembled_length = -1; static const true_false_string fragment_descriptions = { "Yes", "No" }; static int proto_cltp = -1; static gint ett_cltp = -1; static int hf_cltp_li = -1; static int hf_cltp_type = -1; 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, &hf_cotp_reassembled_length, "segments" }; static dissector_handle_t data_handle; /* * ISO8073 OSI COTP definition * See http://standards.iso.org/ittf/PubliclyAvailableStandards/index.html * (or RFC905 for historic, and now-outdated information) */ /* 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 Expedited Data" }, { EA_TPDU, "EA Expedited Data Acknowledgement" }, { RJ_TPDU, "RJ Reject" }, { AK_TPDU, "AK Data Acknowledgement" }, { ER_TPDU, "ER TPDU Error" }, { DR_TPDU, "DR Disconnect Request" }, { DC_TPDU, "DC Disconnect Confirm" }, { CC_TPDU, "CC Connect Confirm" }, { CR_TPDU, "CR Connect Request" }, { DT_TPDU, "DT Data" }, { 0, NULL } }; static const value_string cltp_tpdu_type_abbrev_vals[] = { { UD_TPDU, "UD" }, { 0, NULL } }; static const value_string class_option_vals[] = { {0, "Class 0"}, {1, "Class 1"}, {2, "Class 2"}, {3, "Class 3"}, {4, "Class 4"}, {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; /* 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 CLTP packets put atop CLNP */ static heur_dissector_list_t cltp_heur_subdissector_list; /* * Reassembly of COTP. */ static GHashTable *cotp_segment_table = NULL; static GHashTable *cotp_reassembled_table = NULL; static guint16 cotp_dst_ref = 0; static gboolean cotp_frame_reset = FALSE; static gboolean cotp_last_fragment = FALSE; #define TSAP_DISPLAY_AUTO 0 #define TSAP_DISPLAY_STRING 1 #define TSAP_DISPLAY_BYTES 2 /* options */ static gboolean cotp_reassemble = TRUE; 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 void cotp_frame_end(void) { if (!cotp_last_fragment) { /* Last COTP in frame is not fragmented. * No need for incrementing the dst_ref, so we decrement it here. */ cotp_dst_ref--; } cotp_frame_reset = TRUE; } static gboolean is_all_printable(const guchar *stringtocheck, int length) { gboolean allprintable; int i; allprintable=TRUE; for (i=0;i MAX_TSAP_LEN) g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, ""); else { allprintable = is_all_printable(tsap,length); if (!allprintable) { returned_length = g_snprintf(cur, MAX_TSAP_LEN * 2 + 3, "0x"); idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - 1); } while (length != 0) { if (allprintable) { returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%c", *tsap ++); idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1 ); } else { returned_length = g_snprintf(&cur[idx], MAX_TSAP_LEN * 2 + 3 - idx, "%02x", *tsap ++); idx += MIN(returned_length, MAX_TSAP_LEN * 2 + 3 - idx - 1); } 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; proto_item *hidden_item; 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<