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.
37 #include <epan/packet.h>
38 #include <epan/prefs.h>
40 #define FCIP_ENCAP_HEADER_LEN 28
41 #define FCIP_MIN_HEADER_LEN 16 /* upto frame len field */
42 #define FCIP_IS_SF(pflags) ((pflags & 0x1) == 0x1)
43 #define FCIP_IS_CH(pflags) ((pflags & 0x80) == 0x80)
68 FCENCAP_PROTO_FCIP = 1,
69 FCENCAP_PROTO_iFCP = 2
72 static const value_string fcip_eof_vals[] = {
75 {FCIP_EOFrt, "EOFrt" },
76 {FCIP_EOFdt, "EOFdt" },
77 {FCIP_EOFni, "EOFni" },
78 {FCIP_EOFdti, "EOFdti" },
79 {FCIP_EOFrti, "EOFrti" },
84 static const value_string fcip_sof_vals[] = {
86 {FCIP_SOFi4, "SOFi4" },
87 {FCIP_SOFi2, "SOFi2" },
88 {FCIP_SOFi3, "SOFi3" },
89 {FCIP_SOFn4, "SOFn4" },
90 {FCIP_SOFn2, "SOFn2" },
91 {FCIP_SOFn3, "SOFn3" },
92 {FCIP_SOFc4, "SOFc4" },
96 static const value_string fcencap_proto_vals[] = {
97 {FCENCAP_PROTO_FCIP, "FCIP"},
98 {FCENCAP_PROTO_iFCP, "iFCP"},
102 static const guint8 fcip_header_8_bytes[8] = {
103 0x01, 0x01, 0xFE, 0xFE,
104 0x01, 0x01, 0xFE, 0xFE
107 static int proto_fcip = -1;
109 static int hf_fcip_protocol = -1;
110 static int hf_fcip_protocol_c = -1;
111 static int hf_fcip_version = -1;
112 static int hf_fcip_version_c = -1;
113 static int hf_fcip_encap_word1 = -1;
114 static int hf_fcip_flags = -1;
115 static int hf_fcip_flags_c = -1;
116 static int hf_fcip_framelen = -1;
117 static int hf_fcip_framelen_c = -1;
118 static int hf_fcip_tsec = -1;
119 static int hf_fcip_tusec = -1;
120 static int hf_fcip_encap_crc = -1;
121 static int hf_fcip_sof = -1;
122 static int hf_fcip_sof_c = -1;
123 static int hf_fcip_eof = -1;
124 static int hf_fcip_eof_c = -1;
125 static int hf_fcip_pflags_changed = -1;
126 static int hf_fcip_pflags_special = -1;
127 static int hf_fcip_pflags_c = -1;
128 static int hf_fcip_src_wwn = -1;
129 static int hf_fcip_dst_wwn = -1;
130 static int hf_fcip_conn_code = -1;
131 static int hf_fcip_katov = -1;
132 static int hf_fcip_src_entity_id = -1;
133 static int hf_fcip_conn_nonce = -1;
134 static int hf_fcip_conn_flags = -1;
136 static int ett_fcip = -1;
138 static guint fcip_port = 3225;
139 static gboolean fcip_desegment = TRUE;
141 static dissector_handle_t data_handle;
142 static dissector_handle_t fc_handle;
144 /* This routine attempts to locate the position of the next header in the
148 get_next_fcip_header_offset (tvbuff_t *tvb, packet_info *pinfo, gint offset)
150 gint bytes_remaining = tvb_length_remaining (tvb, offset);
153 fcip_eof_t eof, eofc;
156 * As per the FCIP standard, the following tests must PASS:
157 * 1) Frame Length field validation -- 15 < Frame Length < 545;
158 * 2) Comparison of Frame Length field to its ones complement; and
159 * 3) A valid EOF is found in the word preceding the start of the next
160 * FCIP header as indicated by the Frame Length field, to be tested
162 * 1) Bits 24-31 and 16-23 contain identical legal EOF values (the
163 * list of legal EOF values is in the FC Frame Encapsulation
165 * 2) Bits 8-15 and 0-7 contain the ones complement of the EOF
166 * value found in bits 24-31.
168 * As per the FCIP standard, in addition, at least 3 of the following set
169 * of tests must be performed to identify that we've located the start of
171 * a) Protocol# ones complement field (1 test);
172 * b) Version ones complement field (1 test);
173 * c) Replication of encapsulation word 0 in word 1 (1 test);
174 * d) Reserved field and its ones complement (2 tests);
175 * e) Flags field and its ones complement (2 tests);
176 * f) CRC field is equal to zero (1 test); (DONT DO THIS TEST!)
177 * g) SOF fields and ones complement fields (4 tests);
178 * h) Format and values of FC header (1 test);
179 * i) CRC of FC Frame (2 tests);
180 * j) FC Frame Encapsulation header information in the next FCIP Frame
183 * At least 3 of the 16 tests listed above SHALL be performed. Failure
184 * of any of the above tests actually performed SHALL indicate an
185 * encapsulation error and the FC Frame SHALL NOT be forwarded on to
189 NXT_BYTE: while (bytes_remaining) {
190 if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
191 if(fcip_desegment && pinfo->can_desegment) {
193 * This frame doesn't have all of the data for
194 * this message, but we can do reassembly on it.
196 * Tell the TCP dissector where the data for this
197 * message starts in the data it handed us, and
198 * how many more bytes we need, and return.
200 pinfo->desegment_offset = offset;
201 pinfo->desegment_len = FCIP_ENCAP_HEADER_LEN;
206 /* I check that we have a valid header before checking for the frame
207 * length and the other initial tests.
213 if (tvb_memeql(tvb, offset, fcip_header_8_bytes, 8) != 0) {
219 flen = (tvb_get_ntohs (tvb, offset+12)) & 0x03FF;
220 frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
222 if ((flen < 15) || (flen > 545)) {
223 /* Frame length check failed. Skip byte and try again */
229 flen1 = (tvb_get_ntohs (tvb, offset+14)) & 0x03FF;
231 if ((flen & 0x03FF) != ((~flen1)&0x03FF)) {
232 /* frame_len and its one's complement are not the same */
238 /* Valid EOF check */
239 if (tvb_bytes_exist (tvb, offset+(frame_len-1)*4, 4)) {
240 eof = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4);
241 eofc = (fcip_eof_t)tvb_get_guint8 (tvb, offset+(frame_len-1)*4+2);
243 if ((eof != FCIP_EOFn) && (eof != FCIP_EOFt) && (eof != FCIP_EOFrt)
244 && (eof != FCIP_EOFdt) && (eof != FCIP_EOFni) &&
245 (eof != FCIP_EOFdti) && (eof != FCIP_EOFrti) &&
246 (eof != FCIP_EOFa)) {
252 if ((eof != ~eofc) ||
253 (eof != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+1)) ||
254 (eofc != tvb_get_guint8 (tvb, offset+(frame_len-1)*4+3))) {
262 if ((tvb_get_guint8 (tvb, offset+9) != 0) ||
263 (tvb_get_guint8 (tvb, offset+11) != 0xFF)) {
274 * We dont test this since some implementations actually provide
278 if (bytes_remaining >= (frame_len)) {
279 if (tvb_bytes_exist (tvb, offset+frame_len, 8)) {
280 /* The start of the next header matches what we wish to see */
281 if (tvb_memeql (tvb, offset+frame_len, fcip_header_8_bytes,
296 if(fcip_desegment && pinfo->can_desegment) {
298 * This frame doesn't have all of the data for
299 * this message, but we can do reassembly on it.
301 * Tell the TCP dissector where the data for this
302 * message starts in the data it handed us, and
303 * how many more bytes we need, and return.
305 pinfo->desegment_offset = offset;
306 pinfo->desegment_len = frame_len - bytes_remaining;
315 return (-1); /* Unable to find FCIP header */
319 dissect_fcencap_header (tvbuff_t *tvb, proto_tree *tree, gint offset)
321 guint8 protocol = tvb_get_guint8 (tvb, offset);
324 proto_tree_add_uint (tree, hf_fcip_protocol, tvb, offset, 1, protocol);
325 proto_tree_add_item (tree, hf_fcip_version, tvb, offset+1, 1, 0);
326 proto_tree_add_item (tree, hf_fcip_protocol_c, tvb, offset+2, 1, 0);
327 proto_tree_add_item (tree, hf_fcip_version_c, tvb, offset+3, 1, 0);
329 if (protocol == FCENCAP_PROTO_FCIP) {
330 proto_tree_add_item (tree, hf_fcip_encap_word1, tvb, offset+4,
332 proto_tree_add_item (tree, hf_fcip_pflags_changed, tvb, offset+8,
334 proto_tree_add_item (tree, hf_fcip_pflags_special, tvb, offset+8,
336 proto_tree_add_item (tree, hf_fcip_pflags_c, tvb, offset+10, 1, 0);
339 /* XXX - break out CRCV flag. */
340 proto_tree_add_item (tree, hf_fcip_flags, tvb, offset+12, 1, 0);
341 proto_tree_add_item (tree, hf_fcip_framelen, tvb, offset+12, 2, 0);
342 proto_tree_add_item (tree, hf_fcip_flags_c, tvb, offset+14, 1, 0);
343 proto_tree_add_item (tree, hf_fcip_framelen_c, tvb, offset+14, 2, 0);
344 proto_tree_add_item (tree, hf_fcip_tsec, tvb, offset+16, 4, 0);
345 proto_tree_add_item (tree, hf_fcip_tusec, tvb, offset+20, 4, 0);
346 /* XXX - check CRC if CRCV is set? */
347 proto_tree_add_item (tree, hf_fcip_encap_crc, tvb, offset+24, 4, 0);
352 dissect_fcip_sf (tvbuff_t *tvb, proto_tree *tree, gint offset)
355 proto_tree_add_string (tree, hf_fcip_src_wwn, tvb, offset, 8,
356 fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
357 proto_tree_add_bytes (tree, hf_fcip_src_entity_id, tvb, offset+8, 8,
358 tvb_get_ptr (tvb, offset+8, 8));
359 proto_tree_add_bytes (tree, hf_fcip_conn_nonce, tvb, offset+16, 8,
360 tvb_get_ptr (tvb, offset+16, 8));
361 /* XXX - break out these flags */
362 proto_tree_add_item (tree, hf_fcip_conn_flags, tvb, offset+24, 1, 0);
363 proto_tree_add_item (tree, hf_fcip_conn_code, tvb, offset+26, 2, 0);
364 proto_tree_add_string (tree, hf_fcip_dst_wwn, tvb, offset+30, 8,
365 fcwwn_to_str (tvb_get_ptr (tvb, offset+30, 8)));
366 proto_tree_add_item (tree, hf_fcip_katov, tvb, offset+38, 4, 0);
371 dissect_fcip (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
377 gint bytes_remaining = tvb_length (tvb);
378 guint8 pflags, sof = 0, eof = 0;
379 /* Set up structures needed to add the protocol subtree and manage it */
381 proto_tree *fcip_tree = NULL;
384 if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) {
389 ((pinfo->srcport != fcip_port) && (pinfo->destport != fcip_port))) {
393 while (bytes_remaining > FCIP_ENCAP_HEADER_LEN) {
394 if ((offset = get_next_fcip_header_offset (tvb, pinfo, offset)) == -1) {
397 else if (offset == -2) {
398 /* We need more data to desegment */
403 if (check_col(pinfo->cinfo, COL_PROTOCOL))
404 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCIP");
406 frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4;
408 if (bytes_remaining < frame_len) {
409 if(fcip_desegment && pinfo->can_desegment) {
411 * This frame doesn't have all of the data for
412 * this message, but we can do reassembly on it.
414 * Tell the TCP dissector where the data for this
415 * message starts in the data it handed us, and
416 * how many more bytes we need, and return.
418 pinfo->desegment_offset = offset;
419 pinfo->desegment_len = frame_len - bytes_remaining;
424 pflags = tvb_get_guint8 (tvb, start+8);
427 if (FCIP_IS_SF (pflags)) {
428 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
429 FCIP_ENCAP_HEADER_LEN,
432 else if (tvb_bytes_exist (tvb, offset, offset+frame_len-4)) {
433 sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN);
434 eof = tvb_get_guint8 (tvb, offset+frame_len - 4);
436 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
437 FCIP_ENCAP_HEADER_LEN,
439 val_to_str (sof, fcip_sof_vals,
441 val_to_str (eof, fcip_eof_vals,
445 sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN);
447 ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0,
448 FCIP_ENCAP_HEADER_LEN,
450 val_to_str (sof, fcip_sof_vals,
454 fcip_tree = proto_item_add_subtree (ti, ett_fcip);
455 /* Dissect the Common FC Encap header */
456 dissect_fcencap_header (tvb, fcip_tree, offset);
458 offset += FCIP_ENCAP_HEADER_LEN;
460 if (!FCIP_IS_SF (pflags)) {
462 proto_tree_add_item (fcip_tree, hf_fcip_sof, tvb, offset, 1, 0);
463 proto_tree_add_item (fcip_tree, hf_fcip_sof_c, tvb, offset+2, 1, 0);
466 offset += (frame_len-FCIP_ENCAP_HEADER_LEN-4);
467 if (tvb_bytes_exist (tvb, offset, 4)) {
468 proto_tree_add_item (fcip_tree, hf_fcip_eof, tvb, offset, 1, 0);
469 proto_tree_add_item (fcip_tree, hf_fcip_eof_c, tvb, offset+2, 1, 0);
474 /* Call the FC Dissector if this is carrying an FC frame */
475 if (!FCIP_IS_SF(pflags)) {
476 /* Set the SOF/EOF flags in the packet_info header */
480 if ((sof == FCIP_SOFi3) || (sof == FCIP_SOFi2) || (sof == FCIP_SOFi4)) {
481 pinfo->sof_eof = PINFO_SOF_FIRST_FRAME;
483 else if (sof == FCIP_SOFf) {
484 pinfo->sof_eof = PINFO_SOF_SOFF;
487 if (eof != FCIP_EOFn) {
488 pinfo->sof_eof |= PINFO_EOF_LAST_FRAME;
490 else if (eof != FCIP_EOFt) {
491 pinfo->sof_eof |= PINFO_EOF_INVALID;
495 /* Special frame bit is not set */
496 next_tvb = tvb_new_subset (tvb, FCIP_ENCAP_HEADER_LEN+4, -1, -1);
498 call_dissector (fc_handle, next_tvb, pinfo, tree);
500 else if (data_handle) {
501 call_dissector (data_handle, next_tvb, pinfo, tree);
505 if (check_col(pinfo->cinfo, COL_INFO))
506 col_set_str(pinfo->cinfo, COL_INFO, "Special Frame");
507 if (FCIP_IS_CH (pflags)) {
508 if (check_col(pinfo->cinfo, COL_INFO))
509 col_append_str(pinfo->cinfo, COL_INFO, "(Changed)");
512 dissect_fcip_sf (tvb, fcip_tree, offset+4);
515 bytes_remaining -= frame_len;
521 /* This is called for those sessions where we have explicitely said
522 this to be FCIP using "Decode As..."
523 In this case we will not check the port number for sanity and just
527 dissect_fcip_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
529 dissect_fcip (tvb, pinfo, tree, FALSE);
533 dissect_fcip_heur (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
535 return (dissect_fcip (tvb, pinfo, tree, TRUE));
539 proto_register_fcip (void)
542 /* Setup list of header fields See Section 1.6.1 for details*/
543 static hf_register_info hf[] = {
545 { "Protocol", "fcip.proto", FT_UINT8, BASE_DEC,
546 VALS(fcencap_proto_vals), 0, NULL, HFILL }},
547 { &hf_fcip_protocol_c,
548 {"Protocol (1's Complement)", "fcip.protoc", FT_UINT8, BASE_DEC,
549 NULL, 0, NULL, HFILL}},
551 {"Version", "fcip.version", FT_UINT8, BASE_DEC,
552 NULL, 0, NULL, HFILL}},
553 { &hf_fcip_version_c,
554 {"Version (1's Complement)", "fcip.versionc", FT_UINT8, BASE_DEC,
555 NULL, 0, NULL, HFILL}},
556 { &hf_fcip_encap_word1,
557 {"FCIP Encapsulation Word1", "fcip.encap_word1", FT_UINT32, BASE_HEX,
558 NULL, 0, NULL, HFILL}},
560 {"Flags", "fcip.flags", FT_UINT8, BASE_HEX,
561 NULL, 0xFC, NULL, HFILL}},
563 {"Flags (1's Complement)", "fcip.flagsc", FT_UINT8, BASE_HEX,
564 NULL, 0xFC, NULL, HFILL}},
566 {"Frame Length (in Words)", "fcip.framelen", FT_UINT16, BASE_DEC,
567 NULL, 0x03FF, NULL, HFILL}},
568 { &hf_fcip_framelen_c,
569 {"Frame Length (1's Complement)", "fcip.framelenc", FT_UINT16, BASE_DEC,
570 NULL, 0x03FF, NULL, HFILL}},
572 {"Time (secs)", "fcip.tsec", FT_UINT32, BASE_DEC,
573 NULL, 0, NULL, HFILL}},
575 {"Time (fraction)", "fcip.tusec", FT_UINT32, BASE_DEC,
576 NULL, 0, NULL, HFILL}},
577 { &hf_fcip_encap_crc,
578 {"CRC", "fcip.encap_crc", FT_UINT32, BASE_HEX,
579 NULL, 0, NULL, HFILL}},
581 {"SOF", "fcip.sof", FT_UINT8, BASE_HEX,
582 VALS (&fcip_sof_vals), 0, NULL, HFILL}},
584 {"SOF (1's Complement)", "fcip.sofc", FT_UINT8, BASE_HEX,
585 NULL, 0, NULL, HFILL}},
587 {"EOF", "fcip.eof", FT_UINT8, BASE_HEX,
588 VALS (&fcip_eof_vals), 0, NULL, HFILL}},
590 {"EOF (1's Complement)", "fcip.eofc", FT_UINT8, BASE_HEX,
591 NULL, 0, NULL, HFILL}},
592 { &hf_fcip_pflags_changed,
593 {"Changed Flag", "fcip.pflags.ch", FT_BOOLEAN, 8,
594 NULL, 0x80, NULL, HFILL}},
595 { &hf_fcip_pflags_special,
596 {"Special Frame Flag", "fcip.pflags.sf", FT_BOOLEAN, 8,
597 NULL, 0x1, NULL, HFILL}},
599 {"Pflags (1's Complement)", "fcip.pflagsc", FT_UINT8, BASE_HEX,
600 NULL, 0x0, NULL, HFILL}},
602 {"Source Fabric WWN", "fcip.srcwwn", FT_STRING, BASE_NONE,
603 NULL, 0x0, NULL, HFILL}},
605 {"Destination Fabric WWN", "fcip.dstwwn", FT_STRING, BASE_NONE,
606 NULL, 0x0, NULL, HFILL}},
607 { &hf_fcip_src_entity_id,
608 {"FC/FCIP Entity Id", "fcip.srcid", FT_BYTES, BASE_NONE,
609 NULL, 0x0, NULL, HFILL}},
610 { &hf_fcip_conn_flags,
611 {"Connection Usage Flags", "fcip.connflags", FT_UINT8, BASE_HEX,
612 NULL, 0x0, NULL, HFILL}},
613 { &hf_fcip_conn_code,
614 {"Connection Usage Code", "fcip.conncode", FT_UINT16, BASE_HEX,
615 NULL, 0x0, NULL, HFILL}},
617 {"K_A_TOV", "fcip.katov", FT_UINT32, BASE_DEC,
618 NULL, 0x0, NULL, HFILL}},
619 { &hf_fcip_conn_nonce,
620 {"Connection Nonce", "fcip.nonce", FT_BYTES, BASE_NONE,
621 NULL, 0x0, NULL, HFILL}},
624 static gint *ett[] = {
628 module_t *fcip_module;
630 /* Register the protocol name and description */
631 proto_fcip = proto_register_protocol("FCIP", "Fibre Channel over IP", "fcip");
633 /* Required function calls to register the header fields and
635 proto_register_field_array(proto_fcip, hf, array_length(hf));
636 proto_register_subtree_array(ett, array_length(ett));
638 fcip_module = prefs_register_protocol(proto_fcip, NULL);
639 prefs_register_bool_preference(fcip_module,
641 "Reassemble FCIP messages spanning multiple TCP segments",
642 "Whether the FCIP dissector should reassemble messages spanning multiple TCP segments."
643 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
645 prefs_register_uint_preference(fcip_module,
648 "Port number used for FCIP",
655 * If this dissector uses sub-dissector registration add a
656 * registration routine.
660 * This format is required because a script is used to find these
661 * routines and create the code that calls these routines.
664 proto_reg_handoff_fcip (void)
666 dissector_handle_t fcip_handle;
668 heur_dissector_add("tcp", dissect_fcip_heur, proto_fcip);
670 fcip_handle = create_dissector_handle(dissect_fcip_handle, proto_fcip);
671 dissector_add_handle("tcp.port", fcip_handle);
673 data_handle = find_dissector("data");
674 fc_handle = find_dissector("fc");