2 * Routines for FCIP dissection
4 * Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
38 #define FCIP_ENCAP_HEADER_LEN 28
39 #define FCIP_MIN_HEADER_LEN 16 /* upto frame len field */
40 #define FCIP_IS_SF(pflags) ((pflags & 0x1) == 0x1)
41 #define FCIP_IS_CH(pflags) ((pflags & 0x80) == 0x80)
66 FCENCAP_PROTO_FCIP = 1,
67 FCENCAP_PROTO_iFCP = 2
70 static const value_string fcip_eof_vals[] = {
73 {FCIP_EOFrt, "EOFrt" },
74 {FCIP_EOFdt, "EOFdt" },
75 {FCIP_EOFni, "EOFni" },
76 {FCIP_EOFdti, "EOFdti" },
77 {FCIP_EOFrti, "EOFrti" },
82 static const value_string fcip_sof_vals[] = {
84 {FCIP_SOFi4, "SOFi4" },
85 {FCIP_SOFi2, "SOFi2" },
86 {FCIP_SOFi3, "SOFi3" },
87 {FCIP_SOFn4, "SOFn4" },
88 {FCIP_SOFn2, "SOFn2" },
89 {FCIP_SOFn3, "SOFn3" },
90 {FCIP_SOFc4, "SOFc4" },
94 static const value_string fcencap_proto_vals[] = {
95 {FCENCAP_PROTO_FCIP, "FCIP"},
96 {FCENCAP_PROTO_iFCP, "iFCP"},
100 static const guint8 fcip_header_8_bytes[8] = {
101 0x01, 0x01, 0xFE, 0xFE,
102 0x01, 0x01, 0xFE, 0xFE
105 static int proto_fcip = -1;
107 static int hf_fcip_protocol = -1;
108 static int hf_fcip_protocol_c = -1;
109 static int hf_fcip_version = -1;
110 static int hf_fcip_version_c = -1;
111 static int hf_fcip_encap_word1 = -1;
112 static int hf_fcip_flags = -1;
113 static int hf_fcip_flags_c = -1;
114 static int hf_fcip_framelen = -1;
115 static int hf_fcip_framelen_c = -1;
116 static int hf_fcip_tsec = -1;
117 static int hf_fcip_tusec = -1;
118 static int hf_fcip_encap_crc = -1;
119 static int hf_fcip_sof = -1;
120 static int hf_fcip_sof_c = -1;
121 static int hf_fcip_eof = -1;
122 static int hf_fcip_eof_c = -1;
123 static int hf_fcip_pflags_changed = -1;
124 static int hf_fcip_pflags_special = -1;
125 static int hf_fcip_pflags_c = -1;
126 static int hf_fcip_src_wwn = -1;
127 static int hf_fcip_dst_wwn = -1;
128 static int hf_fcip_conn_code = -1;
129 static int hf_fcip_katov = -1;
130 static int hf_fcip_src_entity_id = -1;
131 static int hf_fcip_conn_nonce = -1;
132 static int hf_fcip_conn_flags = -1;
134 static int ett_fcip = -1;
136 static guint fcip_port = 3225;
137 static gboolean fcip_desegment = TRUE;
139 static dissector_handle_t data_handle;
140 static dissector_handle_t fc_handle;
142 /* This routine attempts to locate the position of the next header in the
146 get_next_fcip_header_offset (tvbuff_t *tvb, packet_info *pinfo, gint offset)
148 gint bytes_remaining = tvb_length_remaining (tvb, offset);
151 fcip_eof_t eof, eofc;
154 * As per the FCIP standard, the following tests must PASS:
155 * 1) Frame Length field validation -- 15 < Frame Length < 545;
156 * 2) Comparison of Frame Length field to its ones complement; and
157 * 3) A valid EOF is found in the word preceding the start of the next
158 * FCIP header as indicated by the Frame Length field, to be tested
160 * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
161 * list of legal EOF values is in the FC Frame Encapsulation
163 * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
164 * value found in bits 24-31.
166 * As per the FCIP standard, in addition, at least 3 of the following set
167 * of tests must be performed to identify that we've located the start of
169 * a) Protocol# ones complement field (1 test);
170 * b) Version ones complement field (1 test);
171 * c) Replication of encapsulation word 0 in word 1 (1 test);
172 * d) Reserved field and its ones complement (2 tests);
173 * e) Flags field and its ones complement (2 tests);
174 * f) CRC field is equal to zero (1 test); (DONT DO THIS TEST!)
175 * g) SOF fields and ones complement fields (4 tests);
176 * h) Format and values of FC header (1 test);
177 * i) CRC of FC Frame (2 tests);
178 * j) FC Frame Encapsulation header information in the next FCIP Frame
181 * At least 3 of the 16 tests listed above SHALL be performed. Failure
182 * of any of the above tests actually performed SHALL indicate an
183 * encapsulation error and the FC Frame SHALL NOT be forwarded on to
187 NXT_BYTE: while (bytes_remaining) {
188 if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
189 if(fcip_desegment && pinfo->can_desegment) {
191 * This frame doesn't have all of the data for
192 * this message, but we can do reassembly on it.
194 * Tell the TCP dissector where the data for this
195 * message starts in the data it handed us, and
196 * how many more bytes we need, and return.
198 pinfo->desegment_offset = offset;
199 pinfo->desegment_len = FCIP_ENCAP_HEADER_LEN;
204 /* I check that we have a valid header before checking for the frame
205 * length and the other initial tests.
211 if (tvb_memeql(tvb, offset, fcip_header_8_bytes, 8) != 0) {
217 flen = (tvb_get_ntohs (tvb, offset+12)) & 0x03FF;
218 frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
220 if ((flen < 15) || (flen > 545)) {
221 /* Frame length check failed. Skip byte and try again */
227 flen1 = (tvb_get_ntohs (tvb, offset+14)) & 0x03FF;
229 if ((flen & 0x03FF) != ((~flen1)&0x03FF)) {
230 /* frame_len and its one's complement are not the same */
236 /* Valid EOF check */
237 if (tvb_bytes_exist (tvb, offset+(frame_len-1)*4, 4)) {
238 eof = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4);
239 eofc = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4+2);
241 if ((eof != FCIP_EOFn) && (eof != FCIP_EOFt) && (eof != FCIP_EOFrt)
242 && (eof != FCIP_EOFdt) && (eof != FCIP_EOFni) &&
243 (eof != FCIP_EOFdti) && (eof != FCIP_EOFrti) &&
244 (eof != FCIP_EOFa)) {
250 if ((eof != ~eofc) ||
251 (eof != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+1)) ||
252 (eofc != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+3))) {
260 if ((tvb_get_guint8 (tvb, offset+9) != 0) ||
261 (tvb_get_guint8 (tvb, offset+11) != 0xFF)) {
272 * We dont test this since some implementations actually provide
276 if (bytes_remaining >= (frame_len)) {
277 if (tvb_bytes_exist (tvb, offset+frame_len, 8)) {
278 /* The start of the next header matches what we wish to see */
279 if (tvb_memeql (tvb, offset+frame_len, fcip_header_8_bytes,
294 if(fcip_desegment && pinfo->can_desegment) {
296 * This frame doesn't have all of the data for
297 * this message, but we can do reassembly on it.
299 * Tell the TCP dissector where the data for this
300 * message starts in the data it handed us, and
301 * how many more bytes we need, and return.
303 pinfo->desegment_offset = offset;
304 pinfo->desegment_len = frame_len - bytes_remaining;
313 return (-1); /* Unable to find FCIP header */
317 dissect_fcencap_header (tvbuff_t *tvb, proto_tree *tree, gint offset)
319 guint8 protocol = tvb_get_guint8 (tvb, offset);
322 proto_tree_add_uint (tree, hf_fcip_protocol, tvb, offset, 1, protocol);
323 proto_tree_add_item (tree, hf_fcip_version, tvb, offset+1, 1, 0);
324 proto_tree_add_item (tree, hf_fcip_protocol_c, tvb, offset+2, 1, 0);
325 proto_tree_add_item (tree, hf_fcip_version_c, tvb, offset+3, 1, 0);
327 if (protocol == FCENCAP_PROTO_FCIP) {
328 proto_tree_add_item (tree, hf_fcip_encap_word1, tvb, offset+4,
330 proto_tree_add_item (tree, hf_fcip_pflags_changed, tvb, offset+8,
332 proto_tree_add_item (tree, hf_fcip_pflags_special, tvb, offset+8,
334 proto_tree_add_item (tree, hf_fcip_pflags_c, tvb, offset+10, 1, 0);
337 /* XXX - break out CRCV flag. */
338 proto_tree_add_item (tree, hf_fcip_flags, tvb, offset+12, 1, 0);
339 proto_tree_add_item (tree, hf_fcip_framelen, tvb, offset+12, 2, 0);
340 proto_tree_add_item (tree, hf_fcip_flags_c, tvb, offset+14, 1, 0);
341 proto_tree_add_item (tree, hf_fcip_framelen_c, tvb, offset+14, 2, 0);
342 proto_tree_add_item (tree, hf_fcip_tsec, tvb, offset+16, 4, 0);
343 proto_tree_add_item (tree, hf_fcip_tusec, tvb, offset+20, 4, 0);
344 /* XXX - check CRC if CRCV is set? */
345 proto_tree_add_item (tree, hf_fcip_encap_crc, tvb, offset+24, 4, 0);
350 dissect_fcip_sf (tvbuff_t *tvb, proto_tree *tree, gint offset)
353 proto_tree_add_string (tree, hf_fcip_src_wwn, tvb, offset, 8,
354 fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
355 proto_tree_add_item (tree, hf_fcip_src_entity_id, tvb, offset+8, 8,
357 proto_tree_add_item (tree, hf_fcip_conn_nonce, tvb, offset+16, 8,
359 /* XXX - break out these flags */
360 proto_tree_add_item (tree, hf_fcip_conn_flags, tvb, offset+24, 1, 0);
361 proto_tree_add_item (tree, hf_fcip_conn_code, tvb, offset+26, 2, 0);
362 proto_tree_add_string (tree, hf_fcip_dst_wwn, tvb, offset+30, 8,
363 fcwwn_to_str (tvb_get_ptr (tvb, offset+30, 8)));
364 proto_tree_add_item (tree, hf_fcip_katov, tvb, offset+38, 4, 0);
369 dissect_fcip (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
375 gint bytes_remaining = tvb_length (tvb);
376 guint8 pflags, sof = 0, eof = 0;
377 /* Set up structures needed to add the protocol subtree and manage it */
379 proto_tree *fcip_tree = NULL;
382 if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
387 ((pinfo->srcport != fcip_port) && (pinfo->destport != fcip_port))) {
391 while (bytes_remaining > FCIP_ENCAP_HEADER_LEN) {
392 if ((offset = get_next_fcip_header_offset (tvb, pinfo, offset)) == -1) {
395 else if (offset == -2) {
396 /* We need more data to desegment */
401 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCIP");
403 frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
405 if (bytes_remaining < frame_len) {
406 if(fcip_desegment && pinfo->can_desegment) {
408 * This frame doesn't have all of the data for
409 * this message, but we can do reassembly on it.
411 * Tell the TCP dissector where the data for this
412 * message starts in the data it handed us, and
413 * how many more bytes we need, and return.
415 pinfo->desegment_offset = offset;
416 pinfo->desegment_len = frame_len - bytes_remaining;
421 pflags = tvb_get_guint8 (tvb, start+8);
424 if (FCIP_IS_SF (pflags)) {
425 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
426 FCIP_ENCAP_HEADER_LEN,
429 else if (tvb_bytes_exist (tvb, offset, offset+frame_len-4)) {
430 sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN);
431 eof = tvb_get_guint8 (tvb, offset+frame_len - 4);
433 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
434 FCIP_ENCAP_HEADER_LEN,
436 val_to_str (sof, fcip_sof_vals,
438 val_to_str (eof, fcip_eof_vals,
442 sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN);
444 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
445 FCIP_ENCAP_HEADER_LEN,
447 val_to_str (sof, fcip_sof_vals,
451 fcip_tree = proto_item_add_subtree (ti, ett_fcip);
452 /* Dissect the Common FC Encap header */
453 dissect_fcencap_header (tvb, fcip_tree, offset);
455 offset += FCIP_ENCAP_HEADER_LEN;
457 if (!FCIP_IS_SF (pflags)) {
459 proto_tree_add_item (fcip_tree, hf_fcip_sof, tvb, offset, 1, 0);
460 proto_tree_add_item (fcip_tree, hf_fcip_sof_c, tvb, offset+2, 1, 0);
463 offset += (frame_len-FCIP_ENCAP_HEADER_LEN-4);
464 if (tvb_bytes_exist (tvb, offset, 4)) {
465 proto_tree_add_item (fcip_tree, hf_fcip_eof, tvb, offset, 1, 0);
466 proto_tree_add_item (fcip_tree, hf_fcip_eof_c, tvb, offset+2, 1, 0);
471 /* Call the FC Dissector if this is carrying an FC frame */
472 if (!FCIP_IS_SF(pflags)) {
473 /* Set the SOF/EOF flags in the packet_info header */
477 if ((sof == FCIP_SOFi3) || (sof == FCIP_SOFi2) || (sof == FCIP_SOFi4)) {
478 pinfo->sof_eof = PINFO_SOF_FIRST_FRAME;
480 else if (sof == FCIP_SOFf) {
481 pinfo->sof_eof = PINFO_SOF_SOFF;
484 if (eof != FCIP_EOFn) {
485 pinfo->sof_eof |= PINFO_EOF_LAST_FRAME;
487 else if (eof != FCIP_EOFt) {
488 pinfo->sof_eof |= PINFO_EOF_INVALID;
492 /* Special frame bit is not set */
493 next_tvb = tvb_new_subset_remaining (tvb, FCIP_ENCAP_HEADER_LEN+4);
495 call_dissector (fc_handle, next_tvb, pinfo, tree);
497 else if (data_handle) {
498 call_dissector (data_handle, next_tvb, pinfo, tree);
502 col_set_str(pinfo->cinfo, COL_INFO, "Special Frame");
503 if (FCIP_IS_CH (pflags)) {
504 col_append_str(pinfo->cinfo, COL_INFO, "(Changed)");
507 dissect_fcip_sf (tvb, fcip_tree, offset+4);
510 bytes_remaining -= frame_len;
516 /* This is called for those sessions where we have explicitely said
517 this to be FCIP using "Decode As..."
518 In this case we will not check the port number for sanity and just
522 dissect_fcip_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
524 dissect_fcip (tvb, pinfo, tree, FALSE);
528 dissect_fcip_heur (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
530 return (dissect_fcip (tvb, pinfo, tree, TRUE));
534 proto_register_fcip (void)
537 /* Setup list of header fields See Section 1.6.1 for details*/
538 static hf_register_info hf[] = {
540 { "Protocol", "fcip.proto", FT_UINT8, BASE_DEC,
541 VALS(fcencap_proto_vals), 0, NULL, HFILL }},
542 { &hf_fcip_protocol_c,
543 {"Protocol (1's Complement)", "fcip.protoc", FT_UINT8, BASE_DEC,
544 NULL, 0, NULL, HFILL}},
546 {"Version", "fcip.version", FT_UINT8, BASE_DEC,
547 NULL, 0, NULL, HFILL}},
548 { &hf_fcip_version_c,
549 {"Version (1's Complement)", "fcip.versionc", FT_UINT8, BASE_DEC,
550 NULL, 0, NULL, HFILL}},
551 { &hf_fcip_encap_word1,
552 {"FCIP Encapsulation Word1", "fcip.encap_word1", FT_UINT32, BASE_HEX,
553 NULL, 0, NULL, HFILL}},
555 {"Flags", "fcip.flags", FT_UINT8, BASE_HEX,
556 NULL, 0xFC, NULL, HFILL}},
558 {"Flags (1's Complement)", "fcip.flagsc", FT_UINT8, BASE_HEX,
559 NULL, 0xFC, NULL, HFILL}},
561 {"Frame Length (in Words)", "fcip.framelen", FT_UINT16, BASE_DEC,
562 NULL, 0x03FF, NULL, HFILL}},
563 { &hf_fcip_framelen_c,
564 {"Frame Length (1's Complement)", "fcip.framelenc", FT_UINT16, BASE_DEC,
565 NULL, 0x03FF, NULL, HFILL}},
567 {"Time (secs)", "fcip.tsec", FT_UINT32, BASE_DEC,
568 NULL, 0, NULL, HFILL}},
570 {"Time (fraction)", "fcip.tusec", FT_UINT32, BASE_DEC,
571 NULL, 0, NULL, HFILL}},
572 { &hf_fcip_encap_crc,
573 {"CRC", "fcip.encap_crc", FT_UINT32, BASE_HEX,
574 NULL, 0, NULL, HFILL}},
576 {"SOF", "fcip.sof", FT_UINT8, BASE_HEX,
577 VALS (&fcip_sof_vals), 0, NULL, HFILL}},
579 {"SOF (1's Complement)", "fcip.sofc", FT_UINT8, BASE_HEX,
580 NULL, 0, NULL, HFILL}},
582 {"EOF", "fcip.eof", FT_UINT8, BASE_HEX,
583 VALS (&fcip_eof_vals), 0, NULL, HFILL}},
585 {"EOF (1's Complement)", "fcip.eofc", FT_UINT8, BASE_HEX,
586 NULL, 0, NULL, HFILL}},
587 { &hf_fcip_pflags_changed,
588 {"Changed Flag", "fcip.pflags.ch", FT_BOOLEAN, 8,
589 NULL, 0x80, NULL, HFILL}},
590 { &hf_fcip_pflags_special,
591 {"Special Frame Flag", "fcip.pflags.sf", FT_BOOLEAN, 8,
592 NULL, 0x1, NULL, HFILL}},
594 {"Pflags (1's Complement)", "fcip.pflagsc", FT_UINT8, BASE_HEX,
595 NULL, 0x0, NULL, HFILL}},
597 {"Source Fabric WWN", "fcip.srcwwn", FT_STRING, BASE_NONE,
598 NULL, 0x0, NULL, HFILL}},
600 {"Destination Fabric WWN", "fcip.dstwwn", FT_STRING, BASE_NONE,
601 NULL, 0x0, NULL, HFILL}},
602 { &hf_fcip_src_entity_id,
603 {"FC/FCIP Entity Id", "fcip.srcid", FT_BYTES, BASE_NONE,
604 NULL, 0x0, NULL, HFILL}},
605 { &hf_fcip_conn_flags,
606 {"Connection Usage Flags", "fcip.connflags", FT_UINT8, BASE_HEX,
607 NULL, 0x0, NULL, HFILL}},
608 { &hf_fcip_conn_code,
609 {"Connection Usage Code", "fcip.conncode", FT_UINT16, BASE_HEX,
610 NULL, 0x0, NULL, HFILL}},
612 {"K_A_TOV", "fcip.katov", FT_UINT32, BASE_DEC,
613 NULL, 0x0, NULL, HFILL}},
614 { &hf_fcip_conn_nonce,
615 {"Connection Nonce", "fcip.nonce", FT_BYTES, BASE_NONE,
616 NULL, 0x0, NULL, HFILL}},
619 static gint *ett[] = {
623 module_t *fcip_module;
625 /* Register the protocol name and description */
626 proto_fcip = proto_register_protocol("FCIP", "Fibre Channel over IP", "fcip");
628 /* Required function calls to register the header fields and
630 proto_register_field_array(proto_fcip, hf, array_length(hf));
631 proto_register_subtree_array(ett, array_length(ett));
633 fcip_module = prefs_register_protocol(proto_fcip, NULL);
634 prefs_register_bool_preference(fcip_module,
636 "Reassemble FCIP messages spanning multiple TCP segments",
637 "Whether the FCIP dissector should reassemble messages spanning multiple TCP segments."
638 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
640 prefs_register_uint_preference(fcip_module,
643 "Port number used for FCIP",
650 * If this dissector uses sub-dissector registration add a
651 * registration routine.
655 * This format is required because a script is used to find these
656 * routines and create the code that calls these routines.
659 proto_reg_handoff_fcip (void)
661 dissector_handle_t fcip_handle;
663 heur_dissector_add("tcp", dissect_fcip_heur, proto_fcip);
665 fcip_handle = create_dissector_handle(dissect_fcip_handle, proto_fcip);
666 dissector_add_handle("tcp.port", fcip_handle);
668 data_handle = find_dissector("data");
669 fc_handle = find_dissector("fc");