2 * Routines for iFCP dissection
5 * Copyright 2005 Aboo Valappil (valappil_aboo@emc.com)
6 * 2006 ronnie sahlberg major refactoring
9 * Significantly based on packet-fcip.c by
10 * Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
24 #include <wsutil/array.h>
26 #include "packet-tcp.h"
27 #include "packet-fc.h"
29 void proto_register_ifcp(void);
30 void proto_reg_handoff_ifcp(void);
32 #define iFCP_ENCAP_HEADER_LEN 28
33 #define iFCP_MIN_HEADER_LEN 16 /* up to frame len field */
58 FCENCAP_PROTO_FCIP
= 1,
59 FCENCAP_PROTO_iFCP
= 2
62 static const value_string ifcp_eof_vals
[] = {
65 {iFCP_EOFrt
, "EOFrt" },
66 {iFCP_EOFdt
, "EOFdt" },
67 {iFCP_EOFni
, "EOFni" },
68 {iFCP_EOFdti
, "EOFdti" },
69 {iFCP_EOFrti
, "EOFrti" },
74 static const value_string ifcp_sof_vals
[] = {
76 {iFCP_SOFi4
, "SOFi4" },
77 {iFCP_SOFi2
, "SOFi2" },
78 {iFCP_SOFi3
, "SOFi3" },
79 {iFCP_SOFn4
, "SOFn4" },
80 {iFCP_SOFn2
, "SOFn2" },
81 {iFCP_SOFn3
, "SOFn3" },
82 {iFCP_SOFc4
, "SOFc4" },
86 static const value_string fcencap_proto_vals
[] = {
87 {FCENCAP_PROTO_iFCP
, "iFCP"},
88 {FCENCAP_PROTO_iFCP
, "iFCP"},
92 /* RFC 4172 section 5.3.1 shows a chart of the iFCP encapsulated Header Format.
93 * It says that bytes 4-7 MUST be zeros. In reality most vendors are putting
94 * some information in these 4 bytes, particularly Nishon.
96 static const uint8_t ifcp_header_4_bytes
[4] = {
97 0x02, 0x01, 0xFD, 0xFE
100 static int proto_ifcp
;
102 static int hf_ifcp_protocol
;
103 static int hf_ifcp_protocol_c
;
104 static int hf_ifcp_version
;
105 static int hf_ifcp_version_c
;
106 static int hf_ifcp_encap_flags_c
;
107 static int hf_ifcp_framelen
;
108 static int hf_ifcp_framelen_c
;
109 static int hf_ifcp_tsec
;
110 static int hf_ifcp_tusec
;
111 static int hf_ifcp_encap_crc
;
112 static int hf_ifcp_sof
;
113 static int hf_ifcp_sof_c
;
114 static int hf_ifcp_eof
;
115 static int hf_ifcp_eof_c
;
116 static int hf_ifcp_ls_command_acc
;
117 static int hf_ifcp_flags
;
118 static int hf_ifcp_flags_ses
;
119 static int hf_ifcp_flags_trp
;
120 static int hf_ifcp_flags_spc
;
121 static int hf_ifcp_common_flags
;
122 static int hf_ifcp_common_flags_crcv
;
125 static int ett_ifcp_sof
;
126 static int ett_ifcp_eof
;
127 static int ett_ifcp_flags
;
128 static int ett_ifcp_common_flags
;
129 static int ett_ifcp_protocol
;
130 static int ett_ifcp_version
;
131 static int ett_ifcp_frame_len
;
133 static bool ifcp_desegment
= true;
135 static dissector_handle_t ifcp_handle
;
136 static dissector_handle_t fc_handle
;
139 /* This function checks the first 16 bytes of the "header" that it looks sane
140 * and returns true if this looks like iFCP and false if it doesn't.
143 ifcp_header_test(tvbuff_t
*tvb
, int offset
)
145 uint16_t flen
, flen1
;
147 /* we can only do this test if we have 16 bytes or more */
148 if(tvb_captured_length_remaining(tvb
, offset
)<iFCP_MIN_HEADER_LEN
){
153 * As per the iFCP standard, the following tests must PASS:
154 * 1) Frame Length field validation -- 15 < Frame Length < 545;
155 * 2) Comparison of Frame Length field to its ones complement; and
156 * 3) A valid EOF is found in the word preceding the start of the next
157 * iFCP header as indicated by the Frame Length field, to be tested
159 * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
160 * list of legal EOF values is in the FC Frame Encapsulation
162 * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
163 * value found in bits 24-31.
165 * As per the iFCP standard, in addition, at least 3 of the following
166 * set of tests must be performed to identify that we've located the
167 * start of an iFCP frame.
168 * a) Protocol# ones complement field (1 test);
169 * b) Version ones complement field (1 test);
170 * c) Replication of encapsulation word 0 in word 1 (1 test);
171 * d) Reserved field and its ones complement (2 tests);
172 * e) Flags field and its ones complement (2 tests);
173 * f) CRC field is equal to zero (1 test); (DON'T DO THIS TEST!)
174 * g) SOF fields and ones complement fields (4 tests);
175 * h) Format and values of FC header (1 test);
176 * i) CRC of FC Frame (2 tests);
177 * j) FC Frame Encapsulation header information in the next iFCP Frame
180 * At least 3 of the 16 tests listed above SHALL be performed. Failure
181 * of any of the above tests actually performed SHALL indicate an
182 * encapsulation error and the FC Frame SHALL NOT be forwarded on to
190 if(tvb_memeql(tvb
, offset
, ifcp_header_4_bytes
, 4) != 0){
194 /* check the frame length */
195 flen
=tvb_get_ntohs(tvb
, offset
+12)&0x03FF;
196 if((flen
< 15) || (flen
> 545)){
200 /* check the complement of the frame length */
201 flen1
=tvb_get_ntohs(tvb
, offset
+14)&0x03FF;
202 if(flen
!=((~flen1
)&0x03FF)){
207 /* this should be good enough for our heuristics */
212 #define IFCP_FLAGS_SES 0x04
213 #define IFCP_FLAGS_TRP 0x02
214 #define IFCP_FLAGS_SPC 0x01
216 static const true_false_string ifcp_flags_ses_tfs
= {
217 "This is a SESSION CONTROL FRAME",
218 "This is a normal frame"
221 static const true_false_string ifcp_flags_trp_tfs
= {
222 "Address TRANSPARENT Mode Enabled",
223 "Address TRANSLATION Mode Enabled"
226 static const true_false_string ifcp_flags_spc_tfs
= {
227 "This frame requires SPECIAL PROCESSING",
228 "This is a normal frame"
232 dissect_ifcpflags(tvbuff_t
*tvb
, int offset
, proto_tree
*parent_tree
)
234 static int * const flags
[] = {
240 proto_tree_add_bitmask(parent_tree
, tvb
, offset
, hf_ifcp_flags
,
241 ett_ifcp_flags
, flags
, ENC_BIG_ENDIAN
);
248 #define IFCP_COMMON_FLAGS_CRCV 0x04
251 dissect_commonflags(tvbuff_t
*tvb
, int offset
, proto_tree
*parent_tree
)
253 static int * const flags
[] = {
254 &hf_ifcp_common_flags_crcv
,
258 proto_tree_add_bitmask(parent_tree
, tvb
, offset
, hf_ifcp_common_flags
,
259 ett_ifcp_common_flags
, flags
, ENC_BIG_ENDIAN
);
263 dissect_ifcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
265 int offset
= 0, frame_len
= 0;
266 uint8_t sof
= 0, eof
= 0;
268 proto_tree
*tree
= NULL
;
271 proto_tree
*protocol_tree
= NULL
;
272 proto_tree
*version_tree
= NULL
;
273 proto_tree
*frame_len_tree
= NULL
;
274 proto_tree
*sof_tree
= NULL
;
275 proto_tree
*eof_tree
= NULL
;
278 /* verify we have a full header (do we need to do this? */
279 if(tvb_captured_length(tvb
)<iFCP_ENCAP_HEADER_LEN
){
283 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "iFCP");
285 frame_len
= (tvb_get_ntohs (tvb
, offset
+12) & 0x03FF)*4;
289 if (tvb_bytes_exist (tvb
, offset
, frame_len
-4)) {
290 sof
= tvb_get_uint8 (tvb
, offset
+iFCP_ENCAP_HEADER_LEN
);
291 eof
= tvb_get_uint8 (tvb
, offset
+frame_len
- 4);
293 ti
= proto_tree_add_protocol_format (parent_tree
, proto_ifcp
, tvb
, offset
,
294 iFCP_ENCAP_HEADER_LEN
,
296 val_to_str (sof
, ifcp_sof_vals
,
298 val_to_str (eof
, ifcp_eof_vals
,
301 sof
= tvb_get_uint8 (tvb
, offset
+iFCP_ENCAP_HEADER_LEN
);
303 ti
= proto_tree_add_protocol_format (parent_tree
, proto_ifcp
, tvb
, offset
,
304 iFCP_ENCAP_HEADER_LEN
,
306 val_to_str (sof
, ifcp_sof_vals
,
310 tree
= proto_item_add_subtree (ti
, ett_ifcp
);
315 /* The Common FC Encap header */
317 protocol
= tvb_get_uint8 (tvb
, offset
);
318 ti
=proto_tree_add_item(tree
, hf_ifcp_protocol
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
319 protocol_tree
=proto_item_add_subtree(ti
, ett_ifcp_protocol
);
324 ti
=proto_tree_add_item(tree
, hf_ifcp_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
325 version_tree
=proto_item_add_subtree(ti
, ett_ifcp_version
);
328 /* protocol complement */
329 proto_tree_add_item(protocol_tree
, hf_ifcp_protocol_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
332 /* version complement */
333 proto_tree_add_item(version_tree
, hf_ifcp_version_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
336 /* 4 reserved bytes */
339 /* iFCP specific fields */
340 if(protocol
==FCENCAP_PROTO_iFCP
){
342 proto_tree_add_item(tree
, hf_ifcp_ls_command_acc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
346 offset
=dissect_ifcpflags(tvb
, offset
, tree
);
349 ti
=proto_tree_add_item(tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
350 sof_tree
=proto_item_add_subtree(ti
, ett_ifcp_sof
);
354 ti
=proto_tree_add_item(tree
, hf_ifcp_eof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
355 eof_tree
=proto_item_add_subtree(ti
, ett_ifcp_eof
);
359 sof_tree
=tree
; /* better than nothing */
364 dissect_commonflags(tvb
, offset
, tree
);
367 ti
=proto_tree_add_item(tree
, hf_ifcp_framelen
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
368 frame_len_tree
=proto_item_add_subtree(ti
, ett_ifcp_frame_len
);
371 /* complement of flags and frame len */
372 proto_tree_add_item(frame_len_tree
, hf_ifcp_encap_flags_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
373 proto_tree_add_item(frame_len_tree
, hf_ifcp_framelen_c
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
376 /* timestamp seconds */
377 proto_tree_add_item(tree
, hf_ifcp_tsec
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
380 /* timestamp fractions */
381 proto_tree_add_item(tree
, hf_ifcp_tusec
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
385 proto_tree_add_item(tree
, hf_ifcp_encap_crc
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
390 proto_tree_add_item(sof_tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
392 proto_tree_add_item(sof_tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
394 proto_tree_add_item(sof_tree
, hf_ifcp_sof_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
396 proto_tree_add_item(sof_tree
, hf_ifcp_sof_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
400 if(tvb_bytes_exist(tvb
, frame_len
-4, 4)) {
401 proto_tree_add_item(eof_tree
, hf_ifcp_eof
, tvb
, frame_len
-4, 1, ENC_BIG_ENDIAN
);
402 proto_tree_add_item(eof_tree
, hf_ifcp_eof
, tvb
, frame_len
-3, 1, ENC_BIG_ENDIAN
);
403 proto_tree_add_item(eof_tree
, hf_ifcp_eof_c
, tvb
, frame_len
-2, 1, ENC_BIG_ENDIAN
);
404 proto_tree_add_item(eof_tree
, hf_ifcp_eof_c
, tvb
, frame_len
-1, 1, ENC_BIG_ENDIAN
);
408 /* Call the FC Dissector if this is carrying an FC frame */
409 /* Set the SOF/EOF flags in the packet_info header */
416 fc_data
.sof_eof
= FC_DATA_SOF_FIRST_FRAME
;
419 fc_data
.sof_eof
= FC_DATA_SOF_SOFF
;
423 if (eof
!= iFCP_EOFn
) {
424 fc_data
.sof_eof
|= FC_DATA_EOF_LAST_FRAME
;
425 } else if (eof
!= iFCP_EOFt
) {
426 fc_data
.sof_eof
|= FC_DATA_EOF_INVALID
;
431 next_tvb
=tvb_new_subset_length(tvb
, offset
, frame_len
-offset
-4);
432 fc_data
.ethertype
= ETHERTYPE_UNK
;
435 call_dissector_with_data(fc_handle
, next_tvb
, pinfo
, parent_tree
, &fc_data
);
437 call_data_dissector(next_tvb
, pinfo
, parent_tree
);
440 return tvb_captured_length(tvb
);
444 get_ifcp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
448 if(!ifcp_header_test(tvb
, offset
)){
452 pdu_len
=(tvb_get_ntohs(tvb
, offset
+12)&0x03FF)*4;
457 dissect_ifcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
459 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, ifcp_desegment
, iFCP_MIN_HEADER_LEN
, get_ifcp_pdu_len
, dissect_ifcp_pdu
, data
);
460 return tvb_captured_length(tvb
);
464 /* This is called for those sessions where we have explicitly said
465 * this to be iFCP using "Decode As..."
466 * In this case we will not check the port number for sanity and just
467 * do as the user said.
470 dissect_ifcp_handle(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
472 return dissect_ifcp(tvb
, pinfo
, tree
, data
);
476 dissect_ifcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
478 if(!ifcp_header_test(tvb
, 0)){
482 dissect_ifcp(tvb
, pinfo
, tree
, data
);
484 /* our heuristics are so strong that if the heuristics above passed
485 * and the dissection of the pdu did not cause any exceptions
486 * then we can set this as our conversation dissector
489 conversation_t
* ifcp_conv
;
491 ifcp_conv
=find_or_create_conversation(pinfo
);
492 /* XXX why does this not work? it doesn't result in dissect_ifcp_handle being called look into later*/
493 conversation_set_dissector(ifcp_conv
, ifcp_handle
);
500 proto_register_ifcp (void)
502 /* Setup list of header fields See Section 1.6.1 for details*/
503 static hf_register_info hf
[] = {
505 {"Protocol", "ifcp.encap.proto", FT_UINT8
, BASE_DEC
, VALS(fcencap_proto_vals
), 0,
507 { &hf_ifcp_protocol_c
,
508 {"Protocol (1's Complement)", "ifcp.encap.protoc", FT_UINT8
, BASE_DEC
, NULL
, 0,
511 {"Version", "ifcp.encap.version", FT_UINT8
, BASE_DEC
, NULL
, 0,
513 { &hf_ifcp_version_c
,
514 {"Version (1's Complement)", "ifcp.encap.versionc", FT_UINT8
, BASE_DEC
, NULL
, 0,
516 { &hf_ifcp_encap_flags_c
,
517 {"iFCP Encapsulation Flags (1's Complement)", "ifcp.encap_flagsc", FT_UINT8
, BASE_HEX
, NULL
, 0xFC,
520 {"Frame Length (in Words)", "ifcp.encap.framelen", FT_UINT16
, BASE_DEC
, NULL
, 0x03FF,
522 { &hf_ifcp_framelen_c
,
523 {"Frame Length (1's Complement)", "ifcp.encap.framelenc", FT_UINT16
, BASE_DEC
, NULL
, 0x03FF,
526 {"Time (secs)", "ifcp.encap.tsec", FT_UINT32
, BASE_DEC
, NULL
, 0,
529 {"Time (fraction)", "ifcp.encap.tusec", FT_UINT32
, BASE_DEC
, NULL
, 0,
531 { &hf_ifcp_encap_crc
,
532 {"CRC", "ifcp.encap.crc", FT_UINT32
, BASE_HEX
, NULL
, 0,
535 {"SOF", "ifcp.sof", FT_UINT8
, BASE_HEX
, VALS (ifcp_sof_vals
), 0,
538 {"EOF", "ifcp.eof", FT_UINT8
, BASE_HEX
, VALS (ifcp_eof_vals
), 0,
541 {"SOF Compliment", "ifcp.sof_c", FT_UINT8
, BASE_HEX
, NULL
, 0,
544 {"EOF Compliment", "ifcp.eof_c", FT_UINT8
, BASE_HEX
, NULL
, 0,
546 { &hf_ifcp_ls_command_acc
,
547 {"Ls Command Acc", "ifcp.ls_command_acc", FT_UINT8
, BASE_HEX
, NULL
, 0,
549 { &hf_ifcp_common_flags
,
550 {"Flags", "ifcp.common_flags", FT_UINT8
, BASE_HEX
, NULL
, 0xfc,
552 { &hf_ifcp_common_flags_crcv
,
553 {"CRC", "ifcp.common_flags.crcv", FT_BOOLEAN
, 8, TFS(&tfs_valid_not_valid
), IFCP_COMMON_FLAGS_CRCV
,
554 "Is the CRC field valid?", HFILL
}},
556 {"iFCP Flags", "ifcp.flags", FT_UINT8
, BASE_HEX
, NULL
, 0,
558 { &hf_ifcp_flags_ses
,
559 {"SES", "ifcp.flags.ses", FT_BOOLEAN
, 8, TFS(&ifcp_flags_ses_tfs
), IFCP_FLAGS_SES
,
560 "Is this a Session control frame", HFILL
}},
561 { &hf_ifcp_flags_trp
,
562 {"TRP", "ifcp.flags.trp", FT_BOOLEAN
, 8, TFS(&ifcp_flags_trp_tfs
), IFCP_FLAGS_TRP
,
563 "Is address transparent mode enabled", HFILL
}},
564 { &hf_ifcp_flags_spc
,
565 {"SPC", "ifcp.flags.spc", FT_BOOLEAN
, 8, TFS(&ifcp_flags_spc_tfs
), IFCP_FLAGS_SPC
,
566 "Is frame part of link service", HFILL
}},
569 static int *ett
[] = {
577 &ett_ifcp_common_flags
,
580 module_t
*ifcp_module
;
582 /* Register the protocol name and description */
583 proto_ifcp
= proto_register_protocol("iFCP", "iFCP", "ifcp");
585 proto_register_field_array(proto_ifcp
, hf
, array_length(hf
));
586 proto_register_subtree_array(ett
, array_length(ett
));
588 ifcp_module
= prefs_register_protocol(proto_ifcp
, NULL
);
589 prefs_register_bool_preference(ifcp_module
,
591 "Reassemble iFCP messages spanning multiple TCP segments",
592 "Whether the iFCP dissector should reassemble messages spanning multiple TCP segments."
593 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
595 prefs_register_obsolete_preference(ifcp_module
, "target_port");
597 ifcp_handle
= register_dissector("ifcp", dissect_ifcp_handle
, proto_ifcp
);
601 proto_reg_handoff_ifcp (void)
603 heur_dissector_add("tcp", dissect_ifcp_heur
, "iFCP over TCP", "ifcp_tcp", proto_ifcp
, HEURISTIC_ENABLE
);
605 dissector_add_for_decode_as_with_preference("tcp.port", ifcp_handle
);
607 fc_handle
= find_dissector_add_dependency("fc_ifcp", proto_ifcp
);
611 * Editor modelines - https://www.wireshark.org/tools/modelines.html
616 * indent-tabs-mode: nil
619 * vi: set shiftwidth=4 tabstop=8 expandtab:
620 * :indentSize=4:tabSize=8:noTabs=true: