3 * Routines for FCoE dissection - Fibre Channel over Ethernet
4 * Copyright (c) 2006 Nuova Systems, Inc. (jre@nuovasystems.com)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Based on packet-fcip.c, Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
12 * SPDX-License-Identifier: GPL-2.0-or-later
16 * For FCoE protocol details, see http://fcoe.com.
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
23 #include <epan/crc32-tvb.h>
24 #include <epan/expert.h>
25 #include "packet-fc.h"
27 void proto_register_fcoe(void);
28 void proto_reg_handoff_fcoe(void);
30 #define FCOE_HEADER_LEN 14 /* header: version, SOF, and padding */
31 #define FCOE_TRAILER_LEN 8 /* trailer: CRC, EOF, and padding */
55 static const value_string fcoe_eof_vals
[] = {
58 {FCOE_EOFrt
, "EOFrt" },
59 {FCOE_EOFdt
, "EOFdt" },
60 {FCOE_EOFni
, "EOFni" },
61 {FCOE_EOFdti
, "EOFdti" },
62 {FCOE_EOFrti
, "EOFrti" },
67 static const value_string fcoe_sof_vals
[] = {
69 {FCOE_SOFi4
, "SOFi4" },
70 {FCOE_SOFi2
, "SOFi2" },
71 {FCOE_SOFi3
, "SOFi3" },
72 {FCOE_SOFn4
, "SOFn4" },
73 {FCOE_SOFn2
, "SOFn2" },
74 {FCOE_SOFn3
, "SOFn3" },
75 {FCOE_SOFc4
, "SOFc4" },
79 static int proto_fcoe
;
80 static int hf_fcoe_ver
;
81 static int hf_fcoe_len
;
82 static int hf_fcoe_sof
;
83 static int hf_fcoe_eof
;
84 static int hf_fcoe_crc
;
85 static int hf_fcoe_crc_status
;
89 static expert_field ei_fcoe_crc
;
91 static dissector_handle_t fc_handle
;
92 static dissector_handle_t fcoe_handle
;
95 /* Looks for the EOF at a given offset. Returns NULL if the EOF is not
96 * present, is not one of the known values, or if the next three bytes, if
97 * present, are not padding. Otherwise returns the entry from the EOF
98 * value_string. Intended for use with the newer T11 version, where the frame
99 * length is not explicitly set (and padding is used). */
101 fcoe_get_eof(tvbuff_t
*tvb
, int eof_offset
)
105 int padding_remaining
;
107 if (!tvb_bytes_exist(tvb
, eof_offset
, 1)) {
111 padding_remaining
= MIN(tvb_captured_length_remaining(tvb
, eof_offset
+1),3);
112 if (tvb_memeql(tvb
, eof_offset
+1, (const uint8_t*)"\x00\x00\x00", padding_remaining
)) {
116 eof
= tvb_get_uint8(tvb
, eof_offset
);
117 eof_str
= try_val_to_str(eof
, fcoe_eof_vals
);
122 dissect_fcoe(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
127 int header_len
= FCOE_HEADER_LEN
;
138 proto_tree
*fcoe_tree
;
141 uint32_t crc_computed
= 0;
146 * For now, handle both the version defined before and after August 2007.
147 * In the newer version, byte 1 is reserved and always zero. In the old
148 * version, it'll never be zero.
150 if (tvb_get_uint8(tvb
, 1)) {
152 len_sof
= tvb_get_ntohs(tvb
, 0);
153 frame_len
= ((len_sof
& 0x3ff0) >> 2) - 4;
155 sof
|= (sof
< 8) ? 0x30 : 0x20;
156 version
= len_sof
>> 14;
159 ver
= wmem_strdup_printf(pinfo
->pool
, ver
, "pre-T11 ver %d ", version
);
160 eof_offset
= header_len
+ frame_len
+ 4;
162 if (tvb_bytes_exist(tvb
, eof_offset
, 1)) {
163 eof
= tvb_get_uint8(tvb
, eof_offset
);
164 eof_str
= val_to_str(eof
, fcoe_eof_vals
, "0x%x");
166 /* Old format has a length field, so we can help the Ethernet dissector
167 * guess about the FCS; note this format does not pad after the EOF */
168 set_actual_length(tvb
, eof_offset
+1);
170 frame_len
= tvb_reported_length_remaining(tvb
, 0) -
171 FCOE_HEADER_LEN
- FCOE_TRAILER_LEN
;
172 sof
= tvb_get_uint8(tvb
, FCOE_HEADER_LEN
- 1);
175 * Only version 0 is defined at this point.
176 * Don't print the version in the short summary if it is zero.
179 version
= tvb_get_uint8(tvb
, 0) >> 4;
181 ver
= wmem_strdup_printf(pinfo
->pool
, ver
, "ver %d ", version
);
183 eof_offset
= header_len
+ frame_len
+ 4;
184 if (NULL
== (eof_str
= fcoe_get_eof(tvb
, eof_offset
))) {
185 /* We didn't find the EOF, look 4 bytes earlier */
186 if (NULL
!= (eof_str
= fcoe_get_eof(tvb
, eof_offset
-4))) {
187 /* Found it, so it seems there's an Ethernet FCS. */
189 set_actual_length(tvb
, eof_offset
);
192 if (tvb_bytes_exist(tvb
, eof_offset
, 1)) {
193 /* Hmm, we have enough bytes to look for the EOF
194 * but it's an unexpected value. */
195 eof
= tvb_get_uint8(tvb
, eof_offset
);
196 eof_str
= wmem_strdup_printf(pinfo
->pool
, "0x%x", eof
);
198 /* We just didn't capture enough to get the EOF */
205 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FCoE");
206 crc_offset
= header_len
+ frame_len
;
208 bytes_remaining
= tvb_captured_length_remaining(tvb
, header_len
);
209 if (bytes_remaining
> frame_len
)
210 bytes_remaining
= frame_len
; /* backing length */
211 next_tvb
= tvb_new_subset_length_caplen(tvb
, header_len
, bytes_remaining
, frame_len
);
217 crc_exists
= tvb_bytes_exist(tvb
, crc_offset
, 4);
219 crc
= tvb_get_ntohl(tvb
, crc_offset
);
220 crc_computed
= crc32_802_tvb(next_tvb
, frame_len
);
221 if (crc
!= crc_computed
) {
222 crc_msg
= " [bad FC CRC]";
226 if ((frame_len
% 4) != 0 || frame_len
< 24) {
227 len_msg
= " [invalid length]";
230 ti
= proto_tree_add_protocol_format(tree
, proto_fcoe
, tvb
, 0,
232 "FCoE %s(%s/%s) %d bytes%s%s", ver
,
233 val_to_str(sof
, fcoe_sof_vals
,
235 eof_str
, frame_len
, crc_msg
,
238 /* Dissect the FCoE header */
240 fcoe_tree
= proto_item_add_subtree(ti
, ett_fcoe
);
241 proto_tree_add_uint(fcoe_tree
, hf_fcoe_ver
, tvb
, 0, 1, version
);
242 if (tvb_get_uint8(tvb
, 1)) {
243 proto_tree_add_uint(fcoe_tree
, hf_fcoe_len
, tvb
, 0, 2, frame_len
);
245 proto_tree_add_uint(fcoe_tree
, hf_fcoe_sof
, tvb
,
246 header_len
- 1, 1, sof
);
249 * Create the CRC information.
252 proto_tree_add_checksum(fcoe_tree
, tvb
, crc_offset
, hf_fcoe_crc
, hf_fcoe_crc_status
, &ei_fcoe_crc
, pinfo
, crc_computed
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
253 proto_tree_set_appendix(fcoe_tree
, tvb
, crc_offset
,
254 tvb_captured_length_remaining (tvb
, crc_offset
));
256 proto_tree_add_checksum(fcoe_tree
, tvb
, crc_offset
, hf_fcoe_crc
, hf_fcoe_crc_status
, &ei_fcoe_crc
, pinfo
, 0, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_NOT_PRESENT
);
262 if (tvb_bytes_exist(tvb
, eof_offset
, 1)) {
263 proto_tree_add_item(fcoe_tree
, hf_fcoe_eof
, tvb
, eof_offset
, 1, ENC_BIG_ENDIAN
);
266 /* Set the SOF/EOF flags in the packet_info header */
268 if (sof
== FCOE_SOFi3
|| sof
== FCOE_SOFi2
|| sof
== FCOE_SOFi4
) {
269 fc_data
.sof_eof
= FC_DATA_SOF_FIRST_FRAME
;
270 } else if (sof
== FCOE_SOFf
) {
271 fc_data
.sof_eof
= FC_DATA_SOF_SOFF
;
274 if (eof
!= FCOE_EOFn
) {
275 fc_data
.sof_eof
|= FC_DATA_EOF_LAST_FRAME
;
276 } else if (eof
!= FCOE_EOFt
) {
277 fc_data
.sof_eof
|= FC_DATA_EOF_INVALID
;
280 /* Call the FC Dissector if this is carrying an FC frame */
281 fc_data
.ethertype
= ETHERTYPE_UNK
;
284 call_dissector_with_data(fc_handle
, next_tvb
, pinfo
, tree
, &fc_data
);
286 call_data_dissector(next_tvb
, pinfo
, tree
);
288 return tvb_captured_length(tvb
);
292 proto_register_fcoe(void)
294 module_t
*fcoe_module
;
296 /* Setup list of header fields See Section 1.6.1 for details*/
297 static hf_register_info hf
[] = {
299 {"SOF", "fcoe.sof", FT_UINT8
, BASE_HEX
, VALS(fcoe_sof_vals
), 0,
302 {"EOF", "fcoe.eof", FT_UINT8
, BASE_HEX
, VALS(fcoe_eof_vals
), 0,
305 {"Version", "fcoe.ver", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
307 {"Frame length", "fcoe.len", FT_UINT32
,
308 BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
310 {"CRC", "fcoe.crc", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
311 { &hf_fcoe_crc_status
,
312 {"CRC Status", "fcoe.crc.status", FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0x0,
315 static int *ett
[] = {
319 static ei_register_info ei
[] = {
320 { &ei_fcoe_crc
, { "fcoe.crc.bad", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
323 expert_module_t
* expert_fcoe
;
325 /* Register the protocol name and description */
326 proto_fcoe
= proto_register_protocol("Fibre Channel over Ethernet",
328 fcoe_handle
= register_dissector("fcoe", dissect_fcoe
, proto_fcoe
);
330 /* Required function calls to register the header fields and
332 proto_register_field_array(proto_fcoe
, hf
, array_length(hf
));
333 proto_register_subtree_array(ett
, array_length(ett
));
334 expert_fcoe
= expert_register_protocol(proto_fcoe
);
335 expert_register_field_array(expert_fcoe
, ei
, array_length(ei
));
337 fcoe_module
= prefs_register_protocol_obsolete(proto_fcoe
);
339 prefs_register_obsolete_preference(fcoe_module
, "ethertype");
343 proto_reg_handoff_fcoe(void)
345 dissector_add_uint("ethertype", ETHERTYPE_FCOE
, fcoe_handle
);
346 fc_handle
= find_dissector_add_dependency("fc", proto_fcoe
);
350 * Editor modelines - https://www.wireshark.org/tools/modelines.html
355 * indent-tabs-mode: nil
358 * vi: set shiftwidth=4 tabstop=8 expandtab:
359 * :indentSize=4:tabSize=8:noTabs=true: