2 * Routines for Fibre Channel Decoding (FC Header, Link Ctl & Basic Link Svc)
3 * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
4 * Copyright 2003 Ronnie Sahlberg, exchange first/last matching and
5 * tap listener and misc updates
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/exceptions.h>
32 #include <epan/prefs.h>
33 #include <epan/to_str.h>
34 #include <wiretap/wtap.h>
35 #include <epan/reassemble.h>
36 #include <epan/conversation.h>
37 #include <epan/etypes.h>
38 #include "packet-fc.h"
39 #include "packet-fclctl.h"
40 #include "packet-fcbls.h"
42 #include <epan/wmem/wmem.h>
43 #include <epan/crc32-tvb.h>
44 #include <epan/expert.h>
46 void proto_register_fc(void);
47 void proto_reg_handoff_fc(void);
49 #define FC_HEADER_SIZE 24
50 #define FC_RCTL_VFT 0x50
51 #define MDSHDR_TRAILER_SIZE 6
53 /* Size of various fields in FC header in bytes */
54 #define FC_RCTL_SIZE 1
56 #define FC_CSCTL_SIZE 1
58 #define FC_TYPE_SIZE 1
59 #define FC_FCTL_SIZE 3
60 #define FC_SEQID_SIZE 1
61 #define FC_DFCTL_SIZE 1
62 #define FC_SEQCNT_SIZE 2
63 #define FC_OXID_SIZE 2
64 #define FC_RXID_SIZE 2
65 #define FC_PARAM_SIZE 4
67 /* Initialize the protocol and registered fields */
68 static int proto_fc = -1;
69 static int hf_fc_time = -1;
70 static int hf_fc_exchange_first_frame = -1;
71 static int hf_fc_exchange_last_frame = -1;
72 static int hf_fc_rctl = -1;
73 static int hf_fc_did = -1;
74 static int hf_fc_csctl = -1;
75 static int hf_fc_sid = -1;
76 static int hf_fc_id = -1;
77 static int hf_fc_type = -1;
78 static int hf_fc_fctl = -1;
79 static int hf_fc_fctl_exchange_responder = -1;
80 static int hf_fc_fctl_seq_recipient = -1;
81 static int hf_fc_fctl_exchange_first = -1;
82 static int hf_fc_fctl_exchange_last = -1;
83 static int hf_fc_fctl_seq_last = -1;
84 static int hf_fc_fctl_priority = -1;
85 static int hf_fc_fctl_transfer_seq_initiative = -1;
86 static int hf_fc_fctl_rexmitted_seq = -1;
87 static int hf_fc_fctl_rel_offset = -1;
88 static int hf_fc_fctl_abts_ack = -1;
89 /* static int hf_fc_fctl_abts_not_ack = -1; */
90 static int hf_fc_fctl_last_data_frame = -1;
91 static int hf_fc_fctl_ack_0_1 = -1;
92 static int hf_fc_seqid = -1;
93 static int hf_fc_dfctl = -1;
94 static int hf_fc_seqcnt = -1;
95 static int hf_fc_oxid = -1;
96 static int hf_fc_rxid = -1;
97 static int hf_fc_param = -1;
98 static int hf_fc_ftype = -1; /* Derived field, non-existent in FC hdr */
99 static int hf_fc_reassembled = -1;
100 static int hf_fc_relative_offset = -1;
103 static int hf_fc_vft = -1;
104 static int hf_fc_vft_rctl = -1;
105 static int hf_fc_vft_ver = -1;
106 static int hf_fc_vft_type = -1;
107 static int hf_fc_vft_pri = -1;
108 static int hf_fc_vft_vf_id = -1;
109 static int hf_fc_vft_hop_ct = -1;
111 /* Network_Header fields */
112 static int hf_fc_nh_da = -1;
113 static int hf_fc_nh_sa = -1;
115 /* For Basic Link Svc */
116 static int hf_fc_bls_seqid_vld = -1;
117 static int hf_fc_bls_lastvld_seqid = -1;
118 static int hf_fc_bls_oxid = -1;
119 static int hf_fc_bls_rxid = -1;
120 static int hf_fc_bls_lowseqcnt = -1;
121 static int hf_fc_bls_hiseqcnt = -1;
122 static int hf_fc_bls_rjtcode = -1;
123 static int hf_fc_bls_rjtdetail = -1;
124 static int hf_fc_bls_vendor = -1;
127 static int proto_fcsof = -1;
129 static int hf_fcsof = -1;
130 static int hf_fceof = -1;
131 static int hf_fccrc = -1;
133 static int ett_fcsof = -1;
134 static int ett_fceof = -1;
135 static int ett_fccrc = -1;
138 /* Initialize the subtree pointers */
139 static gint ett_fc = -1;
140 static gint ett_fctl = -1;
141 static gint ett_fcbls = -1;
142 static gint ett_fc_vft = -1;
144 static expert_field ei_fccrc = EI_INIT;
146 static dissector_handle_t fc_handle, fcsof_handle;
147 static dissector_table_t fcftype_dissector_table;
149 static dissector_handle_t data_handle;
151 static int fc_tap = -1;
153 typedef struct _fc_conv_data_t {
154 wmem_tree_t *exchanges;
158 /* Reassembly stuff */
159 static gboolean fc_reassemble = TRUE;
160 static guint32 fc_max_frame_size = 1024;
161 static reassembly_table fc_reassembly_table;
163 typedef struct _fcseq_conv_key {
167 typedef struct _fcseq_conv_data {
171 static GHashTable *fcseq_req_hash = NULL;
177 fcseq_equal(gconstpointer v, gconstpointer w)
179 const fcseq_conv_key_t *v1 = (const fcseq_conv_key_t *)v;
180 const fcseq_conv_key_t *v2 = (const fcseq_conv_key_t *)w;
182 return (v1->conv_idx == v2->conv_idx);
186 fcseq_hash (gconstpointer v)
188 const fcseq_conv_key_t *key = (const fcseq_conv_key_t *)v;
197 fc_exchange_init_protocol(void)
199 reassembly_table_init(&fc_reassembly_table,
200 &addresses_reassembly_table_functions);
203 g_hash_table_destroy(fcseq_req_hash);
205 fcseq_req_hash = g_hash_table_new(fcseq_hash, fcseq_equal);
209 const value_string fc_fc4_val[] = {
210 {FC_TYPE_BLS, "Basic Link Svc"},
211 {FC_TYPE_ELS, "Ext Link Svc"},
212 {FC_TYPE_LLCSNAP, "LLC_SNAP"},
213 {FC_TYPE_IP, "IP/FC"},
214 {FC_TYPE_SCSI, "FCP"},
215 {FC_TYPE_FCCT, "FC_CT"},
216 {FC_TYPE_SWILS, "SW_ILS"},
218 {FC_TYPE_SNMP, "SNMP"},
219 {FC_TYPE_SB_FROM_CU, "SB-3(CU->Channel)"},
220 {FC_TYPE_SB_TO_CU, "SB-3(Channel->CU)"},
224 static const value_string fc_ftype_vals [] = {
225 {FC_FTYPE_UNDEF , "Unknown frame"},
226 {FC_FTYPE_SWILS, "SW_ILS"},
227 {FC_FTYPE_IP , "IP/FC"},
228 {FC_FTYPE_SCSI , "FCP"},
229 {FC_FTYPE_BLS , "Basic Link Svc"},
230 {FC_FTYPE_ELS , "ELS"},
231 {FC_FTYPE_FCCT , "FC_CT"},
232 {FC_FTYPE_LINKDATA, "Link Data"},
233 {FC_FTYPE_VDO, "Video Data"},
234 {FC_FTYPE_LINKCTL, "Link Ctl"},
235 {FC_FTYPE_SBCCS, "SBCCS"},
236 {FC_FTYPE_OHMS, "OHMS(Cisco MDS)"},
240 static const value_string fc_wka_vals[] _U_ = {
241 {FC_WKA_MULTICAST, "Multicast Server"},
242 {FC_WKA_CLKSYNC, "Clock Sync Server"},
243 {FC_WKA_KEYDIST, "Key Distribution Server"},
244 {FC_WKA_ALIAS, "Alias Server"},
245 {FC_WKA_QOSF, "QoS Facilitator"},
246 {FC_WKA_MGMT, "Management Server"},
247 {FC_WKA_TIME, "Time Server"},
248 {FC_WKA_DNS, "Directory Server"},
249 {FC_WKA_FABRIC_CTRLR, "Fabric Ctlr"},
250 {FC_WKA_FPORT, "F_Port Server"},
251 {FC_WKA_BCAST, "Broadcast ID"},
255 static const value_string fc_routing_val[] = {
256 {FC_RCTL_DEV_DATA, "Device_Data"},
257 {FC_RCTL_ELS, "Extended Link Services"},
258 {FC_RCTL_LINK_DATA, "FC-4 Link_Data"},
259 {FC_RCTL_VIDEO, "Video_Data"},
260 {FC_RCTL_BLS, "Basic Link Services"},
261 {FC_RCTL_LINK_CTL, "Link_Control Frame"},
265 static const value_string fc_iu_val[] = {
266 {FC_IU_UNCATEGORIZED , "Uncategorized Data"},
267 {FC_IU_SOLICITED_DATA , "Solicited Data"},
268 {FC_IU_UNSOLICITED_CTL , "Unsolicited Control"},
269 {FC_IU_SOLICITED_CTL , "Solicited Control"},
270 {FC_IU_UNSOLICITED_DATA, "Solicited Data"},
271 {FC_IU_DATA_DESCRIPTOR , "Data Descriptor"},
272 {FC_IU_UNSOLICITED_CMD , "Unsolicited Command"},
273 {FC_IU_CMD_STATUS , "Command Status"},
279 #define FC_SOFC1 0xBCB51717
280 #define FC_SOFI1 0xBCB55757
281 #define FC_SOFN1 0xBCB53737
282 #define FC_SOFI2 0xBCB55555
283 #define FC_SOFN2 0xBCB53535
284 #define FC_SOFI3 0xBCB55656
285 #define FC_SOFN3 0xBCB53636
286 #define FC_SOFC4 0xBCB51919
287 #define FC_SOFI4 0xBCB55959
288 #define FC_SOFN4 0xBCB53939
289 #define FC_SOFF 0xBCB55858
291 #define EOFT_NEG 0xBC957575
292 #define EOFT_POS 0xBCB57575
293 #define EOFDT_NEG 0xBC959595
294 #define EOFDT_POS 0xBCB59595
295 #define EOFA_NEG 0xBC95F5F5
296 #define EOFA_POS 0xBCB5F5F5
297 #define EOFN_NEG 0xBC95D5D5
298 #define EOFN_POS 0xBCB5D5D5
299 #define EOFNI_NEG 0xBC8AD5D5
300 #define EOFNI_POS 0xBCAAD5D5
301 #define EOFDTI_NEG 0xBC8A9595
302 #define EOFDTI_POS 0xBCAA9595
303 #define EOFRT_NEG 0xBC959999
304 #define EOFRT_POS 0xBCB59999
305 #define EOFRTI_NEG 0xBC8A9999
306 #define EOFRTI_POS 0xBCAA9999
308 static const value_string fc_sof_vals[] = {
309 {FC_SOFC1, "SOFc1 - SOF Connect Class 1 (Obsolete)" },
310 {FC_SOFI1, "SOFi1 - SOF Initiate Class 1 (Obsolete)" },
311 {FC_SOFN1, "SOFn1 - SOF Normal Class 1 (Obsolete)" },
312 {FC_SOFI2, "SOFi2 - SOF Initiate Class 2" },
313 {FC_SOFN2, "SOFn2 - SOF Normal Class 2" },
314 {FC_SOFI3, "SOFi3 - SOF Initiate Class 3" },
315 {FC_SOFN3, "SOFn3 - SOF Normal Class 3" },
316 {FC_SOFC4, "SOFc4 - SOF Activate Class 4 (Obsolete)" },
317 {FC_SOFI4, "SOFi4 - SOF Initiate Class 4 (Obsolete)" },
318 {FC_SOFN4, "SOFn4 - SOF Normal Class 4 (Obsolete)" },
319 {FC_SOFF, "SOFf - SOF Fabric" },
323 static const value_string fc_eof_vals[] = {
324 {EOFT_NEG, "EOFt- - EOF Terminate" },
325 {EOFT_POS, "EOFt+ - EOF Terminate" },
326 {EOFDT_NEG, "EOFdt- - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
327 {EOFDT_POS, "EOFdt+ - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
328 {EOFA_NEG, "EOFa- - EOF Abort" },
329 {EOFA_POS, "EOFa+ - EOF Abort" },
330 {EOFN_NEG, "EOFn- - EOF Normal" },
331 {EOFN_POS, "EOFn+ - EOF Normal" },
332 {EOFNI_NEG, "EOFni- - EOF Normal Invalid" },
333 {EOFNI_POS, "EOFni+ - EOF Normal Invalid" },
334 {EOFDTI_NEG, "EOFdti- - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
335 {EOFDTI_POS, "EOFdti+ - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
336 {EOFRT_NEG, "EOFrt- - EOF Remove-Terminate Class 4 (Obsolete)" },
337 {EOFRT_POS, "EOFrt+ - EOF Remove-Terminate Class 4 (Obsolete)" },
338 {EOFRTI_NEG, "EOFrti- - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
339 {EOFRTI_POS, "EOFrti+ - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
343 /* BA_ACC & BA_RJT are decoded in this file itself instead of a traditional
344 * dedicated file and dissector format because the dissector would require some
345 * fields of the FC_HDR such as param in some cases, type in some others, the
346 * lower 4 bits of r_ctl in some other cases etc. So, we decode BLS & Link Ctl
347 * in this file itself.
350 dissect_fc_ba_acc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
352 /* Set up structures needed to add the protocol subtree and manage it */
354 proto_tree *acc_tree;
357 /* Make entries in Protocol column and Info column on summary display */
358 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
360 col_set_str(pinfo->cinfo, COL_INFO, "BA_ACC");
363 ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
364 acc_tree = proto_item_add_subtree (ti, ett_fcbls);
366 proto_tree_add_item (acc_tree, hf_fc_bls_seqid_vld, tvb, offset++, 1, ENC_BIG_ENDIAN);
367 proto_tree_add_item (acc_tree, hf_fc_bls_lastvld_seqid, tvb, offset++, 1, ENC_BIG_ENDIAN);
368 offset += 2; /* Skip reserved field */
369 proto_tree_add_item (acc_tree, hf_fc_bls_oxid, tvb, offset, 2, ENC_BIG_ENDIAN);
371 proto_tree_add_item (acc_tree, hf_fc_bls_rxid, tvb, offset, 2, ENC_BIG_ENDIAN);
373 proto_tree_add_item (acc_tree, hf_fc_bls_lowseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
375 proto_tree_add_item (acc_tree, hf_fc_bls_hiseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
380 dissect_fc_ba_rjt (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
382 /* Set up structures needed to add the protocol subtree and manage it */
384 proto_tree *rjt_tree;
387 /* Make entries in Protocol column and Info column on summary display */
388 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
390 col_set_str(pinfo->cinfo, COL_INFO, "BA_RJT");
393 ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
394 rjt_tree = proto_item_add_subtree (ti, ett_fcbls);
396 proto_tree_add_item (rjt_tree, hf_fc_bls_rjtcode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
397 proto_tree_add_item (rjt_tree, hf_fc_bls_rjtdetail, tvb, offset+2, 1, ENC_BIG_ENDIAN);
398 proto_tree_add_item (rjt_tree, hf_fc_bls_vendor, tvb, offset+3, 1, ENC_BIG_ENDIAN);
403 fc_get_ftype (guint8 r_ctl, guint8 type)
405 /* A simple attempt to determine the upper level protocol based on the
406 * r_ctl & type fields.
408 switch (r_ctl & 0xF0) {
409 case FC_RCTL_DEV_DATA:
412 if ((r_ctl == 0x2) || (r_ctl == 0x3))
413 return FC_FTYPE_SWILS;
415 return FC_FTYPE_UNDEF;
419 return FC_FTYPE_SCSI;
421 return FC_FTYPE_FCCT;
422 case FC_TYPE_SB_FROM_CU:
423 case FC_TYPE_SB_TO_CU:
424 return FC_FTYPE_SBCCS;
426 return FC_FTYPE_OHMS;
428 return FC_FTYPE_UNDEF;
431 if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3))
433 else if (type == FC_TYPE_ELS)
434 return FC_FTYPE_OHMS;
436 return FC_FTYPE_UNDEF;
437 case FC_RCTL_LINK_DATA:
440 return FC_FTYPE_SCSI;
442 return FC_FTYPE_LINKDATA;
450 return FC_FTYPE_UNDEF;
451 case FC_RCTL_LINK_CTL:
452 return FC_FTYPE_LINKCTL;
454 return FC_FTYPE_UNDEF;
458 static const value_string abts_ack_vals[] = {
459 {0x000000, "ABTS - Cont"},
460 {0x000010, "ABTS - Abort"},
461 {0x000020, "ABTS - Stop"},
462 {0x000030, "ABTS - Imm Seq Retx"},
466 static const value_string abts_not_ack_vals[] = {
467 {0x000000, "ABTS - Abort/MS"},
468 {0x000010, "ABTS - Abort/SS"},
469 {0x000020, "ABTS - Process/IB"},
470 {0x000030, "ABTS - Discard/MS/Imm Retx"},
474 static const value_string last_data_frame_vals[] = {
475 {0x000000, "Last Data Frame - No Info"},
476 {0x004000, "Last Data Frame - Seq Imm"},
477 {0x008000, "Last Data Frame - Seq Soon"},
478 {0x00c000, "Last Data Frame - Seq Delyd"},
481 static const value_string ack_0_1_vals[] = {
482 {0x003000, "ACK_0 Required"},
483 {0x002000, "ACK_0 Required"},
484 {0x001000, "ACK_1 Required"},
485 {0x000000, "no ack required"},
488 static const true_false_string tfs_fc_fctl_exchange_responder = {
489 "Exchange Responder",
490 "Exchange Originator"
492 static const true_false_string tfs_fc_fctl_seq_recipient = {
496 static const true_false_string tfs_fc_fctl_exchange_first = {
500 static const true_false_string tfs_fc_fctl_exchange_last = {
504 static const true_false_string tfs_fc_fctl_seq_last = {
508 static const true_false_string tfs_fc_fctl_priority = {
512 static const true_false_string tfs_fc_fctl_transfer_seq_initiative = {
513 "Transfer Seq Initiative",
514 "NOT transfer seq initiative"
516 static const true_false_string tfs_fc_fctl_rexmitted_seq = {
517 "Retransmitted Sequence",
518 "NOT retransmitted sequence"
520 static const true_false_string tfs_fc_fctl_rel_offset = {
526 * Dissect the VFT header.
529 dissect_fc_vft(proto_tree *parent_tree,
530 tvbuff_t *tvb, int offset)
532 proto_item *item = NULL;
533 proto_tree *tree = NULL;
541 rctl = tvb_get_guint8(tvb, offset);
542 type = tvb_get_guint8(tvb, offset + 1);
543 ver = (type >> 6) & 3;
544 type = (type >> 2) & 0xf;
545 vf_id = tvb_get_ntohs(tvb, offset + 2);
546 pri = (vf_id >> 13) & 7;
547 vf_id = (vf_id >> 1) & 0xfff;
548 hop_ct = tvb_get_guint8(tvb, offset + 4);
551 item = proto_tree_add_uint_format_value(parent_tree, hf_fc_vft, tvb, offset,
552 8, vf_id, "VF_ID %d Pri %d Hop Count %d",
554 tree = proto_item_add_subtree(item, ett_fc_vft);
556 proto_tree_add_uint(tree, hf_fc_vft_rctl, tvb, offset, 1, rctl);
557 proto_tree_add_uint(tree, hf_fc_vft_ver, tvb, offset + 1, 1, ver);
558 proto_tree_add_uint(tree, hf_fc_vft_type, tvb, offset + 1, 1, type);
559 proto_tree_add_uint(tree, hf_fc_vft_pri, tvb, offset + 2, 1, pri);
560 proto_tree_add_uint(tree, hf_fc_vft_vf_id, tvb, offset + 2, 2, vf_id);
561 proto_tree_add_uint(tree, hf_fc_vft_hop_ct, tvb, offset + 4, 1, hop_ct);
564 /* code to dissect the F_CTL bitmask */
566 dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset)
568 proto_item *item=NULL;
569 proto_tree *tree=NULL;
572 flags = tvb_get_guint8 (tvb, offset);
573 flags = (flags<<8) | tvb_get_guint8 (tvb, offset+1);
574 flags = (flags<<8) | tvb_get_guint8 (tvb, offset+2);
577 item=proto_tree_add_uint(parent_tree, hf_fc_fctl, tvb, offset, 3, flags);
578 tree=proto_item_add_subtree(item, ett_fctl);
581 proto_tree_add_boolean(tree, hf_fc_fctl_exchange_responder, tvb, offset, 3, flags);
582 if (flags&FC_FCTL_EXCHANGE_RESPONDER){
583 proto_item_append_text(item, " Exchange Responder");
584 if (flags & (~( FC_FCTL_EXCHANGE_RESPONDER )))
585 proto_item_append_text(item, ",");
587 proto_item_append_text(item, " Exchange Originator");
588 if (flags & (~( FC_FCTL_EXCHANGE_RESPONDER )))
589 proto_item_append_text(item, ",");
591 flags&=(~( FC_FCTL_EXCHANGE_RESPONDER ));
593 proto_tree_add_boolean(tree, hf_fc_fctl_seq_recipient, tvb, offset, 3, flags);
594 if (flags&FC_FCTL_SEQ_RECIPIENT){
595 proto_item_append_text(item, " Seq Recipient");
596 if (flags & (~( FC_FCTL_SEQ_RECIPIENT )))
597 proto_item_append_text(item, ",");
599 proto_item_append_text(item, " Seq Initiator");
600 if (flags & (~( FC_FCTL_SEQ_RECIPIENT )))
601 proto_item_append_text(item, ",");
603 flags&=(~( FC_FCTL_SEQ_RECIPIENT ));
605 proto_tree_add_boolean(tree, hf_fc_fctl_exchange_first, tvb, offset, 3, flags);
606 if (flags&FC_FCTL_EXCHANGE_FIRST){
607 proto_item_append_text(item, " Exchg First");
608 if (flags & (~( FC_FCTL_EXCHANGE_FIRST )))
609 proto_item_append_text(item, ",");
611 flags&=(~( FC_FCTL_EXCHANGE_FIRST ));
613 proto_tree_add_boolean(tree, hf_fc_fctl_exchange_last, tvb, offset, 3, flags);
614 if (flags&FC_FCTL_EXCHANGE_LAST){
615 proto_item_append_text(item, " Exchg Last");
616 if (flags & (~( FC_FCTL_EXCHANGE_LAST )))
617 proto_item_append_text(item, ",");
619 flags&=(~( FC_FCTL_EXCHANGE_LAST ));
621 proto_tree_add_boolean(tree, hf_fc_fctl_seq_last, tvb, offset, 3, flags);
622 if (flags&FC_FCTL_SEQ_LAST){
623 proto_item_append_text(item, " Seq Last");
624 if (flags & (~( FC_FCTL_SEQ_LAST )))
625 proto_item_append_text(item, ",");
627 flags&=(~( FC_FCTL_SEQ_LAST ));
629 proto_tree_add_boolean(tree, hf_fc_fctl_priority, tvb, offset, 3, flags);
630 if (flags&FC_FCTL_PRIORITY){
631 proto_item_append_text(item, " Priority");
632 if (flags & (~( FC_FCTL_PRIORITY )))
633 proto_item_append_text(item, ",");
635 proto_item_append_text(item, " CS_CTL");
636 if (flags & (~( FC_FCTL_PRIORITY )))
637 proto_item_append_text(item, ",");
639 flags&=(~( FC_FCTL_PRIORITY ));
641 proto_tree_add_boolean(tree, hf_fc_fctl_transfer_seq_initiative, tvb, offset, 3, flags);
642 if (flags&FC_FCTL_TRANSFER_SEQ_INITIATIVE){
643 proto_item_append_text(item, " Transfer Seq Initiative");
644 if (flags & (~( FC_FCTL_TRANSFER_SEQ_INITIATIVE )))
645 proto_item_append_text(item, ",");
647 flags&=(~( FC_FCTL_TRANSFER_SEQ_INITIATIVE ));
649 proto_tree_add_uint(tree, hf_fc_fctl_last_data_frame, tvb, offset, 3, flags);
651 proto_tree_add_uint(tree, hf_fc_fctl_ack_0_1, tvb, offset, 3, flags);
653 proto_tree_add_boolean(tree, hf_fc_fctl_rexmitted_seq, tvb, offset, 3, flags);
654 if (flags&FC_FCTL_REXMITTED_SEQ){
655 proto_item_append_text(item, " Rexmitted Seq");
656 if (flags & (~( FC_FCTL_REXMITTED_SEQ )))
657 proto_item_append_text(item, ",");
659 flags&=(~( FC_FCTL_REXMITTED_SEQ ));
661 proto_tree_add_uint(tree, hf_fc_fctl_abts_ack, tvb, offset, 3, flags);
663 proto_tree_add_boolean(tree, hf_fc_fctl_rel_offset, tvb, offset, 3, flags);
664 if (flags&FC_FCTL_REL_OFFSET){
665 proto_item_append_text(item, " Rel Offset");
666 if (flags & (~( FC_FCTL_REL_OFFSET )))
667 proto_item_append_text(item, ",");
672 static const value_string fc_bls_proto_val[] = {
673 {FC_BLS_NOP , "NOP"},
674 {FC_BLS_ABTS , "ABTS"},
675 {FC_BLS_RMC , "RMC"},
676 {FC_BLS_BAACC , "BA_ACC"},
677 {FC_BLS_BARJT , "BA_RJT"},
678 {FC_BLS_PRMT , "PRMT"},
682 static const value_string fc_els_proto_val[] = {
683 {0x01 , "Solicited Data"},
689 /* Code to actually dissect the packets */
691 dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_ifcp, fc_data_t* fc_data)
693 /* Set up structures needed to add the protocol subtree and manage it */
694 proto_item *ti, *hidden_item;
697 int offset = 0, next_offset;
699 gboolean is_lastframe_inseq, is_1frame_inseq, is_exchg_resp = 0;
700 fragment_head *fcfrag_head;
701 guint32 frag_id, frag_size;
702 guint8 df_ctl, seq_id;
705 guint32 param, exchange_key;
710 fc_exchange_t *fc_ex;
711 fc_conv_data_t *fc_conv_data=NULL;
713 conversation_t *conversation;
714 fcseq_conv_data_t *cdata;
715 fcseq_conv_key_t ckey, *req_key;
717 /* Make entries in Protocol column and Info column on summary display */
718 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
720 fchdr.r_ctl = tvb_get_guint8 (tvb, offset);
724 * If the frame contains a VFT (virtual fabric tag), decode it
725 * as a separate header before the FC frame header.
727 * This used to be called the Cisco-proprietary EISL field, but is now
728 * standardized in FC-FS-2. See section 10.2.4.
730 if (fchdr.r_ctl == FC_RCTL_VFT) {
733 fchdr.r_ctl = tvb_get_guint8 (tvb, offset);
736 /* Each fc endpoint pair gets its own TCP session in iFCP but
737 * the src/dst ids are undefined(==semi-random) in the FC header.
738 * This means we can no track conversations for FC over iFCP by using
739 * the FC src/dst addresses.
740 * For iFCP: Do not update the pinfo src/dst struct and let it remain
741 * being tcpip src/dst so that request/response matching in the FCP layer
742 * will use ip addresses instead and still work.
745 TVB_SET_ADDRESS (&pinfo->dst, AT_FC, tvb, offset+1, 3);
746 TVB_SET_ADDRESS (&pinfo->src, AT_FC, tvb, offset+5, 3);
750 SET_ADDRESS(&fchdr.d_id, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
751 SET_ADDRESS(&fchdr.s_id, pinfo->src.type, pinfo->src.len, pinfo->src.data);
753 fchdr.cs_ctl = tvb_get_guint8 (tvb, offset+4);
754 fchdr.type = tvb_get_guint8 (tvb, offset+8);
755 fchdr.fctl=tvb_get_ntoh24(tvb,offset+9);
756 fchdr.seqcnt = tvb_get_ntohs (tvb, offset+14);
757 fchdr.oxid=tvb_get_ntohs(tvb,offset+16);
758 fchdr.rxid=tvb_get_ntohs(tvb,offset+18);
759 fchdr.relative_offset=0;
760 param = tvb_get_ntohl (tvb, offset+20);
761 seq_id = tvb_get_guint8 (tvb, offset+12);
763 pinfo->ptype = PT_EXCHG;
765 /* set up a conversation and conversation data */
766 /* TODO treat the fc address s_id==00.00.00 as a wildcard matching anything */
767 conversation=find_or_create_conversation(pinfo);
768 fc_conv_data=(fc_conv_data_t *)conversation_get_proto_data(conversation, proto_fc);
770 fc_conv_data=wmem_new(wmem_file_scope(), fc_conv_data_t);
771 fc_conv_data->exchanges=wmem_tree_new(wmem_file_scope());
772 fc_conv_data->luns=wmem_tree_new(wmem_file_scope());
773 conversation_add_proto_data(conversation, proto_fc, fc_conv_data);
776 /* Set up LUN data. OXID + LUN make up unique exchanges, but LUN is populated in subdissectors
777 and not necessarily in every frame. Stub it here for now */
779 if (!pinfo->fd->flags.visited) {
780 fchdr.lun = (guint16)GPOINTER_TO_UINT(wmem_tree_lookup32(fc_conv_data->luns, fchdr.oxid));
783 /* In the interest of speed, if "tree" is NULL, don't do any work not
784 necessary to generate protocol tree items. */
785 ti = proto_tree_add_protocol_format (tree, proto_fc, tvb, offset, FC_HEADER_SIZE, "Fibre Channel");
786 fc_tree = proto_item_add_subtree (ti, ett_fc);
788 /*is_ack = ((fchdr.r_ctl == 0xC0) || (fchdr.r_ctl == 0xC1));*/
790 /* There are two ways to determine if this is the first frame of a
792 * (i) The SOF bits indicate that this is the first frame OR
793 * (ii) This is an SOFf frame and seqcnt is 0.
795 is_1frame_inseq = (((fc_data->sof_eof & FC_DATA_SOF_FIRST_FRAME) == FC_DATA_SOF_FIRST_FRAME) ||
796 (((fc_data->sof_eof & FC_DATA_SOF_SOFF) == FC_DATA_SOF_SOFF) &&
797 (fchdr.seqcnt == 0)));
799 is_lastframe_inseq = ((fc_data->sof_eof & FC_DATA_EOF_LAST_FRAME) == FC_DATA_EOF_LAST_FRAME);
801 is_lastframe_inseq |= fchdr.fctl & FC_FCTL_SEQ_LAST;
802 /*is_valid_frame = ((pinfo->sof_eof & 0x40) == 0x40);*/
804 ftype = fc_get_ftype (fchdr.r_ctl, fchdr.type);
806 col_add_str (pinfo->cinfo, COL_INFO, val_to_str (ftype, fc_ftype_vals,
807 "Unknown Type (0x%x)"));
809 if (ftype == FC_FTYPE_LINKCTL)
810 col_append_fstr (pinfo->cinfo, COL_INFO, ", %s",
811 val_to_str ((fchdr.r_ctl & 0x0F),
815 if (vft_offset >= 0) {
816 dissect_fc_vft(fc_tree, tvb, vft_offset);
818 switch (fchdr.r_ctl & 0xF0) {
820 case FC_RCTL_DEV_DATA:
821 case FC_RCTL_LINK_DATA:
823 /* the lower 4 bits of R_CTL are the information category */
824 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
825 FC_RCTL_SIZE, fchdr.r_ctl,
828 val_to_str ((fchdr.r_ctl & 0xF0),
829 fc_routing_val, "0x%x"),
830 val_to_str ((fchdr.r_ctl & 0x0F),
834 case FC_RCTL_LINK_CTL:
835 /* the lower 4 bits of R_CTL indicate the type of link ctl frame */
836 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
837 FC_RCTL_SIZE, fchdr.r_ctl,
840 val_to_str ((fchdr.r_ctl & 0xF0),
841 fc_routing_val, "0x%x"),
842 val_to_str ((fchdr.r_ctl & 0x0F),
843 fc_lctl_proto_val, "0x%x"));
847 switch (fchdr.type) {
850 /* the lower 4 bits of R_CTL indicate the type of BLS frame */
851 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
852 FC_RCTL_SIZE, fchdr.r_ctl,
855 val_to_str ((fchdr.r_ctl & 0xF0),
856 fc_routing_val, "0x%x"),
857 val_to_str ((fchdr.r_ctl & 0x0F),
858 fc_bls_proto_val, "0x%x"));
862 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
863 FC_RCTL_SIZE, fchdr.r_ctl,
866 val_to_str ((fchdr.r_ctl & 0xF0),
867 fc_routing_val, "0x%x"),
874 switch (fchdr.type) {
877 /* the lower 4 bits of R_CTL indicate the type of ELS frame */
878 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
879 FC_RCTL_SIZE, fchdr.r_ctl,
882 val_to_str ((fchdr.r_ctl & 0xF0),
883 fc_routing_val, "0x%x"),
884 val_to_str ((fchdr.r_ctl & 0x0F),
885 fc_els_proto_val, "0x%x"));
889 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
890 FC_RCTL_SIZE, fchdr.r_ctl,
893 val_to_str ((fchdr.r_ctl & 0xF0),
894 fc_routing_val, "0x%x"),
901 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
902 FC_RCTL_SIZE, fchdr.r_ctl,
905 val_to_str ((fchdr.r_ctl & 0xF0),
906 fc_routing_val, "0x%x"),
911 hidden_item = proto_tree_add_uint (fc_tree, hf_fc_ftype, tvb, offset, 1,
913 PROTO_ITEM_SET_HIDDEN(hidden_item);
915 /* XXX - use "fc_wka_vals[]" on this? */
916 proto_tree_add_string (fc_tree, hf_fc_did, tvb, offset+1, 3,
917 fc_to_str ((const guint8 *)fchdr.d_id.data));
918 hidden_item = proto_tree_add_string (fc_tree, hf_fc_id, tvb, offset+1, 3,
919 fc_to_str ((const guint8 *)fchdr.d_id.data));
920 PROTO_ITEM_SET_HIDDEN(hidden_item);
922 proto_tree_add_uint (fc_tree, hf_fc_csctl, tvb, offset+4, 1, fchdr.cs_ctl);
924 /* XXX - use "fc_wka_vals[]" on this? */
925 proto_tree_add_string (fc_tree, hf_fc_sid, tvb, offset+5, 3,
926 fc_to_str ((const guint8 *)fchdr.s_id.data));
927 hidden_item = proto_tree_add_string (fc_tree, hf_fc_id, tvb, offset+5, 3,
928 fc_to_str ((const guint8 *)fchdr.s_id.data));
929 PROTO_ITEM_SET_HIDDEN(hidden_item);
931 if (ftype == FC_FTYPE_LINKCTL) {
932 if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYB) ||
933 ((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYL)) {
934 /* for F_BSY frames, the upper 4 bits of the type field specify the
935 * reason for the BSY.
937 proto_tree_add_uint_format_value(fc_tree, hf_fc_type, tvb,
938 offset+8, FC_TYPE_SIZE,
939 fchdr.type,"0x%x(%s)", fchdr.type,
940 fclctl_get_typestr ((guint8) (fchdr.r_ctl & 0x0F),
943 proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
946 proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
950 dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9);
951 f_ctl = tvb_get_ntoh24(tvb, offset+9);
954 proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, ENC_BIG_ENDIAN);
956 df_ctl = tvb_get_guint8(tvb, offset+13);
958 proto_tree_add_uint (fc_tree, hf_fc_dfctl, tvb, offset+13, 1, df_ctl);
959 proto_tree_add_uint (fc_tree, hf_fc_seqcnt, tvb, offset+14, 2, fchdr.seqcnt);
960 proto_tree_add_uint (fc_tree, hf_fc_oxid, tvb, offset+16, 2, fchdr.oxid);
961 proto_tree_add_uint (fc_tree, hf_fc_rxid, tvb, offset+18, 2, fchdr.rxid);
963 if (ftype == FC_FTYPE_LINKCTL) {
964 if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FRJT) ||
965 ((fchdr.r_ctl & 0x0F) == FC_LCTL_PRJT) ||
966 ((fchdr.r_ctl & 0x0F) == FC_LCTL_PBSY)) {
967 /* In all these cases of Link Ctl frame, the parameter field
968 * encodes the detailed error message
970 proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
973 fclctl_get_paramstr ((fchdr.r_ctl & 0x0F),
976 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
978 } else if (ftype == FC_FTYPE_BLS) {
979 if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
980 proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
983 ((param & 0x0F) == 1 ? "Abort Sequence" :
986 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20,
989 } else if (ftype == FC_FTYPE_SCSI ) {
990 if (f_ctl&FC_FCTL_REL_OFFSET){
991 proto_tree_add_item (fc_tree, hf_fc_relative_offset, tvb, offset+20, 4, ENC_BIG_ENDIAN);
992 fchdr.relative_offset=tvb_get_ntohl(tvb, offset+20);
994 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
997 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
1000 /* Skip the Frame_Header */
1001 next_offset = offset + FC_HEADER_SIZE;
1003 /* Network_Header present? */
1004 if (df_ctl & FC_DFCTL_NH) {
1005 /* Yes - dissect it. */
1007 proto_tree_add_string (fc_tree, hf_fc_nh_da, tvb, next_offset, 8,
1008 fcwwn_to_str (tvb_get_string (wmem_packet_scope(), tvb, offset, 8)));
1009 proto_tree_add_string (fc_tree, hf_fc_nh_sa, tvb, offset+8, 8,
1010 fcwwn_to_str (tvb_get_string (wmem_packet_scope(), tvb, offset+8, 8)));
1015 /* XXX - handle Association_Header and Device_Header here */
1017 if (ftype == FC_FTYPE_LINKCTL) {
1018 /* ACK_1 frames and other LINK_CTL frames echo the last seq bit if the
1019 * packet they're ack'ing did not have it set. So, we'll incorrectly
1020 * flag them as being fragmented when they're not. This fixes the
1023 is_lastframe_inseq = TRUE;
1025 is_exchg_resp = (f_ctl & FC_FCTL_EXCHANGE_RESPONDER) != 0;
1028 if (tvb_reported_length (tvb) < FC_HEADER_SIZE)
1029 THROW(ReportedBoundsError);
1031 frag_size = tvb_reported_length (tvb)-FC_HEADER_SIZE;
1033 /* If there is an MDS header, we need to subtract the MDS trailer size
1034 * Link Ctl, BLS & OHMS are all (encap header + FC Header + encap trailer)
1035 * and are never fragmented and so we ignore the frag_size assertion for
1038 if ((fc_data->ethertype == ETHERTYPE_UNK) || (fc_data->ethertype == ETHERTYPE_FCFT)) {
1039 if ((frag_size < MDSHDR_TRAILER_SIZE) ||
1040 ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1041 (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1042 THROW(ReportedBoundsError);
1043 frag_size -= MDSHDR_TRAILER_SIZE;
1044 } else if (fc_data->ethertype == ETHERTYPE_BRDWALK) {
1045 if ((frag_size <= 8) ||
1046 ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1047 (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1048 THROW(ReportedBoundsError);
1049 frag_size -= 8; /* 4 byte of FC CRC +
1050 4 bytes of error+EOF = 8 bytes */
1053 if (!is_lastframe_inseq) {
1054 /* Show this only as a fragmented FC frame */
1055 col_append_str (pinfo->cinfo, COL_INFO, " (Fragmented)");
1058 /* If this is a fragment, attempt to check if fully reassembled frame is
1059 * present, if we're configured to reassemble.
1061 if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS) &&
1062 (ftype != FC_FTYPE_OHMS) &&
1063 (!is_lastframe_inseq || !is_1frame_inseq) && fc_reassemble &&
1064 tvb_bytes_exist(tvb, FC_HEADER_SIZE, frag_size) && tree) {
1065 /* Add this to the list of fragments */
1067 /* In certain cases such as FICON, the SEQ_CNT is streaming
1068 * i.e. continuously increasing. So, zero does not signify the
1069 * first frame of the sequence. To fix this, we need to save the
1070 * SEQ_CNT of the first frame in sequence and use this value to
1071 * determine the actual offset into a frame.
1073 ckey.conv_idx = conversation->index;
1075 cdata = (fcseq_conv_data_t *)g_hash_table_lookup (fcseq_req_hash,
1078 if (is_1frame_inseq) {
1080 /* Since we never free the memory used by an exchange, this maybe a
1081 * case of another request using the same exchange as a previous
1084 cdata->seq_cnt = fchdr.seqcnt;
1087 req_key = wmem_new(wmem_file_scope(), fcseq_conv_key_t);
1088 req_key->conv_idx = conversation->index;
1090 cdata = wmem_new(wmem_file_scope(), fcseq_conv_data_t);
1091 cdata->seq_cnt = fchdr.seqcnt;
1093 g_hash_table_insert (fcseq_req_hash, req_key, cdata);
1097 else if (cdata != NULL) {
1098 real_seqcnt = fchdr.seqcnt - cdata->seq_cnt ;
1101 real_seqcnt = fchdr.seqcnt;
1104 /* Verify that this is a valid fragment */
1105 if (is_lastframe_inseq && !is_1frame_inseq && !real_seqcnt) {
1106 /* This is a frame that purports to be the last frame in a
1107 * sequence, is not the first frame, but has a seqcnt that is
1108 * 0. This is a bogus frame, don't attempt to reassemble it.
1110 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1111 col_append_str (pinfo->cinfo, COL_INFO, " (Bogus Fragment)");
1114 frag_id = ((fchdr.oxid << 16) ^ seq_id) | is_exchg_resp ;
1116 /* We assume that all frames are of the same max size */
1117 fcfrag_head = fragment_add (&fc_reassembly_table,
1118 tvb, FC_HEADER_SIZE,
1119 pinfo, frag_id, NULL,
1120 real_seqcnt * fc_max_frame_size,
1122 !is_lastframe_inseq);
1125 next_tvb = tvb_new_chain(tvb, fcfrag_head->tvb_data);
1127 /* Add the defragmented data to the data source list. */
1128 add_new_data_source(pinfo, next_tvb, "Reassembled FC");
1131 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1132 tvb, offset+9, 1, 1);
1133 PROTO_ITEM_SET_HIDDEN(hidden_item);
1138 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1139 tvb, offset+9, 1, 0);
1140 PROTO_ITEM_SET_HIDDEN(hidden_item);
1142 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1143 call_dissector (data_handle, next_tvb, pinfo, tree);
1149 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1150 tvb, offset+9, 1, 0);
1151 PROTO_ITEM_SET_HIDDEN(hidden_item);
1153 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1156 if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS)) {
1157 /* If relative offset is used, only dissect the pdu with
1158 * offset 0 (param) */
1159 if( (fchdr.fctl&FC_FCTL_REL_OFFSET) && param ){
1160 call_dissector (data_handle, next_tvb, pinfo, tree);
1162 if (!dissector_try_uint_new (fcftype_dissector_table, ftype,
1163 next_tvb, pinfo, tree, FALSE, &fchdr)) {
1164 call_dissector (data_handle, next_tvb, pinfo, tree);
1167 } else if (ftype == FC_FTYPE_BLS) {
1168 if ((fchdr.r_ctl & 0x0F) == FC_BLS_BAACC) {
1169 dissect_fc_ba_acc (next_tvb, pinfo, tree);
1170 } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_BARJT) {
1171 dissect_fc_ba_rjt (next_tvb, pinfo, tree);
1172 } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
1173 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
1174 col_set_str(pinfo->cinfo, COL_INFO, "ABTS");
1178 /* Lun is only populated by subdissectors, and subsequent packets assume the same lun.
1179 The only way that consistently works is to save the lun on the first pass (with OXID as
1180 key) when packets are guaranteed to be parsed consecutively */
1182 /* Set up LUN data */
1183 if (!pinfo->fd->flags.visited) {
1184 wmem_tree_insert32(fc_conv_data->luns, fchdr.oxid, GUINT_TO_POINTER((guint)fchdr.lun));
1187 exchange_key = ((fchdr.oxid & 0xFFFF) | ((fchdr.lun << 16) & 0xFFFF0000));
1189 /* set up the exchange data */
1190 /* XXX we should come up with a way to handle when the 16bit oxid wraps
1191 * so that large traces will work
1193 fc_ex=(fc_exchange_t*)wmem_tree_lookup32(fc_conv_data->exchanges, exchange_key);
1195 fc_ex=wmem_new(wmem_file_scope(), fc_exchange_t);
1196 fc_ex->first_exchange_frame=0;
1197 fc_ex->last_exchange_frame=0;
1198 fc_ex->fc_time=pinfo->fd->abs_ts;
1200 wmem_tree_insert32(fc_conv_data->exchanges, exchange_key, fc_ex);
1203 fchdr.fc_ex = fc_ex;
1205 /* populate the exchange struct */
1206 if(!pinfo->fd->flags.visited){
1207 if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
1208 fc_ex->first_exchange_frame=pinfo->fd->num;
1209 fc_ex->fc_time = pinfo->fd->abs_ts;
1211 if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1212 fc_ex->last_exchange_frame=pinfo->fd->num;
1216 /* put some nice exchange data in the tree */
1217 if(!(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST)){
1219 it=proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
1220 PROTO_ITEM_SET_GENERATED(it);
1221 if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1223 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fc_ex->fc_time);
1224 it=proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
1225 PROTO_ITEM_SET_GENERATED(it);
1228 if(!(fchdr.fctl&FC_FCTL_EXCHANGE_LAST)){
1230 it=proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
1231 PROTO_ITEM_SET_GENERATED(it);
1234 tap_queue_packet(fc_tap, pinfo, &fchdr);
1238 dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1240 fc_data_t* fc_data = (fc_data_t*)data;
1245 dissect_fc_helper (tvb, pinfo, tree, FALSE, fc_data);
1246 return tvb_length(tvb);
1250 dissect_fc_ifcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1252 fc_data_t* fc_data = (fc_data_t*)data;
1257 dissect_fc_helper (tvb, pinfo, tree, TRUE, fc_data);
1258 return tvb_length(tvb);
1262 dissect_fcsof(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1264 proto_item *it = NULL;
1265 proto_tree *fcsof_tree = NULL;
1266 gint bytes_remaining;
1267 tvbuff_t *next_tvb, *checksum_tvb;
1270 guint32 crc_computed = 0;
1272 gint crc_offset = 0;
1273 gint eof_offset = 0;
1274 gint sof_offset = 0;
1275 const gint FCSOF_TRAILER_LEN = 8;
1276 const gint FCSOF_HEADER_LEN = 4;
1277 gint frame_len_for_checksum = 0;
1280 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
1282 crc_offset = tvb_reported_length(tvb) - FCSOF_TRAILER_LEN;
1283 eof_offset = crc_offset + 4;
1287 sof = tvb_get_ntohl(tvb, 0);
1290 crc = tvb_get_ntohl(tvb, crc_offset);
1292 /* GET Computed CRC */
1293 frame_len_for_checksum = crc_offset - FCSOF_HEADER_LEN;
1294 checksum_tvb = tvb_new_subset(tvb, 4, frame_len_for_checksum, frame_len_for_checksum);
1295 crc_computed = crc32_802_tvb(checksum_tvb, frame_len_for_checksum);
1298 eof = tvb_get_ntohl(tvb, eof_offset);
1300 it = proto_tree_add_protocol_format(tree, proto_fcsof, tvb, 0,
1301 4, "Fibre Channel Delimiter: SOF: %s EOF: %s",
1302 val_to_str(sof, fc_sof_vals, "0x%x"),
1303 val_to_str(eof, fc_eof_vals, "0x%x"));
1305 fcsof_tree = proto_item_add_subtree(it, ett_fcsof);
1307 proto_tree_add_uint(fcsof_tree, hf_fcsof, tvb, sof_offset, 4, sof);
1309 if (crc == crc_computed) {
1310 proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1312 "%8.8x [valid]", crc);
1314 it = proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1316 "%8.8x [error: should be %8.8x]",
1319 expert_add_info_format(pinfo, it, &ei_fccrc,
1320 "Bad FC CRC %8.8x %8.x",
1324 proto_tree_add_uint(fcsof_tree, hf_fceof, tvb, eof_offset, 4, eof);
1326 bytes_remaining = tvb_length_remaining(tvb, 4);
1327 next_tvb = tvb_new_subset(tvb, 4, bytes_remaining, -1);
1329 fc_data.ethertype = 0;
1330 fc_data.sof_eof = 0;
1331 if (sof == FC_SOFI2 || sof == FC_SOFI3) {
1332 fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME;
1333 } else if (sof == FC_SOFF) {
1334 fc_data.sof_eof = FC_DATA_SOF_SOFF;
1337 if (eof == EOFT_POS || eof == EOFT_NEG) {
1338 fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME;
1339 } else if (eof == EOFDTI_NEG || eof == EOFDTI_POS) {
1340 fc_data.sof_eof |= FC_DATA_EOF_INVALID;
1343 /* Call FC dissector */
1344 call_dissector_with_data(fc_handle, next_tvb, pinfo, tree, &fc_data);
1347 /* Register the protocol with Wireshark */
1349 /* this format is require because a script is used to build the C function
1350 that calls all the protocol registration.
1354 proto_register_fc(void)
1357 /* Setup list of header fields See Section 1.6.1 for details*/
1358 static hf_register_info hf[] = {
1360 { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1363 {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
1364 0x0, "Derived Type", HFILL}},
1366 { "Dest Addr", "fc.d_id", FT_STRING, BASE_NONE, NULL, 0x0,
1367 "Destination Address", HFILL}},
1369 {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1372 {"Src Addr", "fc.s_id", FT_STRING, BASE_NONE, NULL, 0x0,
1373 "Source Address", HFILL}},
1375 {"Addr", "fc.id", FT_STRING, BASE_NONE, NULL, 0x0,
1376 "Source or Destination Address", HFILL}},
1378 {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
1381 {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1383 {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
1384 "Sequence ID", HFILL}},
1386 {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1388 {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
1389 "Sequence Count", HFILL}},
1391 {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
1394 {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
1397 {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL,
1400 { &hf_fc_reassembled,
1401 {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_NONE, NULL,
1404 {"Network DA", "fc.nethdr.da", FT_STRING, BASE_NONE, NULL,
1407 {"Network SA", "fc.nethdr.sa", FT_STRING, BASE_NONE, NULL,
1410 /* Basic Link Svc field definitions */
1411 { &hf_fc_bls_seqid_vld,
1412 {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8, BASE_HEX,
1413 VALS (fc_bls_seqid_val), 0x0, NULL, HFILL}},
1414 { &hf_fc_bls_lastvld_seqid,
1415 {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8, BASE_HEX, NULL,
1418 {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1420 {"RXID", "fc.bls_rxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1421 { &hf_fc_bls_lowseqcnt,
1422 {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1424 { &hf_fc_bls_hiseqcnt,
1425 {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1427 { &hf_fc_bls_rjtcode,
1428 {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
1430 { &hf_fc_bls_rjtdetail,
1431 {"Reason Explanation", "fc.bls_rjtdetail", FT_UINT8, BASE_HEX,
1432 VALS (fc_bls_barjt_det_val), 0x0, NULL, HFILL}},
1433 { &hf_fc_bls_vendor,
1434 {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8, BASE_HEX, NULL,
1436 { &hf_fc_fctl_exchange_responder,
1437 {"ExgRpd", "fc.fctl.exchange_responder", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_responder),
1438 FC_FCTL_EXCHANGE_RESPONDER, "Exchange Responder?", HFILL}},
1439 { &hf_fc_fctl_seq_recipient,
1440 {"SeqRec", "fc.fctl.seq_recipient", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_recipient),
1441 FC_FCTL_SEQ_RECIPIENT, "Seq Recipient?", HFILL}},
1442 { &hf_fc_fctl_exchange_first,
1443 {"ExgFst", "fc.fctl.exchange_first", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_first),
1444 FC_FCTL_EXCHANGE_FIRST, "First Exchange?", HFILL}},
1445 { &hf_fc_fctl_exchange_last,
1446 {"ExgLst", "fc.fctl.exchange_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_last),
1447 FC_FCTL_EXCHANGE_LAST, "Last Exchange?", HFILL}},
1448 { &hf_fc_fctl_seq_last,
1449 {"SeqLst", "fc.fctl.seq_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_last),
1450 FC_FCTL_SEQ_LAST, "Last Sequence?", HFILL}},
1451 { &hf_fc_fctl_priority,
1452 {"Pri", "fc.fctl.priority", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_priority),
1453 FC_FCTL_PRIORITY, "Priority", HFILL}},
1454 { &hf_fc_fctl_transfer_seq_initiative,
1455 {"TSI", "fc.fctl.transfer_seq_initiative", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_transfer_seq_initiative),
1456 FC_FCTL_TRANSFER_SEQ_INITIATIVE, "Transfer Seq Initiative", HFILL}},
1457 { &hf_fc_fctl_rexmitted_seq,
1458 {"RetSeq", "fc.fctl.rexmitted_seq", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rexmitted_seq),
1459 FC_FCTL_REXMITTED_SEQ, "Retransmitted Sequence", HFILL}},
1460 { &hf_fc_fctl_rel_offset,
1461 {"RelOff", "fc.fctl.rel_offset", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rel_offset),
1462 FC_FCTL_REL_OFFSET, "rel offset", HFILL}},
1463 { &hf_fc_fctl_last_data_frame,
1464 {"LDF", "fc.fctl.last_data_frame", FT_UINT24, BASE_HEX, VALS(last_data_frame_vals),
1465 FC_FCTL_LAST_DATA_FRAME_MASK, "Last Data Frame?", HFILL}},
1466 { &hf_fc_fctl_ack_0_1,
1467 {"A01", "fc.fctl.ack_0_1", FT_UINT24, BASE_HEX, VALS(ack_0_1_vals),
1468 FC_FCTL_ACK_0_1_MASK, "Ack 0/1 value", HFILL}},
1469 { &hf_fc_fctl_abts_ack,
1470 {"AA", "fc.fctl.abts_ack", FT_UINT24, BASE_HEX, VALS(abts_ack_vals),
1471 FC_FCTL_ABTS_MASK, "ABTS ACK values", HFILL}},
1473 { &hf_fc_fctl_abts_not_ack,
1474 {"AnA", "fc.fctl.abts_not_ack", FT_UINT24, BASE_HEX, VALS(abts_not_ack_vals),
1475 FC_FCTL_ABTS_MASK, "ABTS not ACK vals", HFILL}},
1477 { &hf_fc_exchange_first_frame,
1478 { "Exchange First In", "fc.exchange_first_frame", FT_FRAMENUM, BASE_NONE, NULL,
1479 0, "The first frame of this exchange is in this frame", HFILL }},
1480 { &hf_fc_exchange_last_frame,
1481 { "Exchange Last In", "fc.exchange_last_frame", FT_FRAMENUM, BASE_NONE, NULL,
1482 0, "The last frame of this exchange is in this frame", HFILL }},
1484 { "Time from Exchange First", "fc.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
1485 0, "Time since the first frame of the Exchange", HFILL }},
1486 { &hf_fc_relative_offset,
1487 {"Relative Offset", "fc.relative_offset", FT_UINT32, BASE_DEC, NULL,
1488 0, "Relative offset of data", HFILL}},
1490 {"VFT Header", "fc.vft", FT_UINT16, BASE_DEC, NULL,
1493 {"R_CTL", "fc.vft.rctl", FT_UINT8, BASE_HEX, NULL,
1496 {"Version", "fc.vft.ver", FT_UINT8, BASE_DEC, NULL,
1497 0, "Version of VFT header", HFILL}},
1499 {"Type", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1500 0, "Type of tagged frame", HFILL}},
1502 {"Priority", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1503 0, "QoS Priority", HFILL}},
1505 {"VF_ID", "fc.vft.vf_id", FT_UINT16, BASE_DEC, NULL,
1506 0, "Virtual Fabric ID", HFILL}},
1507 { &hf_fc_vft_hop_ct,
1508 {"HopCT", "fc.vft.hop_ct", FT_UINT8, BASE_DEC, NULL,
1509 0, "Hop Count", HFILL}},
1512 /* Setup protocol subtree array */
1513 static gint *ett[] = {
1520 static ei_register_info ei[] = {
1521 { &ei_fccrc, { "fc.crc.bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1524 module_t *fc_module;
1525 expert_module_t* expert_fc;
1529 static hf_register_info sof_hf[] = {
1531 { "SOF", "fc.sof", FT_UINT32, BASE_HEX, VALS(fc_sof_vals), 0,
1534 { "EOF", "fc.eof", FT_UINT32, BASE_HEX, VALS(fc_eof_vals), 0,
1537 { "CRC", "fc.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
1540 static gint *sof_ett[] = {
1547 /* Register the protocol name and description */
1548 proto_fc = proto_register_protocol ("Fibre Channel", "FC", "fc");
1549 fc_handle = new_register_dissector ("fc", dissect_fc, proto_fc);
1550 new_register_dissector ("fc_ifcp", dissect_fc_ifcp, proto_fc);
1551 fc_tap = register_tap("fc");
1553 /* Required function calls to register the header fields and subtrees used */
1554 proto_register_field_array(proto_fc, hf, array_length(hf));
1555 proto_register_subtree_array(ett, array_length(ett));
1556 expert_fc = expert_register_protocol(proto_fc);
1557 expert_register_field_array(expert_fc, ei, array_length(ei));
1559 /* subdissectors called through this table will find the fchdr structure
1560 * through data parameter of dissector
1562 fcftype_dissector_table = register_dissector_table ("fc.ftype",
1564 FT_UINT8, BASE_HEX);
1566 /* Register preferences */
1567 fc_module = prefs_register_protocol (proto_fc, NULL);
1568 prefs_register_bool_preference (fc_module,
1570 "Reassemble multi-frame sequences",
1571 "If enabled, reassembly of multi-frame "
1572 "sequences is done",
1574 prefs_register_uint_preference (fc_module,
1575 "max_frame_size", "Max FC Frame Size",
1576 "This is the size of non-last frames in a "
1577 "multi-frame sequence", 10,
1578 &fc_max_frame_size);
1580 register_init_routine (fc_exchange_init_protocol);
1583 /* Register FC SOF/EOF */
1584 proto_fcsof = proto_register_protocol("Fibre Channel Delimiters", "FCSoF", "fcsof");
1586 proto_register_field_array(proto_fcsof, sof_hf, array_length(sof_hf));
1587 proto_register_subtree_array(sof_ett, array_length(sof_ett));
1589 fcsof_handle = register_dissector("fcsof", dissect_fcsof, proto_fcsof);
1593 /* If this dissector uses sub-dissector registration add a registration routine.
1594 This format is required because a script is used to find these routines and
1595 create the code that calls these routines.
1598 proto_reg_handoff_fc (void)
1600 dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2, fc_handle);
1602 dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS, fcsof_handle);
1604 data_handle = find_dissector("data");