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.
28 #include <epan/packet.h>
29 #include <epan/exceptions.h>
30 #include <epan/prefs.h>
31 #include <epan/to_str.h>
32 #include <wiretap/wtap.h>
33 #include <epan/reassemble.h>
34 #include <epan/conversation_table.h>
35 #include <epan/etypes.h>
36 #include <epan/srt_table.h>
37 #include "packet-fc.h"
38 #include "packet-fclctl.h"
39 #include "packet-fcbls.h"
40 #include <epan/crc32-tvb.h>
41 #include <epan/expert.h>
43 void proto_register_fc(void);
44 void proto_reg_handoff_fc(void);
46 #define FC_HEADER_SIZE 24
47 #define FC_RCTL_VFT 0x50
48 #define MDSHDR_TRAILER_SIZE 6
50 /* Size of various fields in FC header in bytes */
51 #define FC_RCTL_SIZE 1
53 #define FC_CSCTL_SIZE 1
55 #define FC_TYPE_SIZE 1
56 #define FC_FCTL_SIZE 3
57 #define FC_SEQID_SIZE 1
58 #define FC_DFCTL_SIZE 1
59 #define FC_SEQCNT_SIZE 2
60 #define FC_OXID_SIZE 2
61 #define FC_RXID_SIZE 2
62 #define FC_PARAM_SIZE 4
64 /* Initialize the protocol and registered fields */
65 static int proto_fc = -1;
66 static int hf_fc_time = -1;
67 static int hf_fc_exchange_first_frame = -1;
68 static int hf_fc_exchange_last_frame = -1;
69 static int hf_fc_rctl = -1;
70 static int hf_fc_did = -1;
71 static int hf_fc_csctl = -1;
72 static int hf_fc_sid = -1;
73 static int hf_fc_id = -1;
74 static int hf_fc_type = -1;
75 static int hf_fc_fctl = -1;
76 static int hf_fc_fctl_exchange_responder = -1;
77 static int hf_fc_fctl_seq_recipient = -1;
78 static int hf_fc_fctl_exchange_first = -1;
79 static int hf_fc_fctl_exchange_last = -1;
80 static int hf_fc_fctl_seq_last = -1;
81 static int hf_fc_fctl_priority = -1;
82 static int hf_fc_fctl_transfer_seq_initiative = -1;
83 static int hf_fc_fctl_rexmitted_seq = -1;
84 static int hf_fc_fctl_rel_offset = -1;
85 static int hf_fc_fctl_abts_ack = -1;
86 /* static int hf_fc_fctl_abts_not_ack = -1; */
87 static int hf_fc_fctl_last_data_frame = -1;
88 static int hf_fc_fctl_ack_0_1 = -1;
89 static int hf_fc_seqid = -1;
90 static int hf_fc_dfctl = -1;
91 static int hf_fc_seqcnt = -1;
92 static int hf_fc_oxid = -1;
93 static int hf_fc_rxid = -1;
94 static int hf_fc_param = -1;
95 static int hf_fc_ftype = -1; /* Derived field, non-existent in FC hdr */
96 static int hf_fc_reassembled = -1;
97 static int hf_fc_relative_offset = -1;
100 static int hf_fc_vft = -1;
101 static int hf_fc_vft_rctl = -1;
102 static int hf_fc_vft_ver = -1;
103 static int hf_fc_vft_type = -1;
104 static int hf_fc_vft_pri = -1;
105 static int hf_fc_vft_vf_id = -1;
106 static int hf_fc_vft_hop_ct = -1;
108 /* Network_Header fields */
109 static int hf_fc_nh_da = -1;
110 static int hf_fc_nh_sa = -1;
112 /* For Basic Link Svc */
113 static int hf_fc_bls_seqid_vld = -1;
114 static int hf_fc_bls_lastvld_seqid = -1;
115 static int hf_fc_bls_oxid = -1;
116 static int hf_fc_bls_rxid = -1;
117 static int hf_fc_bls_lowseqcnt = -1;
118 static int hf_fc_bls_hiseqcnt = -1;
119 static int hf_fc_bls_rjtcode = -1;
120 static int hf_fc_bls_rjtdetail = -1;
121 static int hf_fc_bls_vendor = -1;
124 static int proto_fcsof = -1;
126 static int hf_fcsof = -1;
127 static int hf_fceof = -1;
128 static int hf_fccrc = -1;
130 static int ett_fcsof = -1;
131 static int ett_fceof = -1;
132 static int ett_fccrc = -1;
135 /* Initialize the subtree pointers */
136 static gint ett_fc = -1;
137 static gint ett_fctl = -1;
138 static gint ett_fcbls = -1;
139 static gint ett_fc_vft = -1;
141 static expert_field ei_fccrc = EI_INIT;
143 static dissector_handle_t fc_handle, fcsof_handle;
144 static dissector_table_t fcftype_dissector_table;
146 static dissector_handle_t data_handle;
148 static int fc_tap = -1;
150 typedef struct _fc_conv_data_t {
151 wmem_tree_t *exchanges;
155 /* Reassembly stuff */
156 static gboolean fc_reassemble = TRUE;
157 static guint32 fc_max_frame_size = 1024;
158 static reassembly_table fc_reassembly_table;
160 typedef struct _fcseq_conv_key {
164 typedef struct _fcseq_conv_data {
168 static GHashTable *fcseq_req_hash = NULL;
174 fcseq_equal(gconstpointer v, gconstpointer w)
176 const fcseq_conv_key_t *v1 = (const fcseq_conv_key_t *)v;
177 const fcseq_conv_key_t *v2 = (const fcseq_conv_key_t *)w;
179 return (v1->conv_idx == v2->conv_idx);
183 fcseq_hash (gconstpointer v)
185 const fcseq_conv_key_t *key = (const fcseq_conv_key_t *)v;
194 fc_exchange_init_protocol(void)
196 reassembly_table_init(&fc_reassembly_table,
197 &addresses_reassembly_table_functions);
200 g_hash_table_destroy(fcseq_req_hash);
202 fcseq_req_hash = g_hash_table_new(fcseq_hash, fcseq_equal);
205 static const char* fc_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
207 if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_FC))
210 if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_FC))
213 if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_FC))
216 return CONV_FILTER_INVALID;
219 static ct_dissector_info_t fc_ct_dissector_info = {&fc_conv_get_filter_type};
222 fc_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
224 conv_hash_t *hash = (conv_hash_t*) pct;
225 const fc_hdr *fchdr=(const fc_hdr *)vip;
227 add_conversation_table_data(hash, &fchdr->s_id, &fchdr->d_id, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->fd->abs_ts, &fc_ct_dissector_info, PT_NONE);
232 static const char* fc_host_get_filter_type(hostlist_talker_t* host, conv_filter_type_e filter)
234 if ((filter == CONV_FT_ANY_ADDRESS) && (host->myaddress.type == AT_FC))
237 return CONV_FILTER_INVALID;
240 static hostlist_dissector_info_t fc_host_dissector_info = {&fc_host_get_filter_type};
243 fc_hostlist_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
245 conv_hash_t *hash = (conv_hash_t*) pit;
246 const fc_hdr *fchdr=(const fc_hdr *)vip;
248 /* Take two "add" passes per packet, adding for each direction, ensures that all
249 packets are counted properly (even if address is sending to itself)
250 XXX - this could probably be done more efficiently inside hostlist_table */
251 add_hostlist_table_data(hash, &fchdr->s_id, 0, TRUE, 1, pinfo->fd->pkt_len, &fc_host_dissector_info, PT_NONE);
252 add_hostlist_table_data(hash, &fchdr->d_id, 0, FALSE, 1, pinfo->fd->pkt_len, &fc_host_dissector_info, PT_NONE);
257 #define FC_NUM_PROCEDURES 256
260 fcstat_init(struct register_srt* srt _U_, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
262 srt_stat_table *fc_srt_table;
265 fc_srt_table = init_srt_table("Fibre Channel Types", NULL, srt_array, FC_NUM_PROCEDURES, NULL, NULL, gui_callback, gui_data, NULL);
266 for (i = 0; i < FC_NUM_PROCEDURES; i++)
268 gchar* tmp_str = val_to_str_wmem(NULL, i, fc_fc4_val, "Unknown(0x%02x)");
269 init_srt_table_row(fc_srt_table, i, tmp_str);
270 wmem_free(NULL, tmp_str);
275 fcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
278 srt_stat_table *fc_srt_table;
279 srt_data_t *data = (srt_data_t *)pss;
280 const fc_hdr *fc=(const fc_hdr *)prv;
282 /* we are only interested in reply packets */
283 if(!(fc->fctl&FC_FCTL_EXCHANGE_RESPONDER)){
286 /* if we havnt seen the request, just ignore it */
287 if ( (!fc->fc_ex) || (fc->fc_ex->first_exchange_frame==0) ){
291 fc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
292 add_srt_table_data(fc_srt_table, fc->type, &fc->fc_ex->fc_time, pinfo);
298 const value_string fc_fc4_val[] = {
299 {FC_TYPE_BLS, "Basic Link Svc"},
300 {FC_TYPE_ELS, "Ext Link Svc"},
301 {FC_TYPE_LLCSNAP, "LLC_SNAP"},
302 {FC_TYPE_IP, "IP/FC"},
303 {FC_TYPE_SCSI, "FCP"},
304 {FC_TYPE_FCCT, "FC_CT"},
305 {FC_TYPE_SWILS, "SW_ILS"},
307 {FC_TYPE_SNMP, "SNMP"},
308 {FC_TYPE_SB_FROM_CU, "SB-3(CU->Channel)"},
309 {FC_TYPE_SB_TO_CU, "SB-3(Channel->CU)"},
313 static const value_string fc_ftype_vals [] = {
314 {FC_FTYPE_UNDEF , "Unknown frame"},
315 {FC_FTYPE_SWILS, "SW_ILS"},
316 {FC_FTYPE_IP , "IP/FC"},
317 {FC_FTYPE_SCSI , "FCP"},
318 {FC_FTYPE_BLS , "Basic Link Svc"},
319 {FC_FTYPE_ELS , "ELS"},
320 {FC_FTYPE_FCCT , "FC_CT"},
321 {FC_FTYPE_LINKDATA, "Link Data"},
322 {FC_FTYPE_VDO, "Video Data"},
323 {FC_FTYPE_LINKCTL, "Link Ctl"},
324 {FC_FTYPE_SBCCS, "SBCCS"},
325 {FC_FTYPE_OHMS, "OHMS(Cisco MDS)"},
329 static const value_string fc_wka_vals[] _U_ = {
330 {FC_WKA_MULTICAST, "Multicast Server"},
331 {FC_WKA_CLKSYNC, "Clock Sync Server"},
332 {FC_WKA_KEYDIST, "Key Distribution Server"},
333 {FC_WKA_ALIAS, "Alias Server"},
334 {FC_WKA_QOSF, "QoS Facilitator"},
335 {FC_WKA_MGMT, "Management Server"},
336 {FC_WKA_TIME, "Time Server"},
337 {FC_WKA_DNS, "Directory Server"},
338 {FC_WKA_FABRIC_CTRLR, "Fabric Ctlr"},
339 {FC_WKA_FPORT, "F_Port Server"},
340 {FC_WKA_BCAST, "Broadcast ID"},
344 static const value_string fc_routing_val[] = {
345 {FC_RCTL_DEV_DATA, "Device_Data"},
346 {FC_RCTL_ELS, "Extended Link Services"},
347 {FC_RCTL_LINK_DATA, "FC-4 Link_Data"},
348 {FC_RCTL_VIDEO, "Video_Data"},
349 {FC_RCTL_BLS, "Basic Link Services"},
350 {FC_RCTL_LINK_CTL, "Link_Control Frame"},
354 static const value_string fc_iu_val[] = {
355 {FC_IU_UNCATEGORIZED , "Uncategorized Data"},
356 {FC_IU_SOLICITED_DATA , "Solicited Data"},
357 {FC_IU_UNSOLICITED_CTL , "Unsolicited Control"},
358 {FC_IU_SOLICITED_CTL , "Solicited Control"},
359 {FC_IU_UNSOLICITED_DATA, "Solicited Data"},
360 {FC_IU_DATA_DESCRIPTOR , "Data Descriptor"},
361 {FC_IU_UNSOLICITED_CMD , "Unsolicited Command"},
362 {FC_IU_CMD_STATUS , "Command Status"},
368 #define FC_SOFC1 0xBCB51717
369 #define FC_SOFI1 0xBCB55757
370 #define FC_SOFN1 0xBCB53737
371 #define FC_SOFI2 0xBCB55555
372 #define FC_SOFN2 0xBCB53535
373 #define FC_SOFI3 0xBCB55656
374 #define FC_SOFN3 0xBCB53636
375 #define FC_SOFC4 0xBCB51919
376 #define FC_SOFI4 0xBCB55959
377 #define FC_SOFN4 0xBCB53939
378 #define FC_SOFF 0xBCB55858
380 #define EOFT_NEG 0xBC957575
381 #define EOFT_POS 0xBCB57575
382 #define EOFDT_NEG 0xBC959595
383 #define EOFDT_POS 0xBCB59595
384 #define EOFA_NEG 0xBC95F5F5
385 #define EOFA_POS 0xBCB5F5F5
386 #define EOFN_NEG 0xBC95D5D5
387 #define EOFN_POS 0xBCB5D5D5
388 #define EOFNI_NEG 0xBC8AD5D5
389 #define EOFNI_POS 0xBCAAD5D5
390 #define EOFDTI_NEG 0xBC8A9595
391 #define EOFDTI_POS 0xBCAA9595
392 #define EOFRT_NEG 0xBC959999
393 #define EOFRT_POS 0xBCB59999
394 #define EOFRTI_NEG 0xBC8A9999
395 #define EOFRTI_POS 0xBCAA9999
397 static const value_string fc_sof_vals[] = {
398 {FC_SOFC1, "SOFc1 - SOF Connect Class 1 (Obsolete)" },
399 {FC_SOFI1, "SOFi1 - SOF Initiate Class 1 (Obsolete)" },
400 {FC_SOFN1, "SOFn1 - SOF Normal Class 1 (Obsolete)" },
401 {FC_SOFI2, "SOFi2 - SOF Initiate Class 2" },
402 {FC_SOFN2, "SOFn2 - SOF Normal Class 2" },
403 {FC_SOFI3, "SOFi3 - SOF Initiate Class 3" },
404 {FC_SOFN3, "SOFn3 - SOF Normal Class 3" },
405 {FC_SOFC4, "SOFc4 - SOF Activate Class 4 (Obsolete)" },
406 {FC_SOFI4, "SOFi4 - SOF Initiate Class 4 (Obsolete)" },
407 {FC_SOFN4, "SOFn4 - SOF Normal Class 4 (Obsolete)" },
408 {FC_SOFF, "SOFf - SOF Fabric" },
412 static const value_string fc_eof_vals[] = {
413 {EOFT_NEG, "EOFt- - EOF Terminate" },
414 {EOFT_POS, "EOFt+ - EOF Terminate" },
415 {EOFDT_NEG, "EOFdt- - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
416 {EOFDT_POS, "EOFdt+ - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
417 {EOFA_NEG, "EOFa- - EOF Abort" },
418 {EOFA_POS, "EOFa+ - EOF Abort" },
419 {EOFN_NEG, "EOFn- - EOF Normal" },
420 {EOFN_POS, "EOFn+ - EOF Normal" },
421 {EOFNI_NEG, "EOFni- - EOF Normal Invalid" },
422 {EOFNI_POS, "EOFni+ - EOF Normal Invalid" },
423 {EOFDTI_NEG, "EOFdti- - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
424 {EOFDTI_POS, "EOFdti+ - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
425 {EOFRT_NEG, "EOFrt- - EOF Remove-Terminate Class 4 (Obsolete)" },
426 {EOFRT_POS, "EOFrt+ - EOF Remove-Terminate Class 4 (Obsolete)" },
427 {EOFRTI_NEG, "EOFrti- - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
428 {EOFRTI_POS, "EOFrti+ - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
432 /* BA_ACC & BA_RJT are decoded in this file itself instead of a traditional
433 * dedicated file and dissector format because the dissector would require some
434 * fields of the FC_HDR such as param in some cases, type in some others, the
435 * lower 4 bits of r_ctl in some other cases etc. So, we decode BLS & Link Ctl
436 * in this file itself.
439 dissect_fc_ba_acc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
441 /* Set up structures needed to add the protocol subtree and manage it */
442 proto_tree *acc_tree;
445 /* Make entries in Protocol column and Info column on summary display */
446 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
448 col_set_str(pinfo->cinfo, COL_INFO, "BA_ACC");
451 acc_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_fcbls, NULL, "Basic Link Svc");
453 proto_tree_add_item (acc_tree, hf_fc_bls_seqid_vld, tvb, offset++, 1, ENC_BIG_ENDIAN);
454 proto_tree_add_item (acc_tree, hf_fc_bls_lastvld_seqid, tvb, offset++, 1, ENC_BIG_ENDIAN);
455 offset += 2; /* Skip reserved field */
456 proto_tree_add_item (acc_tree, hf_fc_bls_oxid, tvb, offset, 2, ENC_BIG_ENDIAN);
458 proto_tree_add_item (acc_tree, hf_fc_bls_rxid, tvb, offset, 2, ENC_BIG_ENDIAN);
460 proto_tree_add_item (acc_tree, hf_fc_bls_lowseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
462 proto_tree_add_item (acc_tree, hf_fc_bls_hiseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
467 dissect_fc_ba_rjt (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
469 /* Set up structures needed to add the protocol subtree and manage it */
470 proto_tree *rjt_tree;
473 /* Make entries in Protocol column and Info column on summary display */
474 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
476 col_set_str(pinfo->cinfo, COL_INFO, "BA_RJT");
479 rjt_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_fcbls, NULL, "Basic Link Svc");
481 proto_tree_add_item (rjt_tree, hf_fc_bls_rjtcode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
482 proto_tree_add_item (rjt_tree, hf_fc_bls_rjtdetail, tvb, offset+2, 1, ENC_BIG_ENDIAN);
483 proto_tree_add_item (rjt_tree, hf_fc_bls_vendor, tvb, offset+3, 1, ENC_BIG_ENDIAN);
488 fc_get_ftype (guint8 r_ctl, guint8 type)
490 /* A simple attempt to determine the upper level protocol based on the
491 * r_ctl & type fields.
493 switch (r_ctl & 0xF0) {
494 case FC_RCTL_DEV_DATA:
497 if ((r_ctl == 0x2) || (r_ctl == 0x3))
498 return FC_FTYPE_SWILS;
500 return FC_FTYPE_UNDEF;
504 return FC_FTYPE_SCSI;
506 return FC_FTYPE_FCCT;
507 case FC_TYPE_SB_FROM_CU:
508 case FC_TYPE_SB_TO_CU:
509 return FC_FTYPE_SBCCS;
511 return FC_FTYPE_OHMS;
513 return FC_FTYPE_UNDEF;
516 if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3))
518 else if (type == FC_TYPE_ELS)
519 return FC_FTYPE_OHMS;
521 return FC_FTYPE_UNDEF;
522 case FC_RCTL_LINK_DATA:
525 return FC_FTYPE_SCSI;
527 return FC_FTYPE_LINKDATA;
535 return FC_FTYPE_UNDEF;
536 case FC_RCTL_LINK_CTL:
537 return FC_FTYPE_LINKCTL;
539 return FC_FTYPE_UNDEF;
543 static const value_string abts_ack_vals[] = {
544 {0x000000, "ABTS - Cont"},
545 {0x000010, "ABTS - Abort"},
546 {0x000020, "ABTS - Stop"},
547 {0x000030, "ABTS - Imm Seq Retx"},
551 static const value_string abts_not_ack_vals[] = {
552 {0x000000, "ABTS - Abort/MS"},
553 {0x000010, "ABTS - Abort/SS"},
554 {0x000020, "ABTS - Process/IB"},
555 {0x000030, "ABTS - Discard/MS/Imm Retx"},
559 static const value_string last_data_frame_vals[] = {
560 {0x000000, "Last Data Frame - No Info"},
561 {0x004000, "Last Data Frame - Seq Imm"},
562 {0x008000, "Last Data Frame - Seq Soon"},
563 {0x00c000, "Last Data Frame - Seq Delyd"},
566 static const value_string ack_0_1_vals[] = {
567 {0x003000, "ACK_0 Required"},
568 {0x002000, "ACK_0 Required"},
569 {0x001000, "ACK_1 Required"},
570 {0x000000, "no ack required"},
573 static const true_false_string tfs_fc_fctl_exchange_responder = {
574 "Exchange Responder",
575 "Exchange Originator"
577 static const true_false_string tfs_fc_fctl_seq_recipient = {
581 static const true_false_string tfs_fc_fctl_exchange_first = {
585 static const true_false_string tfs_fc_fctl_exchange_last = {
589 static const true_false_string tfs_fc_fctl_seq_last = {
593 static const true_false_string tfs_fc_fctl_priority = {
597 static const true_false_string tfs_fc_fctl_transfer_seq_initiative = {
598 "Transfer Seq Initiative",
599 "NOT transfer seq initiative"
601 static const true_false_string tfs_fc_fctl_rexmitted_seq = {
602 "Retransmitted Sequence",
603 "NOT retransmitted sequence"
605 static const true_false_string tfs_fc_fctl_rel_offset = {
611 * Dissect the VFT header.
614 dissect_fc_vft(proto_tree *parent_tree,
615 tvbuff_t *tvb, int offset)
626 rctl = tvb_get_guint8(tvb, offset);
627 type = tvb_get_guint8(tvb, offset + 1);
628 ver = (type >> 6) & 3;
629 type = (type >> 2) & 0xf;
630 vf_id = tvb_get_ntohs(tvb, offset + 2);
631 pri = (vf_id >> 13) & 7;
632 vf_id = (vf_id >> 1) & 0xfff;
633 hop_ct = tvb_get_guint8(tvb, offset + 4);
635 item = proto_tree_add_uint_format_value(parent_tree, hf_fc_vft, tvb, offset,
636 8, vf_id, "VF_ID %d Pri %d Hop Count %d",
638 tree = proto_item_add_subtree(item, ett_fc_vft);
639 proto_tree_add_uint(tree, hf_fc_vft_rctl, tvb, offset, 1, rctl);
640 proto_tree_add_uint(tree, hf_fc_vft_ver, tvb, offset + 1, 1, ver);
641 proto_tree_add_uint(tree, hf_fc_vft_type, tvb, offset + 1, 1, type);
642 proto_tree_add_uint(tree, hf_fc_vft_pri, tvb, offset + 2, 1, pri);
643 proto_tree_add_uint(tree, hf_fc_vft_vf_id, tvb, offset + 2, 2, vf_id);
644 proto_tree_add_uint(tree, hf_fc_vft_hop_ct, tvb, offset + 4, 1, hop_ct);
647 /* code to dissect the F_CTL bitmask */
649 dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset)
651 static const int * flags[] = {
652 &hf_fc_fctl_exchange_responder,
653 &hf_fc_fctl_seq_recipient,
654 &hf_fc_fctl_exchange_first,
655 &hf_fc_fctl_exchange_last,
656 &hf_fc_fctl_seq_last,
657 &hf_fc_fctl_priority,
658 &hf_fc_fctl_transfer_seq_initiative,
659 &hf_fc_fctl_last_data_frame,
661 &hf_fc_fctl_rexmitted_seq,
662 &hf_fc_fctl_abts_ack,
663 &hf_fc_fctl_rel_offset,
667 proto_tree_add_bitmask_with_flags(parent_tree, tvb, offset, hf_fc_fctl,
668 ett_fctl, flags, ENC_BIG_ENDIAN, BMT_NO_INT);
671 static const value_string fc_bls_proto_val[] = {
672 {FC_BLS_NOP , "NOP"},
673 {FC_BLS_ABTS , "ABTS"},
674 {FC_BLS_RMC , "RMC"},
675 {FC_BLS_BAACC , "BA_ACC"},
676 {FC_BLS_BARJT , "BA_RJT"},
677 {FC_BLS_PRMT , "PRMT"},
681 static const value_string fc_els_proto_val[] = {
682 {0x01 , "Solicited Data"},
688 /* Code to actually dissect the packets */
690 dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_ifcp, fc_data_t* fc_data)
692 /* Set up structures needed to add the protocol subtree and manage it */
693 proto_item *ti, *hidden_item;
696 int offset = 0, next_offset;
698 gboolean is_lastframe_inseq, is_1frame_inseq, is_exchg_resp = 0;
699 fragment_head *fcfrag_head;
700 guint32 frag_id, frag_size;
701 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 SET_ADDRESS(&addr, AT_FC, 3, fchdr.d_id.data);
917 proto_tree_add_item(fc_tree, hf_fc_did, tvb, offset+1, 3, ENC_NA);
918 hidden_item = proto_tree_add_item (fc_tree, hf_fc_id, tvb, offset+1, 3, ENC_NA);
919 PROTO_ITEM_SET_HIDDEN(hidden_item);
921 proto_tree_add_uint (fc_tree, hf_fc_csctl, tvb, offset+4, 1, fchdr.cs_ctl);
923 /* XXX - use "fc_wka_vals[]" on this? */
924 SET_ADDRESS(&addr, AT_FC, 3, fchdr.s_id.data);
925 proto_tree_add_item(fc_tree, hf_fc_sid, tvb, offset+5, 3, ENC_NA);
926 hidden_item = proto_tree_add_item (fc_tree, hf_fc_id, tvb, offset+5, 3, ENC_NA);
927 PROTO_ITEM_SET_HIDDEN(hidden_item);
929 if (ftype == FC_FTYPE_LINKCTL) {
930 if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYB) ||
931 ((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYL)) {
932 /* for F_BSY frames, the upper 4 bits of the type field specify the
933 * reason for the BSY.
935 proto_tree_add_uint_format_value(fc_tree, hf_fc_type, tvb,
936 offset+8, FC_TYPE_SIZE,
937 fchdr.type,"0x%x(%s)", fchdr.type,
938 fclctl_get_typestr ((guint8) (fchdr.r_ctl & 0x0F),
941 proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
944 proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
948 dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9);
949 f_ctl = tvb_get_ntoh24(tvb, offset+9);
952 proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, ENC_BIG_ENDIAN);
954 df_ctl = tvb_get_guint8(tvb, offset+13);
956 proto_tree_add_uint (fc_tree, hf_fc_dfctl, tvb, offset+13, 1, df_ctl);
957 proto_tree_add_uint (fc_tree, hf_fc_seqcnt, tvb, offset+14, 2, fchdr.seqcnt);
958 proto_tree_add_uint (fc_tree, hf_fc_oxid, tvb, offset+16, 2, fchdr.oxid);
959 proto_tree_add_uint (fc_tree, hf_fc_rxid, tvb, offset+18, 2, fchdr.rxid);
961 if (ftype == FC_FTYPE_LINKCTL) {
962 if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FRJT) ||
963 ((fchdr.r_ctl & 0x0F) == FC_LCTL_PRJT) ||
964 ((fchdr.r_ctl & 0x0F) == FC_LCTL_PBSY)) {
965 /* In all these cases of Link Ctl frame, the parameter field
966 * encodes the detailed error message
968 proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
971 fclctl_get_paramstr ((fchdr.r_ctl & 0x0F),
974 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
976 } else if (ftype == FC_FTYPE_BLS) {
977 if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
978 proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
981 ((param & 0x0F) == 1 ? "Abort Sequence" :
984 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20,
987 } else if (ftype == FC_FTYPE_SCSI ) {
988 if (f_ctl&FC_FCTL_REL_OFFSET){
989 proto_tree_add_item (fc_tree, hf_fc_relative_offset, tvb, offset+20, 4, ENC_BIG_ENDIAN);
990 fchdr.relative_offset=tvb_get_ntohl(tvb, offset+20);
992 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
995 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
998 /* Skip the Frame_Header */
999 next_offset = offset + FC_HEADER_SIZE;
1001 /* Network_Header present? */
1002 if (df_ctl & FC_DFCTL_NH) {
1003 proto_tree_add_item(fc_tree, hf_fc_nh_da, tvb, next_offset, 8, ENC_NA);
1004 proto_tree_add_item(fc_tree, hf_fc_nh_sa, tvb, next_offset+8, 8, ENC_NA);
1008 /* XXX - handle Association_Header and Device_Header here */
1010 if (ftype == FC_FTYPE_LINKCTL) {
1011 /* ACK_1 frames and other LINK_CTL frames echo the last seq bit if the
1012 * packet they're ack'ing did not have it set. So, we'll incorrectly
1013 * flag them as being fragmented when they're not. This fixes the
1016 is_lastframe_inseq = TRUE;
1018 is_exchg_resp = (f_ctl & FC_FCTL_EXCHANGE_RESPONDER) != 0;
1021 if (tvb_reported_length (tvb) < FC_HEADER_SIZE)
1022 THROW(ReportedBoundsError);
1024 frag_size = tvb_reported_length (tvb)-FC_HEADER_SIZE;
1026 /* If there is an MDS header, we need to subtract the MDS trailer size
1027 * Link Ctl, BLS & OHMS are all (encap header + FC Header + encap trailer)
1028 * and are never fragmented and so we ignore the frag_size assertion for
1031 if ((fc_data->ethertype == ETHERTYPE_UNK) || (fc_data->ethertype == ETHERTYPE_FCFT)) {
1032 if ((frag_size < MDSHDR_TRAILER_SIZE) ||
1033 ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1034 (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1035 THROW(ReportedBoundsError);
1036 frag_size -= MDSHDR_TRAILER_SIZE;
1037 } else if (fc_data->ethertype == ETHERTYPE_BRDWALK) {
1038 if ((frag_size <= 8) ||
1039 ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1040 (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1041 THROW(ReportedBoundsError);
1042 frag_size -= 8; /* 4 byte of FC CRC +
1043 4 bytes of error+EOF = 8 bytes */
1046 if (!is_lastframe_inseq) {
1047 /* Show this only as a fragmented FC frame */
1048 col_append_str (pinfo->cinfo, COL_INFO, " (Fragmented)");
1051 /* If this is a fragment, attempt to check if fully reassembled frame is
1052 * present, if we're configured to reassemble.
1054 if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS) &&
1055 (ftype != FC_FTYPE_OHMS) &&
1056 (!is_lastframe_inseq || !is_1frame_inseq) && fc_reassemble &&
1057 tvb_bytes_exist(tvb, FC_HEADER_SIZE, frag_size) && tree) {
1058 /* Add this to the list of fragments */
1060 /* In certain cases such as FICON, the SEQ_CNT is streaming
1061 * i.e. continuously increasing. So, zero does not signify the
1062 * first frame of the sequence. To fix this, we need to save the
1063 * SEQ_CNT of the first frame in sequence and use this value to
1064 * determine the actual offset into a frame.
1066 ckey.conv_idx = conversation->index;
1068 cdata = (fcseq_conv_data_t *)g_hash_table_lookup (fcseq_req_hash,
1071 if (is_1frame_inseq) {
1073 /* Since we never free the memory used by an exchange, this maybe a
1074 * case of another request using the same exchange as a previous
1077 cdata->seq_cnt = fchdr.seqcnt;
1080 req_key = wmem_new(wmem_file_scope(), fcseq_conv_key_t);
1081 req_key->conv_idx = conversation->index;
1083 cdata = wmem_new(wmem_file_scope(), fcseq_conv_data_t);
1084 cdata->seq_cnt = fchdr.seqcnt;
1086 g_hash_table_insert (fcseq_req_hash, req_key, cdata);
1090 else if (cdata != NULL) {
1091 real_seqcnt = fchdr.seqcnt - cdata->seq_cnt ;
1094 real_seqcnt = fchdr.seqcnt;
1097 /* Verify that this is a valid fragment */
1098 if (is_lastframe_inseq && !is_1frame_inseq && !real_seqcnt) {
1099 /* This is a frame that purports to be the last frame in a
1100 * sequence, is not the first frame, but has a seqcnt that is
1101 * 0. This is a bogus frame, don't attempt to reassemble it.
1103 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1104 col_append_str (pinfo->cinfo, COL_INFO, " (Bogus Fragment)");
1107 frag_id = ((fchdr.oxid << 16) ^ seq_id) | is_exchg_resp ;
1109 /* We assume that all frames are of the same max size */
1110 fcfrag_head = fragment_add (&fc_reassembly_table,
1111 tvb, FC_HEADER_SIZE,
1112 pinfo, frag_id, NULL,
1113 real_seqcnt * fc_max_frame_size,
1115 !is_lastframe_inseq);
1118 next_tvb = tvb_new_chain(tvb, fcfrag_head->tvb_data);
1120 /* Add the defragmented data to the data source list. */
1121 add_new_data_source(pinfo, next_tvb, "Reassembled FC");
1123 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1124 tvb, offset+9, 1, 1);
1125 PROTO_ITEM_SET_HIDDEN(hidden_item);
1128 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1129 tvb, offset+9, 1, 0);
1130 PROTO_ITEM_SET_HIDDEN(hidden_item);
1131 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1132 call_dissector (data_handle, next_tvb, pinfo, tree);
1137 hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1138 tvb, offset+9, 1, 0);
1139 PROTO_ITEM_SET_HIDDEN(hidden_item);
1140 next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1143 if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS)) {
1144 /* If relative offset is used, only dissect the pdu with
1145 * offset 0 (param) */
1146 if( (fchdr.fctl&FC_FCTL_REL_OFFSET) && param ){
1147 call_dissector (data_handle, next_tvb, pinfo, tree);
1149 if (!dissector_try_uint_new (fcftype_dissector_table, ftype,
1150 next_tvb, pinfo, tree, FALSE, &fchdr)) {
1151 call_dissector (data_handle, next_tvb, pinfo, tree);
1154 } else if (ftype == FC_FTYPE_BLS) {
1155 if ((fchdr.r_ctl & 0x0F) == FC_BLS_BAACC) {
1156 dissect_fc_ba_acc (next_tvb, pinfo, tree);
1157 } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_BARJT) {
1158 dissect_fc_ba_rjt (next_tvb, pinfo, tree);
1159 } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
1160 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
1161 col_set_str(pinfo->cinfo, COL_INFO, "ABTS");
1165 /* Lun is only populated by subdissectors, and subsequent packets assume the same lun.
1166 The only way that consistently works is to save the lun on the first pass (with OXID as
1167 key) when packets are guaranteed to be parsed consecutively */
1169 /* Set up LUN data */
1170 if (!pinfo->fd->flags.visited) {
1171 wmem_tree_insert32(fc_conv_data->luns, fchdr.oxid, GUINT_TO_POINTER((guint)fchdr.lun));
1174 exchange_key = ((fchdr.oxid & 0xFFFF) | ((fchdr.lun << 16) & 0xFFFF0000));
1176 /* set up the exchange data */
1177 /* XXX we should come up with a way to handle when the 16bit oxid wraps
1178 * so that large traces will work
1180 fc_ex=(fc_exchange_t*)wmem_tree_lookup32(fc_conv_data->exchanges, exchange_key);
1182 fc_ex=wmem_new(wmem_file_scope(), fc_exchange_t);
1183 fc_ex->first_exchange_frame=0;
1184 fc_ex->last_exchange_frame=0;
1185 fc_ex->fc_time=pinfo->fd->abs_ts;
1187 wmem_tree_insert32(fc_conv_data->exchanges, exchange_key, fc_ex);
1190 fchdr.fc_ex = fc_ex;
1192 /* populate the exchange struct */
1193 if(!pinfo->fd->flags.visited){
1194 if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
1195 fc_ex->first_exchange_frame=pinfo->fd->num;
1196 fc_ex->fc_time = pinfo->fd->abs_ts;
1198 if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1199 fc_ex->last_exchange_frame=pinfo->fd->num;
1203 /* put some nice exchange data in the tree */
1204 if(!(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST)){
1206 it=proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
1207 PROTO_ITEM_SET_GENERATED(it);
1208 if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1210 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fc_ex->fc_time);
1211 it=proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
1212 PROTO_ITEM_SET_GENERATED(it);
1215 if(!(fchdr.fctl&FC_FCTL_EXCHANGE_LAST)){
1217 it=proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
1218 PROTO_ITEM_SET_GENERATED(it);
1221 tap_queue_packet(fc_tap, pinfo, &fchdr);
1225 dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1227 fc_data_t* fc_data = (fc_data_t*)data;
1232 dissect_fc_helper (tvb, pinfo, tree, FALSE, fc_data);
1233 return tvb_captured_length(tvb);
1237 dissect_fc_wtap (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1241 fc_data.ethertype = ETHERTYPE_UNK;
1242 fc_data.sof_eof = 0;
1244 dissect_fc_helper (tvb, pinfo, tree, FALSE, &fc_data);
1245 return tvb_captured_length(tvb);
1249 dissect_fc_ifcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1251 fc_data_t* fc_data = (fc_data_t*)data;
1256 dissect_fc_helper (tvb, pinfo, tree, TRUE, fc_data);
1257 return tvb_captured_length(tvb);
1261 dissect_fcsof(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1263 proto_item *it = NULL;
1264 proto_tree *fcsof_tree = NULL;
1265 tvbuff_t *next_tvb, *checksum_tvb;
1268 guint32 crc_computed = 0;
1270 gint crc_offset = 0;
1271 gint eof_offset = 0;
1272 gint sof_offset = 0;
1273 const gint FCSOF_TRAILER_LEN = 8;
1274 const gint FCSOF_HEADER_LEN = 4;
1275 gint frame_len_for_checksum = 0;
1278 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
1280 crc_offset = tvb_reported_length(tvb) - FCSOF_TRAILER_LEN;
1281 eof_offset = crc_offset + 4;
1285 sof = tvb_get_ntohl(tvb, 0);
1288 crc = tvb_get_ntohl(tvb, crc_offset);
1290 /* GET Computed CRC */
1291 frame_len_for_checksum = crc_offset - FCSOF_HEADER_LEN;
1292 checksum_tvb = tvb_new_subset_length(tvb, 4, frame_len_for_checksum);
1293 crc_computed = crc32_802_tvb(checksum_tvb, frame_len_for_checksum);
1296 eof = tvb_get_ntohl(tvb, eof_offset);
1298 it = proto_tree_add_protocol_format(tree, proto_fcsof, tvb, 0,
1299 4, "Fibre Channel Delimiter: SOF: %s EOF: %s",
1300 val_to_str(sof, fc_sof_vals, "0x%x"),
1301 val_to_str(eof, fc_eof_vals, "0x%x"));
1303 fcsof_tree = proto_item_add_subtree(it, ett_fcsof);
1305 proto_tree_add_uint(fcsof_tree, hf_fcsof, tvb, sof_offset, 4, sof);
1307 if (crc == crc_computed) {
1308 proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1310 "%8.8x [valid]", crc);
1312 it = proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1314 "%8.8x [error: should be %8.8x]",
1317 expert_add_info_format(pinfo, it, &ei_fccrc,
1318 "Bad FC CRC %8.8x %8.x",
1322 proto_tree_add_uint(fcsof_tree, hf_fceof, tvb, eof_offset, 4, eof);
1324 next_tvb = tvb_new_subset_remaining(tvb, 4);
1326 fc_data.ethertype = 0;
1327 fc_data.sof_eof = 0;
1328 if (sof == FC_SOFI2 || sof == FC_SOFI3) {
1329 fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME;
1330 } else if (sof == FC_SOFF) {
1331 fc_data.sof_eof = FC_DATA_SOF_SOFF;
1334 if (eof == EOFT_POS || eof == EOFT_NEG) {
1335 fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME;
1336 } else if (eof == EOFDTI_NEG || eof == EOFDTI_POS) {
1337 fc_data.sof_eof |= FC_DATA_EOF_INVALID;
1340 /* Call FC dissector */
1341 call_dissector_with_data(fc_handle, next_tvb, pinfo, tree, &fc_data);
1344 /* Register the protocol with Wireshark */
1346 /* this format is require because a script is used to build the C function
1347 that calls all the protocol registration.
1351 proto_register_fc(void)
1354 /* Setup list of header fields See Section 1.6.1 for details*/
1355 static hf_register_info hf[] = {
1357 { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1360 {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
1361 0x0, "Derived Type", HFILL}},
1363 { "Dest Addr", "fc.d_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1364 "Destination Address", HFILL}},
1366 {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1369 {"Src Addr", "fc.s_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1370 "Source Address", HFILL}},
1372 {"Addr", "fc.id", FT_BYTES, SEP_DOT, NULL, 0x0,
1373 "Source or Destination Address", HFILL}},
1375 {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
1378 {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1380 {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
1381 "Sequence ID", HFILL}},
1383 {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1385 {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
1386 "Sequence Count", HFILL}},
1388 {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
1391 {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
1394 {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL,
1397 { &hf_fc_reassembled,
1398 {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_NONE, NULL,
1401 {"Network DA", "fc.nethdr.da", FT_FCWWN, BASE_NONE, NULL,
1404 {"Network SA", "fc.nethdr.sa", FT_FCWWN, BASE_NONE, NULL,
1407 /* Basic Link Svc field definitions */
1408 { &hf_fc_bls_seqid_vld,
1409 {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8, BASE_HEX,
1410 VALS (fc_bls_seqid_val), 0x0, NULL, HFILL}},
1411 { &hf_fc_bls_lastvld_seqid,
1412 {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8, BASE_HEX, NULL,
1415 {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1417 {"RXID", "fc.bls_rxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1418 { &hf_fc_bls_lowseqcnt,
1419 {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1421 { &hf_fc_bls_hiseqcnt,
1422 {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1424 { &hf_fc_bls_rjtcode,
1425 {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
1427 { &hf_fc_bls_rjtdetail,
1428 {"Reason Explanation", "fc.bls_rjtdetail", FT_UINT8, BASE_HEX,
1429 VALS (fc_bls_barjt_det_val), 0x0, NULL, HFILL}},
1430 { &hf_fc_bls_vendor,
1431 {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8, BASE_HEX, NULL,
1433 { &hf_fc_fctl_exchange_responder,
1434 {"ExgRpd", "fc.fctl.exchange_responder", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_responder),
1435 FC_FCTL_EXCHANGE_RESPONDER, "Exchange Responder?", HFILL}},
1436 { &hf_fc_fctl_seq_recipient,
1437 {"SeqRec", "fc.fctl.seq_recipient", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_recipient),
1438 FC_FCTL_SEQ_RECIPIENT, "Seq Recipient?", HFILL}},
1439 { &hf_fc_fctl_exchange_first,
1440 {"ExgFst", "fc.fctl.exchange_first", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_first),
1441 FC_FCTL_EXCHANGE_FIRST, "First Exchange?", HFILL}},
1442 { &hf_fc_fctl_exchange_last,
1443 {"ExgLst", "fc.fctl.exchange_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_last),
1444 FC_FCTL_EXCHANGE_LAST, "Last Exchange?", HFILL}},
1445 { &hf_fc_fctl_seq_last,
1446 {"SeqLst", "fc.fctl.seq_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_last),
1447 FC_FCTL_SEQ_LAST, "Last Sequence?", HFILL}},
1448 { &hf_fc_fctl_priority,
1449 {"Pri", "fc.fctl.priority", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_priority),
1450 FC_FCTL_PRIORITY, "Priority", HFILL}},
1451 { &hf_fc_fctl_transfer_seq_initiative,
1452 {"TSI", "fc.fctl.transfer_seq_initiative", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_transfer_seq_initiative),
1453 FC_FCTL_TRANSFER_SEQ_INITIATIVE, "Transfer Seq Initiative", HFILL}},
1454 { &hf_fc_fctl_rexmitted_seq,
1455 {"RetSeq", "fc.fctl.rexmitted_seq", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rexmitted_seq),
1456 FC_FCTL_REXMITTED_SEQ, "Retransmitted Sequence", HFILL}},
1457 { &hf_fc_fctl_rel_offset,
1458 {"RelOff", "fc.fctl.rel_offset", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rel_offset),
1459 FC_FCTL_REL_OFFSET, "rel offset", HFILL}},
1460 { &hf_fc_fctl_last_data_frame,
1461 {"LDF", "fc.fctl.last_data_frame", FT_UINT24, BASE_HEX, VALS(last_data_frame_vals),
1462 FC_FCTL_LAST_DATA_FRAME_MASK, "Last Data Frame?", HFILL}},
1463 { &hf_fc_fctl_ack_0_1,
1464 {"A01", "fc.fctl.ack_0_1", FT_UINT24, BASE_HEX, VALS(ack_0_1_vals),
1465 FC_FCTL_ACK_0_1_MASK, "Ack 0/1 value", HFILL}},
1466 { &hf_fc_fctl_abts_ack,
1467 {"AA", "fc.fctl.abts_ack", FT_UINT24, BASE_HEX, VALS(abts_ack_vals),
1468 FC_FCTL_ABTS_MASK, "ABTS ACK values", HFILL}},
1470 { &hf_fc_fctl_abts_not_ack,
1471 {"AnA", "fc.fctl.abts_not_ack", FT_UINT24, BASE_HEX, VALS(abts_not_ack_vals),
1472 FC_FCTL_ABTS_MASK, "ABTS not ACK vals", HFILL}},
1474 { &hf_fc_exchange_first_frame,
1475 { "Exchange First In", "fc.exchange_first_frame", FT_FRAMENUM, BASE_NONE, NULL,
1476 0, "The first frame of this exchange is in this frame", HFILL }},
1477 { &hf_fc_exchange_last_frame,
1478 { "Exchange Last In", "fc.exchange_last_frame", FT_FRAMENUM, BASE_NONE, NULL,
1479 0, "The last frame of this exchange is in this frame", HFILL }},
1481 { "Time from Exchange First", "fc.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
1482 0, "Time since the first frame of the Exchange", HFILL }},
1483 { &hf_fc_relative_offset,
1484 {"Relative Offset", "fc.relative_offset", FT_UINT32, BASE_DEC, NULL,
1485 0, "Relative offset of data", HFILL}},
1487 {"VFT Header", "fc.vft", FT_UINT16, BASE_DEC, NULL,
1490 {"R_CTL", "fc.vft.rctl", FT_UINT8, BASE_HEX, NULL,
1493 {"Version", "fc.vft.ver", FT_UINT8, BASE_DEC, NULL,
1494 0, "Version of VFT header", HFILL}},
1496 {"Type", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1497 0, "Type of tagged frame", HFILL}},
1499 {"Priority", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1500 0, "QoS Priority", HFILL}},
1502 {"VF_ID", "fc.vft.vf_id", FT_UINT16, BASE_DEC, NULL,
1503 0, "Virtual Fabric ID", HFILL}},
1504 { &hf_fc_vft_hop_ct,
1505 {"HopCT", "fc.vft.hop_ct", FT_UINT8, BASE_DEC, NULL,
1506 0, "Hop Count", HFILL}},
1509 /* Setup protocol subtree array */
1510 static gint *ett[] = {
1517 static ei_register_info ei[] = {
1518 { &ei_fccrc, { "fc.crc.bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1521 module_t *fc_module;
1522 expert_module_t* expert_fc;
1526 static hf_register_info sof_hf[] = {
1528 { "SOF", "fc.sof", FT_UINT32, BASE_HEX, VALS(fc_sof_vals), 0,
1531 { "EOF", "fc.eof", FT_UINT32, BASE_HEX, VALS(fc_eof_vals), 0,
1534 { "CRC", "fc.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
1537 static gint *sof_ett[] = {
1544 /* Register the protocol name and description */
1545 proto_fc = proto_register_protocol ("Fibre Channel", "FC", "fc");
1546 fc_handle = new_register_dissector ("fc", dissect_fc, proto_fc);
1547 new_register_dissector ("fc_ifcp", dissect_fc_ifcp, proto_fc);
1548 fc_tap = register_tap("fc");
1550 /* Required function calls to register the header fields and subtrees used */
1551 proto_register_field_array(proto_fc, hf, array_length(hf));
1552 proto_register_subtree_array(ett, array_length(ett));
1553 expert_fc = expert_register_protocol(proto_fc);
1554 expert_register_field_array(expert_fc, ei, array_length(ei));
1556 /* subdissectors called through this table will find the fchdr structure
1557 * through data parameter of dissector
1559 fcftype_dissector_table = register_dissector_table ("fc.ftype",
1561 FT_UINT8, BASE_HEX);
1563 /* Register preferences */
1564 fc_module = prefs_register_protocol (proto_fc, NULL);
1565 prefs_register_bool_preference (fc_module,
1567 "Reassemble multi-frame sequences",
1568 "If enabled, reassembly of multi-frame "
1569 "sequences is done",
1571 prefs_register_uint_preference (fc_module,
1572 "max_frame_size", "Max FC Frame Size",
1573 "This is the size of non-last frames in a "
1574 "multi-frame sequence", 10,
1575 &fc_max_frame_size);
1577 register_init_routine (fc_exchange_init_protocol);
1580 /* Register FC SOF/EOF */
1581 proto_fcsof = proto_register_protocol("Fibre Channel Delimiters", "FCSoF", "fcsof");
1583 proto_register_field_array(proto_fcsof, sof_hf, array_length(sof_hf));
1584 proto_register_subtree_array(sof_ett, array_length(sof_ett));
1586 fcsof_handle = register_dissector("fcsof", dissect_fcsof, proto_fcsof);
1588 register_conversation_table(proto_fc, TRUE, fc_conversation_packet, fc_hostlist_packet);
1589 register_srt_table(proto_fc, NULL, 1, fcstat_packet, fcstat_init, NULL);
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,
1601 new_create_dissector_handle(dissect_fc_wtap, proto_fc));
1603 dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS, fcsof_handle);
1605 data_handle = find_dissector("data");
1609 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1614 * indent-tabs-mode: nil
1617 * vi: set shiftwidth=4 tabstop=8 expandtab:
1618 * :indentSize=4:tabSize=8:noTabs=true: