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)
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #include <epan/packet.h>
38 #include <epan/prefs.h>
39 #include <epan/conversation.h>
40 #include "packet-tcp.h"
42 #define iFCP_ENCAP_HEADER_LEN 28
43 #define iFCP_MIN_HEADER_LEN 16 /* upto frame len field */
68 FCENCAP_PROTO_FCIP
= 1,
69 FCENCAP_PROTO_iFCP
= 2
72 static const value_string ifcp_eof_vals
[] = {
75 {iFCP_EOFrt
, "EOFrt" },
76 {iFCP_EOFdt
, "EOFdt" },
77 {iFCP_EOFni
, "EOFni" },
78 {iFCP_EOFdti
, "EOFdti" },
79 {iFCP_EOFrti
, "EOFrti" },
84 static const value_string ifcp_sof_vals
[] = {
86 {iFCP_SOFi4
, "SOFi4" },
87 {iFCP_SOFi2
, "SOFi2" },
88 {iFCP_SOFi3
, "SOFi3" },
89 {iFCP_SOFn4
, "SOFn4" },
90 {iFCP_SOFn2
, "SOFn2" },
91 {iFCP_SOFn3
, "SOFn3" },
92 {iFCP_SOFc4
, "SOFc4" },
96 static const value_string fcencap_proto_vals
[] = {
97 {FCENCAP_PROTO_iFCP
, "iFCP"},
98 {FCENCAP_PROTO_iFCP
, "iFCP"},
102 /* RFC 4172 section 5.3.1 shows a chart of the iFCP encapsulated Header Format.
103 * It says that bytes 4-7 MUST be zeros. In reality most vendors are putting
104 * some information in these 4 bytes, particularly Nishon.
106 static const guint8 ifcp_header_4_bytes
[4] = {
107 0x02, 0x01, 0xFD, 0xFE
110 static int proto_ifcp
= -1;
112 static int hf_ifcp_protocol
= -1;
113 static int hf_ifcp_protocol_c
= -1;
114 static int hf_ifcp_version
= -1;
115 static int hf_ifcp_version_c
= -1;
116 static int hf_ifcp_encap_flags_c
=-1;
117 static int hf_ifcp_framelen
= -1;
118 static int hf_ifcp_framelen_c
= -1;
119 static int hf_ifcp_tsec
= -1;
120 static int hf_ifcp_tusec
= -1;
121 static int hf_ifcp_encap_crc
= -1;
122 static int hf_ifcp_sof
= -1;
123 static int hf_ifcp_sof_c
= -1;
124 static int hf_ifcp_eof
= -1;
125 static int hf_ifcp_eof_c
= -1;
126 static int hf_ifcp_ls_command_acc
= -1;
127 static int hf_ifcp_flags
= -1;
128 static int hf_ifcp_flags_ses
= -1;
129 static int hf_ifcp_flags_trp
= -1;
130 static int hf_ifcp_flags_spc
= -1;
131 static int hf_ifcp_common_flags
= -1;
132 static int hf_ifcp_common_flags_crcv
= -1;
134 static int ett_ifcp
= -1;
135 static int ett_ifcp_sof
= -1;
136 static int ett_ifcp_eof
= -1;
137 static int ett_ifcp_flags
= -1;
138 static int ett_ifcp_common_flags
= -1;
139 static int ett_ifcp_protocol
= -1;
140 static int ett_ifcp_version
= -1;
141 static int ett_ifcp_frame_len
= -1;
143 static gboolean ifcp_desegment
= TRUE
;
145 static dissector_handle_t ifcp_handle
=NULL
;
146 static dissector_handle_t data_handle
=NULL
;
147 static dissector_handle_t fc_handle
=NULL
;
150 /* This function checks the first 16 bytes of the "header" that it looks sane
151 * and returns TRUE if this looks like iFCP and FALSE if it doesnt.
154 ifcp_header_test(tvbuff_t
*tvb
, int offset
)
158 /* we can only do this test if we have 16 bytes or more */
159 if(tvb_length_remaining(tvb
, offset
)<iFCP_MIN_HEADER_LEN
){
164 * As per the iFCP standard, the following tests must PASS:
165 * 1) Frame Length field validation -- 15 < Frame Length < 545;
166 * 2) Comparison of Frame Length field to its ones complement; and
167 * 3) A valid EOF is found in the word preceding the start of the next
168 * iFCP header as indicated by the Frame Length field, to be tested
170 * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
171 * list of legal EOF values is in the FC Frame Encapsulation
173 * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
174 * value found in bits 24-31.
176 * As per the iFCP standard, in addition, at least 3 of the following
177 * set of tests must be performed to identify that we've located the
178 * start of an iFCP frame.
179 * a) Protocol# ones complement field (1 test);
180 * b) Version ones complement field (1 test);
181 * c) Replication of encapsulation word 0 in word 1 (1 test);
182 * d) Reserved field and its ones complement (2 tests);
183 * e) Flags field and its ones complement (2 tests);
184 * f) CRC field is equal to zero (1 test); (DONT DO THIS TEST!)
185 * g) SOF fields and ones complement fields (4 tests);
186 * h) Format and values of FC header (1 test);
187 * i) CRC of FC Frame (2 tests);
188 * j) FC Frame Encapsulation header information in the next iFCP Frame
191 * At least 3 of the 16 tests listed above SHALL be performed. Failure
192 * of any of the above tests actually performed SHALL indicate an
193 * encapsulation error and the FC Frame SHALL NOT be forwarded on to
201 if(tvb_memeql(tvb
, offset
, ifcp_header_4_bytes
, 4) != 0){
205 /* check the frame length */
206 flen
=tvb_get_ntohs(tvb
, offset
+12)&0x03FF;
207 if((flen
< 15) || (flen
> 545)){
211 /* check the complement of the frame length */
212 flen1
=tvb_get_ntohs(tvb
, offset
+14)&0x03FF;
213 if(flen
!=((~flen1
)&0x03FF)){
218 /* this should be good enough for our heuristics */
223 #define IFCP_FLAGS_SES 0x04
224 #define IFCP_FLAGS_TRP 0x02
225 #define IFCP_FLAGS_SPC 0x01
227 static const true_false_string ifcp_flags_ses_tfs
= {
228 "This is a SESSION CONTROL FRAME",
229 "This is a normal frame"
232 static const true_false_string ifcp_flags_trp_tfs
= {
233 "Address TRANSPARENT Mode Enabled",
234 "Address TRANSLATION Mode Enabled"
237 static const true_false_string ifcp_flags_spc_tfs
= {
238 "This frame requires SPECIAL PROCESSING",
239 "This is a normal frame"
243 dissect_ifcpflags(tvbuff_t
*tvb
, int offset
, proto_tree
*parent_tree
)
245 proto_item
*item
=NULL
;
246 proto_tree
*tree
=NULL
;
250 item
=proto_tree_add_item(parent_tree
, hf_ifcp_flags
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
251 tree
=proto_item_add_subtree (item
, ett_ifcp_flags
);
254 flags
=tvb_get_guint8(tvb
, offset
);
257 proto_tree_add_boolean(tree
, hf_ifcp_flags_ses
, tvb
, offset
, 1, flags
);
258 if(flags
&IFCP_FLAGS_SES
){
259 proto_item_append_text(item
, " SES");
261 flags
&=(~IFCP_FLAGS_SES
);
264 proto_tree_add_boolean(tree
, hf_ifcp_flags_trp
, tvb
, offset
, 1, flags
);
265 if(flags
&IFCP_FLAGS_TRP
){
266 proto_item_append_text(item
, " TRP");
268 flags
&=(~IFCP_FLAGS_TRP
);
271 proto_tree_add_boolean(tree
, hf_ifcp_flags_spc
, tvb
, offset
, 1, flags
);
272 if(flags
&IFCP_FLAGS_SPC
){
273 proto_item_append_text(item
, " SPC");
282 #define IFCP_COMMON_FLAGS_CRCV 0x04
284 static const true_false_string ifcp_common_flags_crcv_tfs
= {
290 dissect_commonflags(tvbuff_t
*tvb
, int offset
, proto_tree
*parent_tree
)
292 proto_item
*item
=NULL
;
293 proto_tree
*tree
=NULL
;
297 item
=proto_tree_add_item(parent_tree
, hf_ifcp_common_flags
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
298 tree
=proto_item_add_subtree (item
, ett_ifcp_common_flags
);
301 flags
=tvb_get_guint8(tvb
, offset
);
304 proto_tree_add_boolean(tree
, hf_ifcp_common_flags_crcv
, tvb
, offset
, 1, flags
);
305 if(flags
&IFCP_COMMON_FLAGS_CRCV
){
306 proto_item_append_text(item
, " CRCV");
311 dissect_ifcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
313 gint offset
= 0, frame_len
= 0;
314 guint8 sof
= 0, eof
= 0;
316 proto_tree
*tree
= NULL
;
319 proto_tree
*protocol_tree
=NULL
;
320 proto_tree
*version_tree
=NULL
;
321 proto_tree
*frame_len_tree
=NULL
;
322 proto_tree
*sof_tree
=NULL
;
323 proto_tree
*eof_tree
=NULL
;
325 /* verify we have a full header (do we need to do this? */
326 if(tvb_length(tvb
)<iFCP_ENCAP_HEADER_LEN
){
330 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "iFCP");
332 frame_len
= (tvb_get_ntohs (tvb
, offset
+12) & 0x03FF)*4;
336 if (tvb_bytes_exist (tvb
, offset
, frame_len
-4)) {
337 sof
= tvb_get_guint8 (tvb
, offset
+iFCP_ENCAP_HEADER_LEN
);
338 eof
= tvb_get_guint8 (tvb
, offset
+frame_len
- 4);
340 ti
= proto_tree_add_protocol_format (parent_tree
, proto_ifcp
, tvb
, offset
,
341 iFCP_ENCAP_HEADER_LEN
,
343 val_to_str (sof
, ifcp_sof_vals
,
345 val_to_str (eof
, ifcp_eof_vals
,
348 sof
= tvb_get_guint8 (tvb
, offset
+iFCP_ENCAP_HEADER_LEN
);
350 ti
= proto_tree_add_protocol_format (parent_tree
, proto_ifcp
, tvb
, offset
,
351 iFCP_ENCAP_HEADER_LEN
,
353 val_to_str (sof
, ifcp_sof_vals
,
357 tree
= proto_item_add_subtree (ti
, ett_ifcp
);
362 /* The Common FC Encap header */
364 protocol
= tvb_get_guint8 (tvb
, offset
);
365 ti
=proto_tree_add_item(tree
, hf_ifcp_protocol
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
367 protocol_tree
=proto_item_add_subtree(ti
, ett_ifcp_protocol
);
372 ti
=proto_tree_add_item(tree
, hf_ifcp_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
374 version_tree
=proto_item_add_subtree(ti
, ett_ifcp_version
);
378 /* protocol complement */
379 proto_tree_add_item(protocol_tree
, hf_ifcp_protocol_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
382 /* version complement */
383 proto_tree_add_item(version_tree
, hf_ifcp_version_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
386 /* 4 reserved bytes */
389 /* iFCP specific fields */
390 if(protocol
==FCENCAP_PROTO_iFCP
){
392 proto_tree_add_item(tree
, hf_ifcp_ls_command_acc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
396 offset
=dissect_ifcpflags(tvb
, offset
, tree
);
399 ti
=proto_tree_add_item(tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
401 sof_tree
=proto_item_add_subtree(ti
, ett_ifcp_sof
);
406 ti
=proto_tree_add_item(tree
, hf_ifcp_eof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
408 eof_tree
=proto_item_add_subtree(ti
, ett_ifcp_eof
);
413 sof_tree
=tree
; /* better than nothing */
418 dissect_commonflags(tvb
, offset
, tree
);
421 ti
=proto_tree_add_item(tree
, hf_ifcp_framelen
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
423 frame_len_tree
=proto_item_add_subtree(ti
, ett_ifcp_frame_len
);
427 /* complement of flags and frame len */
428 proto_tree_add_item(frame_len_tree
, hf_ifcp_encap_flags_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
429 proto_tree_add_item(frame_len_tree
, hf_ifcp_framelen_c
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
432 /* timestamp seconds */
433 proto_tree_add_item(tree
, hf_ifcp_tsec
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
436 /* timestamp fractions */
437 proto_tree_add_item(tree
, hf_ifcp_tusec
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
441 proto_tree_add_item(tree
, hf_ifcp_encap_crc
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
446 proto_tree_add_item(sof_tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
448 proto_tree_add_item(sof_tree
, hf_ifcp_sof
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
450 proto_tree_add_item(sof_tree
, hf_ifcp_sof_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
452 proto_tree_add_item(sof_tree
, hf_ifcp_sof_c
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
456 if(tvb_bytes_exist(tvb
, frame_len
-4, 4)) {
457 proto_tree_add_item(eof_tree
, hf_ifcp_eof
, tvb
, frame_len
-4, 1, ENC_BIG_ENDIAN
);
458 proto_tree_add_item(eof_tree
, hf_ifcp_eof
, tvb
, frame_len
-3, 1, ENC_BIG_ENDIAN
);
459 proto_tree_add_item(eof_tree
, hf_ifcp_eof_c
, tvb
, frame_len
-2, 1, ENC_BIG_ENDIAN
);
460 proto_tree_add_item(eof_tree
, hf_ifcp_eof_c
, tvb
, frame_len
-1, 1, ENC_BIG_ENDIAN
);
464 /* Call the FC Dissector if this is carrying an FC frame */
465 /* Set the SOF/EOF flags in the packet_info header */
472 pinfo
->sof_eof
= PINFO_SOF_FIRST_FRAME
;
475 pinfo
->sof_eof
= PINFO_SOF_SOFF
;
479 if (eof
!= iFCP_EOFn
) {
480 pinfo
->sof_eof
|= PINFO_EOF_LAST_FRAME
;
481 } else if (eof
!= iFCP_EOFt
) {
482 pinfo
->sof_eof
|= PINFO_EOF_INVALID
;
487 next_tvb
=tvb_new_subset(tvb
, offset
, frame_len
-offset
-4, frame_len
-offset
-4);
490 call_dissector(fc_handle
, next_tvb
, pinfo
, parent_tree
);
491 } else if(data_handle
){
492 call_dissector(data_handle
, next_tvb
, pinfo
, parent_tree
);
495 return tvb_length(tvb
);
499 get_ifcp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
)
503 if(!ifcp_header_test(tvb
, offset
)){
507 pdu_len
=(tvb_get_ntohs(tvb
, offset
+12)&0x03FF)*4;
512 dissect_ifcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
514 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, ifcp_desegment
, iFCP_MIN_HEADER_LEN
, get_ifcp_pdu_len
, dissect_ifcp_pdu
, data
);
515 return tvb_length(tvb
);
519 /* This is called for those sessions where we have explicitely said
520 * this to be iFCP using "Decode As..."
521 * In this case we will not check the port number for sanity and just
522 * do as the user said.
525 dissect_ifcp_handle(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
527 return dissect_ifcp(tvb
, pinfo
, tree
, data
);
531 dissect_ifcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
533 if(!ifcp_header_test(tvb
, 0)){
537 dissect_ifcp(tvb
, pinfo
, tree
, data
);
539 /* our heuristics are so strong that if the heuristics above passed
540 * and the dissection of the pdu did not cause any exceptions
541 * then we can set this as our conversation dissector
544 conversation_t
* ifcp_conv
;
546 ifcp_conv
=find_or_create_conversation(pinfo
);
547 /* XXX why does this not work? it doesnt result in dissect_ifcp_handle being called look into later*/
548 conversation_set_dissector(ifcp_conv
, ifcp_handle
);
555 proto_register_ifcp (void)
558 /* Setup list of header fields See Section 1.6.1 for details*/
559 static hf_register_info hf
[] = {
561 { "Protocol", "ifcp.encap.proto", FT_UINT8
, BASE_DEC
,
562 VALS(fcencap_proto_vals
), 0, NULL
, HFILL
}},
563 { &hf_ifcp_protocol_c
,
564 {"Protocol (1's Complement)", "ifcp.encap.protoc", FT_UINT8
, BASE_DEC
, NULL
,
567 {"Version", "ifcp.encap.version", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
,
569 { &hf_ifcp_version_c
,
570 {"Version (1's Complement)", "ifcp.encap.versionc", FT_UINT8
, BASE_DEC
,
571 NULL
, 0, NULL
, HFILL
}},
572 { &hf_ifcp_encap_flags_c
,
573 {"iFCP Encapsulation Flags (1's Complement)", "ifcp.encap_flagsc", FT_UINT8
, BASE_HEX
,
574 NULL
, 0xFC, NULL
, HFILL
}},
576 {"Frame Length (in Words)", "ifcp.encap.framelen", FT_UINT16
, BASE_DEC
,
577 NULL
, 0x03FF, NULL
, HFILL
}},
578 { &hf_ifcp_framelen_c
,
579 {"Frame Length (1's Complement)", "ifcp.encap.framelenc", FT_UINT16
,
580 BASE_DEC
, NULL
, 0x03FF, NULL
, HFILL
}},
582 {"Time (secs)", "ifcp.encap.tsec", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
,
585 {"Time (fraction)", "ifcp.encap.tusec", FT_UINT32
, BASE_DEC
, NULL
, 0,
587 { &hf_ifcp_encap_crc
,
588 {"CRC", "ifcp.encap.crc", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
590 {"SOF", "ifcp.sof", FT_UINT8
, BASE_HEX
, VALS (&ifcp_sof_vals
), 0,
593 {"EOF", "ifcp.eof", FT_UINT8
, BASE_HEX
, VALS (&ifcp_eof_vals
), 0,
596 {"SOF Compliment", "ifcp.sof_c", FT_UINT8
, BASE_HEX
, NULL
, 0,
599 {"EOF Compliment", "ifcp.eof_c", FT_UINT8
, BASE_HEX
, NULL
, 0,
601 { &hf_ifcp_ls_command_acc
,
602 {"Ls Command Acc", "ifcp.ls_command_acc", FT_UINT8
, BASE_HEX
, NULL
, 0,
604 { &hf_ifcp_common_flags
,
605 {"Flags", "ifcp.common_flags", FT_UINT8
, BASE_HEX
, NULL
, 0xfc, NULL
, HFILL
}},
606 { &hf_ifcp_common_flags_crcv
,
607 {"CRCV", "ifcp.common_flags.crcv", FT_BOOLEAN
, 8, TFS(&ifcp_common_flags_crcv_tfs
), IFCP_COMMON_FLAGS_CRCV
, "Is the CRC field valid?", HFILL
}},
609 {"iFCP Flags", "ifcp.flags", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
610 { &hf_ifcp_flags_ses
,
611 {"SES", "ifcp.flags.ses", FT_BOOLEAN
, 8, TFS(&ifcp_flags_ses_tfs
), IFCP_FLAGS_SES
, "Is this a Session control frame", HFILL
}},
612 { &hf_ifcp_flags_trp
,
613 {"TRP", "ifcp.flags.trp", FT_BOOLEAN
, 8, TFS(&ifcp_flags_trp_tfs
), IFCP_FLAGS_TRP
, "Is address transparent mode enabled", HFILL
}},
614 { &hf_ifcp_flags_spc
,
615 {"SPC", "ifcp.flags.spc", FT_BOOLEAN
, 8, TFS(&ifcp_flags_spc_tfs
), IFCP_FLAGS_SPC
, "Is frame part of link service", HFILL
}},
618 static gint
*ett
[] = {
626 &ett_ifcp_common_flags
,
629 module_t
*ifcp_module
;
631 /* Register the protocol name and description */
632 proto_ifcp
= proto_register_protocol("iFCP", "iFCP", "ifcp");
634 /* Required function calls to register the header fields and
636 proto_register_field_array(proto_ifcp
, hf
, array_length(hf
));
637 proto_register_subtree_array(ett
, array_length(ett
));
639 ifcp_module
= prefs_register_protocol(proto_ifcp
, NULL
);
640 prefs_register_bool_preference(ifcp_module
,
642 "Reassemble iFCP messages spanning multiple TCP segments",
643 "Whether the iFCP dissector should reassemble messages spanning multiple TCP segments."
644 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
646 prefs_register_obsolete_preference(ifcp_module
, "target_port");
651 * If this dissector uses sub-dissector registration add a
652 * registration routine.
656 * This format is required because a script is used to find these
657 * routines and create the code that calls these routines.
660 proto_reg_handoff_ifcp (void)
662 heur_dissector_add("tcp", dissect_ifcp_heur
, proto_ifcp
);
664 ifcp_handle
= new_create_dissector_handle(dissect_ifcp_handle
, proto_ifcp
);
665 dissector_add_handle("tcp.port", ifcp_handle
);
667 data_handle
= find_dissector("data");
668 fc_handle
= find_dissector("fc_ifcp");