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