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