2 * Routines for FCIP dissection
4 * Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/to_str.h>
18 #include "packet-fc.h"
20 void proto_register_fcip(void);
21 void proto_reg_handoff_fcip(void);
23 #define FCIP_ENCAP_HEADER_LEN 28
24 #define FCIP_MIN_HEADER_LEN 16 /* up to frame len field */
25 #define FCIP_IS_SF(pflags) ((pflags & 0x1) == 0x1)
26 #define FCIP_IS_CH(pflags) ((pflags & 0x80) == 0x80)
51 FCENCAP_PROTO_FCIP
= 1,
52 FCENCAP_PROTO_iFCP
= 2
55 static const value_string fcip_eof_vals
[] = {
58 {FCIP_EOFrt
, "EOFrt" },
59 {FCIP_EOFdt
, "EOFdt" },
60 {FCIP_EOFni
, "EOFni" },
61 {FCIP_EOFdti
, "EOFdti" },
62 {FCIP_EOFrti
, "EOFrti" },
67 static const value_string fcip_sof_vals
[] = {
69 {FCIP_SOFi4
, "SOFi4" },
70 {FCIP_SOFi2
, "SOFi2" },
71 {FCIP_SOFi3
, "SOFi3" },
72 {FCIP_SOFn4
, "SOFn4" },
73 {FCIP_SOFn2
, "SOFn2" },
74 {FCIP_SOFn3
, "SOFn3" },
75 {FCIP_SOFc4
, "SOFc4" },
79 static const value_string fcencap_proto_vals
[] = {
80 {FCENCAP_PROTO_FCIP
, "FCIP" },
81 {FCENCAP_PROTO_iFCP
, "iFCP" },
85 static const uint8_t fcip_header_8_bytes
[8] = {
86 0x01, 0x01, 0xFE, 0xFE,
87 0x01, 0x01, 0xFE, 0xFE
90 static int proto_fcip
;
92 static int hf_fcip_protocol
;
93 static int hf_fcip_protocol_c
;
94 static int hf_fcip_version
;
95 static int hf_fcip_version_c
;
96 static int hf_fcip_encap_word1
;
97 static int hf_fcip_flags
;
98 static int hf_fcip_flags_c
;
99 static int hf_fcip_framelen
;
100 static int hf_fcip_framelen_c
;
101 static int hf_fcip_tsec
;
102 static int hf_fcip_tusec
;
103 static int hf_fcip_encap_crc
;
104 static int hf_fcip_sof
;
105 static int hf_fcip_sof_c
;
106 static int hf_fcip_eof
;
107 static int hf_fcip_eof_c
;
108 static int hf_fcip_pflags_changed
;
109 static int hf_fcip_pflags_special
;
110 static int hf_fcip_pflags_c
;
111 static int hf_fcip_src_wwn
;
112 static int hf_fcip_dst_wwn
;
113 static int hf_fcip_conn_code
;
114 static int hf_fcip_katov
;
115 static int hf_fcip_src_entity_id
;
116 static int hf_fcip_conn_nonce
;
117 static int hf_fcip_conn_flags
;
121 static unsigned fcip_port
= 3225;
122 static bool fcip_desegment
= true;
124 static dissector_handle_t fc_handle
;
125 static dissector_handle_t fcip_handle
;
128 /* This routine attempts to locate the position of the next header in the
132 get_next_fcip_header_offset (tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
)
134 int bytes_remaining
= tvb_reported_length_remaining (tvb
, offset
);
136 uint16_t flen
, flen1
;
137 fcip_eof_t eof
, eofc
;
140 * As per the FCIP standard, the following tests must PASS:
141 * 1) Frame Length field validation -- 15 < Frame Length < 545;
142 * 2) Comparison of Frame Length field to its ones complement; and
143 * 3) A valid EOF is found in the word preceding the start of the next
144 * FCIP header as indicated by the Frame Length field, to be tested
146 * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
147 * list of legal EOF values is in the FC Frame Encapsulation
149 * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
150 * value found in bits 24-31.
152 * As per the FCIP standard, in addition, at least 3 of the following set
153 * of tests must be performed to identify that we've located the start of
155 * a) Protocol# ones complement field (1 test);
156 * b) Version ones complement field (1 test);
157 * c) Replication of encapsulation word 0 in word 1 (1 test);
158 * d) Reserved field and its ones complement (2 tests);
159 * e) Flags field and its ones complement (2 tests);
160 * f) CRC field is equal to zero (1 test); (DON'T DO THIS TEST!)
161 * g) SOF fields and ones complement fields (4 tests);
162 * h) Format and values of FC header (1 test);
163 * i) CRC of FC Frame (2 tests);
164 * j) FC Frame Encapsulation header information in the next FCIP Frame
167 * At least 3 of the 16 tests listed above SHALL be performed. Failure
168 * of any of the above tests actually performed SHALL indicate an
169 * encapsulation error and the FC Frame SHALL NOT be forwarded on to
173 NXT_BYTE
: while (bytes_remaining
) {
174 if (bytes_remaining
< FCIP_ENCAP_HEADER_LEN
) {
175 if(fcip_desegment
&& pinfo
->can_desegment
) {
177 * This frame doesn't have all of the data for
178 * the message header, but we can do reassembly on it.
180 * Tell the TCP dissector where the data for this
181 * message starts in the data it handed us, and that we need
182 * "some more data." Don't tell it exactly how many bytes
183 * we need because if/when we ask for even more (after the
184 * header) that will break reassembly.
186 pinfo
->desegment_offset
= offset
;
187 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
192 /* I check that we have a valid header before checking for the frame
193 * length and the other initial tests.
199 if (tvb_memeql(tvb
, offset
, fcip_header_8_bytes
, 8) != 0) {
205 flen
= (tvb_get_ntohs (tvb
, offset
+12)) & 0x03FF;
206 frame_len
= (tvb_get_ntohs (tvb
, offset
+12) & 0x03FF)*4;
208 if ((flen
< 15) || (flen
> 545)) {
209 /* Frame length check failed. Skip byte and try again */
215 flen1
= (tvb_get_ntohs (tvb
, offset
+14)) & 0x03FF;
217 if ((flen
& 0x03FF) != ((~flen1
)&0x03FF)) {
218 /* frame_len and its one's complement are not the same */
224 /* Valid EOF check */
225 if (tvb_bytes_exist (tvb
, offset
+(frame_len
-1)*4, 4)) {
226 eof
= (fcip_eof_t
)tvb_get_uint8 (tvb
, offset
+(frame_len
-1)*4);
227 eofc
= (fcip_eof_t
)tvb_get_uint8 (tvb
, offset
+(frame_len
-1)*4+2);
229 if ((eof
!= FCIP_EOFn
) && (eof
!= FCIP_EOFt
) && (eof
!= FCIP_EOFrt
)
230 && (eof
!= FCIP_EOFdt
) && (eof
!= FCIP_EOFni
) &&
231 (eof
!= FCIP_EOFdti
) && (eof
!= FCIP_EOFrti
) &&
232 (eof
!= FCIP_EOFa
)) {
238 if ((eof
!= ~eofc
) ||
239 (eof
!= tvb_get_uint8 (tvb
, offset
+(frame_len
-1)*4+1)) ||
240 (eofc
!= tvb_get_uint8 (tvb
, offset
+(frame_len
-1)*4+3))) {
248 if ((tvb_get_uint8 (tvb
, offset
+9) != 0) ||
249 (tvb_get_uint8 (tvb
, offset
+11) != 0xFF)) {
260 * We don't test this since some implementations actually provide
264 if (bytes_remaining
>= (frame_len
)) {
265 if (tvb_bytes_exist (tvb
, offset
+frame_len
, 8)) {
266 /* The start of the next header matches what we wish to see */
267 if (tvb_memeql (tvb
, offset
+frame_len
, fcip_header_8_bytes
,
282 if(fcip_desegment
&& pinfo
->can_desegment
) {
284 * This frame doesn't have all of the data for
285 * this message, but we can do reassembly on it.
287 * Tell the TCP dissector where the data for this
288 * message starts in the data it handed us, and
289 * how many more bytes we need, and return.
291 pinfo
->desegment_offset
= offset
;
292 pinfo
->desegment_len
= frame_len
- bytes_remaining
;
301 return (-1); /* Unable to find FCIP header */
305 dissect_fcencap_header (tvbuff_t
*tvb
, proto_tree
*tree
, int offset
)
307 uint8_t protocol
= tvb_get_uint8 (tvb
, offset
);
310 proto_tree_add_uint (tree
, hf_fcip_protocol
, tvb
, offset
, 1, protocol
);
311 proto_tree_add_item (tree
, hf_fcip_version
, tvb
, offset
+1, 1, ENC_BIG_ENDIAN
);
312 proto_tree_add_item (tree
, hf_fcip_protocol_c
, tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
313 proto_tree_add_item (tree
, hf_fcip_version_c
, tvb
, offset
+3, 1, ENC_BIG_ENDIAN
);
315 if (protocol
== FCENCAP_PROTO_FCIP
) {
316 proto_tree_add_item (tree
, hf_fcip_encap_word1
, tvb
, offset
+4,
318 proto_tree_add_item (tree
, hf_fcip_pflags_changed
, tvb
, offset
+8,
320 proto_tree_add_item (tree
, hf_fcip_pflags_special
, tvb
, offset
+8,
322 proto_tree_add_item (tree
, hf_fcip_pflags_c
, tvb
, offset
+10, 1, ENC_BIG_ENDIAN
);
325 /* XXX - break out CRCV flag. */
326 proto_tree_add_item (tree
, hf_fcip_flags
, tvb
, offset
+12, 1, ENC_BIG_ENDIAN
);
327 proto_tree_add_item (tree
, hf_fcip_framelen
, tvb
, offset
+12, 2, ENC_BIG_ENDIAN
);
328 proto_tree_add_item (tree
, hf_fcip_flags_c
, tvb
, offset
+14, 1, ENC_BIG_ENDIAN
);
329 proto_tree_add_item (tree
, hf_fcip_framelen_c
, tvb
, offset
+14, 2, ENC_BIG_ENDIAN
);
330 proto_tree_add_item (tree
, hf_fcip_tsec
, tvb
, offset
+16, 4, ENC_BIG_ENDIAN
);
331 proto_tree_add_item (tree
, hf_fcip_tusec
, tvb
, offset
+20, 4, ENC_BIG_ENDIAN
);
332 /* XXX - check CRC if CRCV is set? */
333 proto_tree_add_item (tree
, hf_fcip_encap_crc
, tvb
, offset
+24, 4, ENC_BIG_ENDIAN
);
338 dissect_fcip_sf (tvbuff_t
*tvb
, proto_tree
*tree
, int offset
)
341 proto_tree_add_item (tree
, hf_fcip_src_wwn
, tvb
, offset
, 8, ENC_NA
);
342 proto_tree_add_item (tree
, hf_fcip_src_entity_id
, tvb
, offset
+8, 8,
344 proto_tree_add_item (tree
, hf_fcip_conn_nonce
, tvb
, offset
+16, 8,
346 /* XXX - break out these flags */
347 proto_tree_add_item (tree
, hf_fcip_conn_flags
, tvb
, offset
+24, 1, ENC_BIG_ENDIAN
);
348 proto_tree_add_item (tree
, hf_fcip_conn_code
, tvb
, offset
+26, 2, ENC_BIG_ENDIAN
);
349 proto_tree_add_item (tree
, hf_fcip_dst_wwn
, tvb
, offset
+30, 8, ENC_NA
);
350 proto_tree_add_item (tree
, hf_fcip_katov
, tvb
, offset
+38, 4, ENC_BIG_ENDIAN
);
355 dissect_fcip (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
361 int bytes_remaining
= tvb_captured_length (tvb
);
362 uint8_t pflags
, sof
= 0, eof
= 0;
363 /* Set up structures needed to add the protocol subtree and manage it */
365 proto_tree
*fcip_tree
= NULL
;
369 if (bytes_remaining
< FCIP_ENCAP_HEADER_LEN
) {
374 ((pinfo
->srcport
!= fcip_port
) && (pinfo
->destport
!= fcip_port
))) {
378 while (bytes_remaining
> FCIP_ENCAP_HEADER_LEN
) {
379 if ((offset
= get_next_fcip_header_offset (tvb
, pinfo
, offset
)) == -1) {
382 else if (offset
== -2) {
383 /* We need more data to desegment */
388 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FCIP");
390 frame_len
= (tvb_get_ntohs (tvb
, offset
+12) & 0x03FF)*4;
392 if (bytes_remaining
< frame_len
) {
393 if(fcip_desegment
&& pinfo
->can_desegment
) {
395 * This frame doesn't have all of the data for
396 * this message, but we can do reassembly on it.
398 * Tell the TCP dissector where the data for this
399 * message starts in the data it handed us, and
400 * how many more bytes we need, and return.
402 pinfo
->desegment_offset
= offset
;
403 pinfo
->desegment_len
= frame_len
- bytes_remaining
;
408 pflags
= tvb_get_uint8 (tvb
, start
+8);
411 if (FCIP_IS_SF (pflags
)) {
412 ti
= proto_tree_add_protocol_format (tree
, proto_fcip
, tvb
, 0,
413 FCIP_ENCAP_HEADER_LEN
,
416 else if (tvb_bytes_exist (tvb
, offset
, offset
+frame_len
-4)) {
417 sof
= tvb_get_uint8 (tvb
, offset
+FCIP_ENCAP_HEADER_LEN
);
418 eof
= tvb_get_uint8 (tvb
, offset
+frame_len
- 4);
420 ti
= proto_tree_add_protocol_format (tree
, proto_fcip
, tvb
, 0,
421 FCIP_ENCAP_HEADER_LEN
,
423 val_to_str (sof
, fcip_sof_vals
,
425 val_to_str (eof
, fcip_eof_vals
,
429 sof
= tvb_get_uint8 (tvb
, offset
+FCIP_ENCAP_HEADER_LEN
);
431 ti
= proto_tree_add_protocol_format (tree
, proto_fcip
, tvb
, 0,
432 FCIP_ENCAP_HEADER_LEN
,
434 val_to_str (sof
, fcip_sof_vals
,
438 fcip_tree
= proto_item_add_subtree (ti
, ett_fcip
);
439 /* Dissect the Common FC Encap header */
440 dissect_fcencap_header (tvb
, fcip_tree
, offset
);
442 offset
+= FCIP_ENCAP_HEADER_LEN
;
444 if (!FCIP_IS_SF (pflags
)) {
446 proto_tree_add_item (fcip_tree
, hf_fcip_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
447 proto_tree_add_item (fcip_tree
, hf_fcip_sof_c
, tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
450 offset
+= (frame_len
-FCIP_ENCAP_HEADER_LEN
-4);
451 if (tvb_bytes_exist (tvb
, offset
, 4)) {
452 proto_tree_add_item (fcip_tree
, hf_fcip_eof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
453 proto_tree_add_item (fcip_tree
, hf_fcip_eof_c
, tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
458 /* Call the FC Dissector if this is carrying an FC frame */
459 if (!FCIP_IS_SF(pflags
)) {
460 /* Set the SOF/EOF flags in the packet_info header */
464 if ((sof
== FCIP_SOFi3
) || (sof
== FCIP_SOFi2
) || (sof
== FCIP_SOFi4
)) {
465 fc_data
.sof_eof
= FC_DATA_SOF_FIRST_FRAME
;
467 else if (sof
== FCIP_SOFf
) {
468 fc_data
.sof_eof
= FC_DATA_SOF_SOFF
;
471 if (eof
!= FCIP_EOFn
) {
472 fc_data
.sof_eof
|= FC_DATA_EOF_LAST_FRAME
;
474 else if (eof
!= FCIP_EOFt
) {
475 fc_data
.sof_eof
|= FC_DATA_EOF_INVALID
;
479 /* Special frame bit is not set */
480 next_tvb
= tvb_new_subset_remaining (tvb
, FCIP_ENCAP_HEADER_LEN
+4);
482 fc_data
.ethertype
= ETHERTYPE_UNK
;
483 call_dissector_with_data(fc_handle
, next_tvb
, pinfo
, tree
, &fc_data
);
486 call_data_dissector(next_tvb
, pinfo
, tree
);
490 col_set_str(pinfo
->cinfo
, COL_INFO
, "Special Frame");
491 if (FCIP_IS_CH (pflags
)) {
492 col_append_str(pinfo
->cinfo
, COL_INFO
, "(Changed)");
495 dissect_fcip_sf (tvb
, fcip_tree
, offset
+4);
498 bytes_remaining
-= frame_len
;
504 /* This is called for those sessions where we have explicitly said
505 this to be FCIP using "Decode As..."
506 In this case we will not check the port number for sanity and just
510 dissect_fcip_handle(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
512 dissect_fcip (tvb
, pinfo
, tree
, false);
513 return tvb_captured_length(tvb
);
517 dissect_fcip_heur (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
519 return (dissect_fcip (tvb
, pinfo
, tree
, true));
523 proto_register_fcip (void)
526 /* Setup list of header fields See Section 1.6.1 for details*/
527 static hf_register_info hf
[] = {
529 { "Protocol", "fcip.proto", FT_UINT8
, BASE_DEC
,
530 VALS(fcencap_proto_vals
), 0, NULL
, HFILL
}},
531 { &hf_fcip_protocol_c
,
532 {"Protocol (1's Complement)", "fcip.protoc", FT_UINT8
, BASE_DEC
,
533 NULL
, 0, NULL
, HFILL
}},
535 {"Version", "fcip.version", FT_UINT8
, BASE_DEC
,
536 NULL
, 0, NULL
, HFILL
}},
537 { &hf_fcip_version_c
,
538 {"Version (1's Complement)", "fcip.versionc", FT_UINT8
, BASE_DEC
,
539 NULL
, 0, NULL
, HFILL
}},
540 { &hf_fcip_encap_word1
,
541 {"FCIP Encapsulation Word1", "fcip.encap_word1", FT_UINT32
, BASE_HEX
,
542 NULL
, 0, NULL
, HFILL
}},
544 {"Flags", "fcip.flags", FT_UINT8
, BASE_HEX
,
545 NULL
, 0xFC, NULL
, HFILL
}},
547 {"Flags (1's Complement)", "fcip.flagsc", FT_UINT8
, BASE_HEX
,
548 NULL
, 0xFC, NULL
, HFILL
}},
550 {"Frame Length (in Words)", "fcip.framelen", FT_UINT16
, BASE_DEC
,
551 NULL
, 0x03FF, NULL
, HFILL
}},
552 { &hf_fcip_framelen_c
,
553 {"Frame Length (1's Complement)", "fcip.framelenc", FT_UINT16
, BASE_DEC
,
554 NULL
, 0x03FF, NULL
, HFILL
}},
556 {"Time (secs)", "fcip.tsec", FT_UINT32
, BASE_DEC
,
557 NULL
, 0, NULL
, HFILL
}},
559 {"Time (fraction)", "fcip.tusec", FT_UINT32
, BASE_DEC
,
560 NULL
, 0, NULL
, HFILL
}},
561 { &hf_fcip_encap_crc
,
562 {"CRC", "fcip.encap_crc", FT_UINT32
, BASE_HEX
,
563 NULL
, 0, NULL
, HFILL
}},
565 {"SOF", "fcip.sof", FT_UINT8
, BASE_HEX
,
566 VALS (fcip_sof_vals
), 0, NULL
, HFILL
}},
568 {"SOF (1's Complement)", "fcip.sofc", FT_UINT8
, BASE_HEX
,
569 NULL
, 0, NULL
, HFILL
}},
571 {"EOF", "fcip.eof", FT_UINT8
, BASE_HEX
,
572 VALS (fcip_eof_vals
), 0, NULL
, HFILL
}},
574 {"EOF (1's Complement)", "fcip.eofc", FT_UINT8
, BASE_HEX
,
575 NULL
, 0, NULL
, HFILL
}},
576 { &hf_fcip_pflags_changed
,
577 {"Changed Flag", "fcip.pflags.ch", FT_BOOLEAN
, 8,
578 NULL
, 0x80, NULL
, HFILL
}},
579 { &hf_fcip_pflags_special
,
580 {"Special Frame Flag", "fcip.pflags.sf", FT_BOOLEAN
, 8,
581 NULL
, 0x1, NULL
, HFILL
}},
583 {"Pflags (1's Complement)", "fcip.pflagsc", FT_UINT8
, BASE_HEX
,
584 NULL
, 0x0, NULL
, HFILL
}},
586 {"Source Fabric WWN", "fcip.srcwwn", FT_FCWWN
, BASE_NONE
,
587 NULL
, 0x0, NULL
, HFILL
}},
589 {"Destination Fabric WWN", "fcip.dstwwn", FT_FCWWN
, BASE_NONE
,
590 NULL
, 0x0, NULL
, HFILL
}},
591 { &hf_fcip_src_entity_id
,
592 {"FC/FCIP Entity Id", "fcip.srcid", FT_BYTES
, BASE_NONE
,
593 NULL
, 0x0, NULL
, HFILL
}},
594 { &hf_fcip_conn_flags
,
595 {"Connection Usage Flags", "fcip.connflags", FT_UINT8
, BASE_HEX
,
596 NULL
, 0x0, NULL
, HFILL
}},
597 { &hf_fcip_conn_code
,
598 {"Connection Usage Code", "fcip.conncode", FT_UINT16
, BASE_HEX
,
599 NULL
, 0x0, NULL
, HFILL
}},
601 {"K_A_TOV", "fcip.katov", FT_UINT32
, BASE_DEC
,
602 NULL
, 0x0, NULL
, HFILL
}},
603 { &hf_fcip_conn_nonce
,
604 {"Connection Nonce", "fcip.nonce", FT_BYTES
, BASE_NONE
,
605 NULL
, 0x0, NULL
, HFILL
}},
608 static int *ett
[] = {
612 module_t
*fcip_module
;
614 /* Register the protocol name and description */
615 proto_fcip
= proto_register_protocol("FCIP", "Fibre Channel over IP", "fcip");
616 fcip_handle
= register_dissector("fcip", dissect_fcip_handle
, proto_fcip
);
618 proto_register_field_array(proto_fcip
, hf
, array_length(hf
));
619 proto_register_subtree_array(ett
, array_length(ett
));
621 fcip_module
= prefs_register_protocol(proto_fcip
, NULL
);
622 prefs_register_bool_preference(fcip_module
,
624 "Reassemble FCIP messages spanning multiple TCP segments",
625 "Whether the FCIP dissector should reassemble messages spanning multiple TCP segments."
626 " To use this option, you must also enable"
627 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
629 prefs_register_uint_preference(fcip_module
,
632 "Port number used for FCIP",
638 proto_reg_handoff_fcip (void)
640 heur_dissector_add("tcp", dissect_fcip_heur
, "FCIP over TCP", "fcip_tcp", proto_fcip
, HEURISTIC_ENABLE
);
642 dissector_add_for_decode_as_with_preference("tcp.port", fcip_handle
);
644 fc_handle
= find_dissector_add_dependency("fc", proto_fcip
);
648 * Editor modelines - https://www.wireshark.org/tools/modelines.html
653 * indent-tabs-mode: nil
656 * vi: set shiftwidth=4 tabstop=8 expandtab:
657 * :indentSize=4:tabSize=8:noTabs=true: