1 /* packet-mdshdr.c 2 * Routines for dissection of Cisco MDS Switch Internal Header 3 * Copyright 2001, Dinesh G Dutt <ddutt@andiamo.com> 4 * 5 * Wireshark - Network traffic analyzer 6 * By Gerald Combs <gerald@wireshark.org> 7 * Copyright 1998 Gerald Combs 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 */ 11 12 #include "config.h" 13 14 #include <epan/packet.h> 15 #include <epan/etypes.h> 16 #include <epan/prefs.h> 17 #include "packet-fc.h" 18 19 void proto_register_mdshdr(void); 20 void proto_reg_handoff_mdshdr(void); 21 22 #define MDSHDR_VERSION_OFFSET 0 23 24 /* Mdshdr Control bits */ 25 #define MDSHDR_CTL_IDXDIRECT 1 26 #define MDSHDR_CTL_IGNACLO 2 27 #define MDSHDR_CTL_DRP 4 28 29 /* OFFSETS OF FIELDS */ 30 #define MDSHDR_VER_OFFSET 0 31 #define MDSHDR_SOF_OFFSET 1 32 #define MDSHDR_PKTLEN_OFFSET 2 33 #define MDSHDR_DIDX_OFFSET 5 34 #define MDSHDR_SIDX_OFFSET 6 35 #define MDSHDR_VSAN_OFFSET 13 36 37 /* Two size definitions are sufficient */ 38 #define MDSHDR_SIZE_BYTE sizeof(gchar) 39 #define MDSHDR_SIZE_INT16 sizeof(guint16) 40 #define MDSHDR_SIZE_INT32 sizeof(guint32) 41 42 /* Other miscellaneous defines; can't rely on sizeof structs */ 43 #define MDSHDR_MAX_VERSION 0 44 #define MDSHDR_HEADER_SIZE 16 45 #define MDSHDR_TRAILER_SIZE 6 46 47 /* SOF Encodings */ 48 #define MDSHDR_SOFc1 0x1 49 #define MDSHDR_SOFi1 0x2 50 #define MDSHDR_SOFn1 0x3 51 #define MDSHDR_SOFi2 0x4 52 #define MDSHDR_SOFn2 0x5 53 #define MDSHDR_SOFi3 0x6 54 #define MDSHDR_SOFn3 0x7 55 #define MDSHDR_SOFf 0x8 56 #define MDSHDR_SOFc4 0x9 57 #define MDSHDR_SOFi4 0xa 58 #define MDSHDR_SOFn4 0xb 59 60 /* EOF Encodings */ 61 #define MDSHDR_EOFt 0x1 62 #define MDSHDR_EOFdt 0x2 63 #define MDSHDR_EOFa 0x4 64 #define MDSHDR_EOFn 0x3 65 #define MDSHDR_EOFdti 0x6 66 #define MDSHDR_EOFni 0x7 67 #define MDSHDR_EOFrt 0xa 68 #define MDSHDR_EOFrti 0xe 69 #define MDSHDR_EOF_UNKNOWN 0xb 70 71 /* Initialize the protocol and registered fields */ 72 static int proto_mdshdr = -1; 73 static int hf_mdshdr_sof = -1; 74 static int hf_mdshdr_pkt_len = -1; 75 static int hf_mdshdr_dstidx = -1; 76 static int hf_mdshdr_srcidx = -1; 77 static int hf_mdshdr_vsan = -1; 78 static int hf_mdshdr_eof = -1; 79 static int hf_mdshdr_no_trailer = -1; 80 static int hf_mdshdr_span = -1; 81 static int hf_mdshdr_fccrc = -1; 82 83 /* Initialize the subtree pointers */ 84 static gint ett_mdshdr = -1; 85 static gint ett_mdshdr_hdr = -1; 86 static gint ett_mdshdr_trlr = -1; 87 88 static dissector_handle_t fc_dissector_handle; 89 90 static gboolean decode_if_zero_etype = FALSE; 91 92 static const value_string sof_vals[] = { 93 {MDSHDR_SOFc1, "SOFc1"}, 94 {MDSHDR_SOFi1, "SOFi1"}, 95 {MDSHDR_SOFn1, "SOFn1"}, 96 {MDSHDR_SOFi2, "SOFi2"}, 97 {MDSHDR_SOFn2, "SOFn2"}, 98 {MDSHDR_SOFi3, "SOFi3"}, 99 {MDSHDR_SOFn3, "SOFn3"}, 100 {MDSHDR_SOFc4, "SOFc4"}, 101 {MDSHDR_SOFi4, "SOFi4"}, 102 {MDSHDR_SOFn4, "SOFn4"}, 103 {MDSHDR_SOFf, "SOFf"}, 104 {0, NULL}, 105 }; 106 107 static const value_string eof_vals[] = { 108 {MDSHDR_EOFt, "EOFt"}, 109 {MDSHDR_EOFdt, "EOFdt"}, 110 {MDSHDR_EOFa, "EOFa"}, 111 {MDSHDR_EOFn, "EOFn"}, 112 {MDSHDR_EOFdti, "EOFdti"}, 113 {MDSHDR_EOFni, "EOFni"}, 114 {MDSHDR_EOFrt, "EOFrt"}, 115 {MDSHDR_EOFrti, "EOFrti"}, 116 /*{MDSHDR_EOF_UNKNOWN, ""}, intentionally removed*/ 117 {0, NULL}, 118 }; 119 120 static int 121 dissect_mdshdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) 122 { 123 124 /* Set up structures needed to add the protocol subtree and manage it */ 125 proto_item *ti_main; 126 proto_item *hidden_item; 127 proto_tree *mdshdr_tree_main, *mdshdr_tree_hdr, *mdshdr_tree_trlr; 128 int offset = 0; 129 guint pktlen; 130 tvbuff_t *next_tvb; 131 guint8 sof, eof; 132 int trailer_start = 0; /*0 means "no trailer found"*/ 133 fc_data_t fc_data; 134 135 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MDS Header"); 136 137 col_clear(pinfo->cinfo, COL_INFO); 138 139 sof = tvb_get_guint8(tvb, offset+MDSHDR_SOF_OFFSET) & 0x0F; 140 pktlen = tvb_get_ntohs(tvb, offset+MDSHDR_PKTLEN_OFFSET) & 0x1FFF; 141 142 /* The Mdshdr trailer is at the end of the frame */ 143 if ((tvb_captured_length(tvb) >= (MDSHDR_HEADER_SIZE + pktlen)) 144 /* Avoid header/trailer overlap if something wrong */ 145 && (pktlen >= MDSHDR_TRAILER_SIZE)) { 146 trailer_start = MDSHDR_HEADER_SIZE + pktlen - MDSHDR_TRAILER_SIZE; 147 148 eof = tvb_get_guint8(tvb, trailer_start); 149 tvb_set_reported_length(tvb, MDSHDR_HEADER_SIZE+pktlen); 150 } 151 else { 152 eof = MDSHDR_EOF_UNKNOWN; 153 } 154 155 fc_data.sof_eof = 0; 156 157 if ((sof == MDSHDR_SOFi3) || (sof == MDSHDR_SOFi2) || (sof == MDSHDR_SOFi1) 158 || (sof == MDSHDR_SOFi4)) { 159 fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME; 160 } 161 else if (sof == MDSHDR_SOFf) { 162 fc_data.sof_eof = FC_DATA_SOF_SOFF; 163 } 164 165 if (eof != MDSHDR_EOFn) { 166 fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME; 167 } 168 else if (eof != MDSHDR_EOFt) { 169 fc_data.sof_eof |= FC_DATA_EOF_INVALID; 170 } 171 172 if (tree) { 173 ti_main = proto_tree_add_protocol_format(tree, proto_mdshdr, tvb, 0, 174 MDSHDR_HEADER_SIZE+pktlen, 175 "MDS Header(%s/%s)", 176 val_to_str(sof, sof_vals, "Unknown(%u)"), 177 val_to_str(eof, eof_vals, "Unknown(%u)")); 178 179 mdshdr_tree_main = proto_item_add_subtree(ti_main, ett_mdshdr); 180 181 /* Add Header part as subtree first */ 182 mdshdr_tree_hdr = proto_tree_add_subtree(mdshdr_tree_main, tvb, MDSHDR_VER_OFFSET, 183 MDSHDR_HEADER_SIZE, ett_mdshdr_hdr, NULL, "MDS Header"); 184 185 hidden_item = proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_sof, tvb, MDSHDR_SOF_OFFSET, 186 MDSHDR_SIZE_BYTE, ENC_BIG_ENDIAN); 187 proto_item_set_hidden(hidden_item); 188 proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_pkt_len, tvb, MDSHDR_PKTLEN_OFFSET, 189 MDSHDR_SIZE_INT16, ENC_BIG_ENDIAN); 190 proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_dstidx, tvb, MDSHDR_DIDX_OFFSET, 191 MDSHDR_SIZE_INT16, ENC_BIG_ENDIAN); 192 proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_srcidx, tvb, MDSHDR_SIDX_OFFSET, 193 MDSHDR_SIZE_INT16, ENC_BIG_ENDIAN); 194 proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_vsan, tvb, MDSHDR_VSAN_OFFSET, 195 MDSHDR_SIZE_INT16, ENC_BIG_ENDIAN); 196 hidden_item = proto_tree_add_item(mdshdr_tree_hdr, hf_mdshdr_span, 197 tvb, MDSHDR_VSAN_OFFSET, 198 MDSHDR_SIZE_INT16, ENC_BIG_ENDIAN); 199 proto_item_set_hidden(hidden_item); 200 201 /* Add Mdshdr Trailer part */ 202 if (tvb_reported_length(tvb) >= MDSHDR_HEADER_SIZE + pktlen 203 && 0 != trailer_start) { 204 mdshdr_tree_trlr = proto_tree_add_subtree(mdshdr_tree_main, tvb, trailer_start, 205 MDSHDR_TRAILER_SIZE, 206 ett_mdshdr_trlr, NULL, "MDS Trailer"); 207 208 proto_tree_add_item(mdshdr_tree_trlr, hf_mdshdr_eof, tvb, 209 trailer_start, MDSHDR_SIZE_BYTE, ENC_BIG_ENDIAN); 210 proto_tree_add_item(mdshdr_tree_trlr, hf_mdshdr_fccrc, tvb, 211 trailer_start+2, MDSHDR_SIZE_INT32, ENC_BIG_ENDIAN); 212 } 213 else { 214 proto_tree_add_item(mdshdr_tree_main, hf_mdshdr_no_trailer, tvb, 0, 0, ENC_NA); 215 } 216 } 217 218 if (tvb_reported_length(tvb) >= MDSHDR_HEADER_SIZE + pktlen 219 && 0 != pktlen /*if something wrong*/) { 220 next_tvb = tvb_new_subset_length(tvb, MDSHDR_HEADER_SIZE, pktlen); 221 /* XXX what to do with the rest of this frame? --ArtemTamazov */ 222 } 223 else { 224 next_tvb = tvb_new_subset_remaining(tvb, MDSHDR_HEADER_SIZE); 225 } 226 227 /* Call the Fibre Channel dissector */ 228 if (fc_dissector_handle) { 229 fc_data.ethertype = ETHERTYPE_FCFT; 230 call_dissector_with_data(fc_dissector_handle, next_tvb, pinfo, tree, &fc_data); 231 } 232 else { 233 call_data_dissector(next_tvb, pinfo, tree); 234 } 235 return tvb_captured_length(tvb); 236 } 237 238 239 void 240 proto_register_mdshdr(void) 241 { 242 243 static hf_register_info hf[] = { 244 { &hf_mdshdr_sof, 245 {"SOF", "mdshdr.sof", FT_UINT8, BASE_DEC, VALS(sof_vals), 0x0, NULL, HFILL}}, 246 247 { &hf_mdshdr_pkt_len, 248 {"Packet Len", "mdshdr.plen", FT_UINT16, BASE_DEC, NULL, 0x1FFF, NULL, HFILL}}, 249 250 { &hf_mdshdr_dstidx, 251 {"Dst Index", "mdshdr.dstidx", FT_UINT16, BASE_HEX, NULL, 0xFFC, NULL, HFILL}}, 252 253 { &hf_mdshdr_srcidx, 254 {"Src Index", "mdshdr.srcidx", FT_UINT16, BASE_HEX, NULL, 0x3FF, NULL, HFILL}}, 255 256 { &hf_mdshdr_vsan, 257 {"VSAN", "mdshdr.vsan", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL}}, 258 259 { &hf_mdshdr_eof, 260 {"EOF", "mdshdr.eof", FT_UINT8, BASE_DEC, VALS(eof_vals), 0x0, NULL, HFILL}}, 261 262 { &hf_mdshdr_no_trailer, 263 {"MDS Trailer: Not Found", "mdshdr.no_trailer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}}, 264 265 { &hf_mdshdr_span, 266 {"SPAN Frame", "mdshdr.span", FT_UINT16, BASE_DEC, NULL, 0xF000, NULL, HFILL}}, 267 268 { &hf_mdshdr_fccrc, 269 {"CRC", "mdshdr.crc", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}}, 270 }; 271 272 /* Setup protocol subtree array */ 273 static gint *ett[] = { 274 &ett_mdshdr, 275 &ett_mdshdr_hdr, 276 &ett_mdshdr_trlr 277 }; 278 module_t *mdshdr_module; 279 280 /* Register the protocol name and description */ 281 proto_mdshdr = proto_register_protocol("MDS Header", "MDS Header", "mdshdr"); 282 283 proto_register_field_array(proto_mdshdr, hf, array_length(hf)); 284 proto_register_subtree_array(ett, array_length(ett)); 285 286 mdshdr_module = prefs_register_protocol(proto_mdshdr, proto_reg_handoff_mdshdr); 287 prefs_register_bool_preference(mdshdr_module, "decode_if_etype_zero", 288 "Decode as MDS Header if Ethertype == 0", 289 "A frame is considered for decoding as MDSHDR if either " 290 "ethertype is 0xFCFC or zero. Turn this flag off if you " 291 "don't want ethertype zero to be decoded as MDSHDR. " 292 "This might be useful to avoid problems with test frames.", 293 &decode_if_zero_etype); 294 } 295 296 void 297 proto_reg_handoff_mdshdr(void) 298 { 299 static dissector_handle_t mdshdr_handle; 300 static gboolean registered_for_zero_etype = FALSE; 301 static gboolean mdshdr_prefs_initialized = FALSE; 302 303 if (!mdshdr_prefs_initialized) { 304 /* 305 * This is the first time this has been called (i.e., 306 * Wireshark/TShark is starting up), so create a handle for 307 * the MDS Header dissector, register the dissector for 308 * ethertype ETHERTYPE_FCFT, and fetch the data and Fibre 309 * Channel handles. 310 */ 311 mdshdr_handle = create_dissector_handle(dissect_mdshdr, proto_mdshdr); 312 dissector_add_uint("ethertype", ETHERTYPE_FCFT, mdshdr_handle); 313 fc_dissector_handle = find_dissector_add_dependency("fc", proto_mdshdr); 314 mdshdr_prefs_initialized = TRUE; 315 } 316 317 /* 318 * Only register the dissector for ethertype 0 if the preference 319 * is set to do so. 320 */ 321 if (decode_if_zero_etype) { 322 /* 323 * The preference to register for ethertype ETHERTYPE_UNK (0) 324 * is set; if we're not registered for ethertype ETHERTYPE_UNK, 325 * do so. 326 */ 327 if (!registered_for_zero_etype) { 328 dissector_add_uint("ethertype", ETHERTYPE_UNK, mdshdr_handle); 329 registered_for_zero_etype = TRUE; 330 } 331 } else { 332 /* 333 * The preference to register for ethertype ETHERTYPE_UNK (0) 334 * is not set; if we're registered for ethertype ETHERTYPE_UNK, 335 * undo that registration. 336 */ 337 if (registered_for_zero_etype) { 338 dissector_delete_uint("ethertype", ETHERTYPE_UNK, mdshdr_handle); 339 registered_for_zero_etype = FALSE; 340 } 341 } 342 } 343 344 /* 345 * Editor modelines - https://www.wireshark.org/tools/modelines.html 346 * 347 * Local variables: 348 * c-basic-offset: 4 349 * tab-width: 8 350 * indent-tabs-mode: nil 351 * End: 352 * 353 * vi: set shiftwidth=4 tabstop=8 expandtab: 354 * :indentSize=4:tabSize=8:noTabs=true: 355 */ 356