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 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include <epan/prefs.h>
19 #include <wiretap/wtap.h>
20 #include <epan/reassemble.h>
21 #include <epan/conversation_table.h>
22 #include <epan/srt_table.h>
23 #include "packet-fc.h"
24 #include "packet-fclctl.h"
25 #include "packet-fcbls.h"
26 #include <epan/crc32-tvb.h>
27 #include <epan/expert.h>
29 void proto_register_fc(void);
30 void proto_reg_handoff_fc(void);
32 #define FC_HEADER_SIZE 24
33 #define FC_RCTL_VFT 0x50
34 #define MDSHDR_TRAILER_SIZE 6
36 /* Size of various fields in FC header in bytes */
37 #define FC_RCTL_SIZE 1
39 #define FC_CSCTL_SIZE 1
41 #define FC_TYPE_SIZE 1
42 #define FC_FCTL_SIZE 3
43 #define FC_SEQID_SIZE 1
44 #define FC_DFCTL_SIZE 1
45 #define FC_SEQCNT_SIZE 2
46 #define FC_OXID_SIZE 2
47 #define FC_RXID_SIZE 2
48 #define FC_PARAM_SIZE 4
50 /* Initialize the protocol and registered fields */
52 static int hf_fc_time
;
53 static int hf_fc_exchange_first_frame
;
54 static int hf_fc_exchange_last_frame
;
55 static int hf_fc_rctl
;
57 static int hf_fc_csctl
;
60 static int hf_fc_type
;
61 static int hf_fc_fctl
;
62 static int hf_fc_fctl_exchange_responder
;
63 static int hf_fc_fctl_seq_recipient
;
64 static int hf_fc_fctl_exchange_first
;
65 static int hf_fc_fctl_exchange_last
;
66 static int hf_fc_fctl_seq_last
;
67 static int hf_fc_fctl_priority
;
68 static int hf_fc_fctl_transfer_seq_initiative
;
69 static int hf_fc_fctl_rexmitted_seq
;
70 static int hf_fc_fctl_rel_offset
;
71 static int hf_fc_fctl_abts_ack
;
72 /* static int hf_fc_fctl_abts_not_ack; */
73 static int hf_fc_fctl_last_data_frame
;
74 static int hf_fc_fctl_ack_0_1
;
75 static int hf_fc_seqid
;
76 static int hf_fc_dfctl
;
77 static int hf_fc_seqcnt
;
78 static int hf_fc_oxid
;
79 static int hf_fc_rxid
;
80 static int hf_fc_param
;
81 static int hf_fc_ftype
; /* Derived field, non-existent in FC hdr */
82 static int hf_fc_reassembled
;
83 static int hf_fc_relative_offset
;
87 static int hf_fc_vft_rctl
;
88 static int hf_fc_vft_ver
;
89 static int hf_fc_vft_type
;
90 static int hf_fc_vft_pri
;
91 static int hf_fc_vft_vf_id
;
92 static int hf_fc_vft_hop_ct
;
94 /* Network_Header fields */
95 static int hf_fc_nh_da
;
96 static int hf_fc_nh_sa
;
98 /* For Basic Link Svc */
99 static int hf_fc_bls_seqid_vld
;
100 static int hf_fc_bls_lastvld_seqid
;
101 static int hf_fc_bls_oxid
;
102 static int hf_fc_bls_rxid
;
103 static int hf_fc_bls_lowseqcnt
;
104 static int hf_fc_bls_hiseqcnt
;
105 static int hf_fc_bls_rjtcode
;
106 static int hf_fc_bls_rjtdetail
;
107 static int hf_fc_bls_vendor
;
110 static int proto_fcsof
;
115 static int hf_fccrc_status
;
117 static int ett_fcsof
;
118 static int ett_fceof
;
119 static int ett_fccrc
;
122 /* Initialize the subtree pointers */
125 static int ett_fcbls
;
126 static int ett_fc_vft
;
128 static expert_field ei_fccrc
;
129 static expert_field ei_short_hdr
;
130 /* static expert_field ei_frag_size; */
132 static dissector_handle_t fc_handle
, fcsof_handle
;
133 static dissector_table_t fcftype_dissector_table
;
137 typedef struct _fc_conv_data_t
{
138 wmem_tree_t
*exchanges
;
142 /* Reassembly stuff */
143 static bool fc_reassemble
= true;
144 static uint32_t fc_max_frame_size
= 1024;
145 static reassembly_table fc_reassembly_table
;
147 typedef struct _fcseq_conv_key
{
151 typedef struct _fcseq_conv_data
{
155 static wmem_map_t
*fcseq_req_hash
;
161 fcseq_equal(const void *v
, const void *w
)
163 const fcseq_conv_key_t
*v1
= (const fcseq_conv_key_t
*)v
;
164 const fcseq_conv_key_t
*v2
= (const fcseq_conv_key_t
*)w
;
166 return (v1
->conv_idx
== v2
->conv_idx
);
170 fcseq_hash (const void *v
)
172 const fcseq_conv_key_t
*key
= (const fcseq_conv_key_t
*)v
;
180 static const char* fc_conv_get_filter_type(conv_item_t
* conv
, conv_filter_type_e filter
)
182 if ((filter
== CONV_FT_SRC_ADDRESS
) && (conv
->src_address
.type
== AT_FC
))
185 if ((filter
== CONV_FT_DST_ADDRESS
) && (conv
->dst_address
.type
== AT_FC
))
188 if ((filter
== CONV_FT_ANY_ADDRESS
) && (conv
->src_address
.type
== AT_FC
))
191 return CONV_FILTER_INVALID
;
194 static ct_dissector_info_t fc_ct_dissector_info
= {&fc_conv_get_filter_type
};
196 static tap_packet_status
197 fc_conversation_packet(void *pct
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *vip
, tap_flags_t flags
)
199 conv_hash_t
*hash
= (conv_hash_t
*) pct
;
201 const fc_hdr
*fchdr
=(const fc_hdr
*)vip
;
203 add_conversation_table_data(hash
, &fchdr
->s_id
, &fchdr
->d_id
, 0, 0, 1, pinfo
->fd
->pkt_len
, &pinfo
->rel_ts
, &pinfo
->abs_ts
, &fc_ct_dissector_info
, CONVERSATION_NONE
);
205 return TAP_PACKET_REDRAW
;
208 static const char* fc_endpoint_get_filter_type(endpoint_item_t
* endpoint
, conv_filter_type_e filter
)
210 if ((filter
== CONV_FT_ANY_ADDRESS
) && (endpoint
->myaddress
.type
== AT_FC
))
213 return CONV_FILTER_INVALID
;
216 static et_dissector_info_t fc_endpoint_dissector_info
= {&fc_endpoint_get_filter_type
};
218 static tap_packet_status
219 fc_endpoint_packet(void *pit
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *vip
, tap_flags_t flags
)
221 conv_hash_t
*hash
= (conv_hash_t
*) pit
;
223 const fc_hdr
*fchdr
=(const fc_hdr
*)vip
;
225 /* Take two "add" passes per packet, adding for each direction, ensures that all
226 packets are counted properly (even if address is sending to itself)
227 XXX - this could probably be done more efficiently inside endpoint_table */
228 add_endpoint_table_data(hash
, &fchdr
->s_id
, 0, true, 1, pinfo
->fd
->pkt_len
, &fc_endpoint_dissector_info
, ENDPOINT_NONE
);
229 add_endpoint_table_data(hash
, &fchdr
->d_id
, 0, false, 1, pinfo
->fd
->pkt_len
, &fc_endpoint_dissector_info
, ENDPOINT_NONE
);
231 return TAP_PACKET_REDRAW
;
234 #define FC_NUM_PROCEDURES 256
237 fcstat_init(struct register_srt
* srt _U_
, GArray
* srt_array
)
239 srt_stat_table
*fc_srt_table
;
242 fc_srt_table
= init_srt_table("Fibre Channel Types", NULL
, srt_array
, FC_NUM_PROCEDURES
, NULL
, "fc.type", NULL
);
243 for (i
= 0; i
< FC_NUM_PROCEDURES
; i
++)
245 char* tmp_str
= val_to_str_wmem(NULL
, i
, fc_fc4_val
, "Unknown(0x%02x)");
246 init_srt_table_row(fc_srt_table
, i
, tmp_str
);
247 wmem_free(NULL
, tmp_str
);
251 static tap_packet_status
252 fcstat_packet(void *pss
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *prv
, tap_flags_t flags _U_
)
255 srt_stat_table
*fc_srt_table
;
256 srt_data_t
*data
= (srt_data_t
*)pss
;
257 const fc_hdr
*fc
=(const fc_hdr
*)prv
;
259 /* we are only interested in reply packets */
260 if(!(fc
->fctl
&FC_FCTL_EXCHANGE_RESPONDER
)){
261 return TAP_PACKET_DONT_REDRAW
;
263 /* if we havnt seen the request, just ignore it */
264 if ( (!fc
->fc_ex
) || (fc
->fc_ex
->first_exchange_frame
==0) ){
265 return TAP_PACKET_DONT_REDRAW
;
268 fc_srt_table
= g_array_index(data
->srt_array
, srt_stat_table
*, i
);
269 add_srt_table_data(fc_srt_table
, fc
->type
, &fc
->fc_ex
->fc_time
, pinfo
);
271 return TAP_PACKET_REDRAW
;
275 const value_string fc_fc4_val
[] = {
276 {FC_TYPE_BLS
, "Basic Link Svc"},
277 {FC_TYPE_ELS
, "Ext Link Svc"},
278 {FC_TYPE_LLCSNAP
, "LLC_SNAP"},
279 {FC_TYPE_IP
, "IP/FC"},
280 {FC_TYPE_SCSI
, "FCP"},
281 {FC_TYPE_FCCT
, "FC_CT"},
282 {FC_TYPE_SWILS
, "SW_ILS"},
284 {FC_TYPE_SNMP
, "SNMP"},
285 {FC_TYPE_SB_FROM_CU
, "SB-3(CU->Channel)"},
286 {FC_TYPE_SB_TO_CU
, "SB-3(Channel->CU)"},
290 static const value_string fc_ftype_vals
[] = {
291 {FC_FTYPE_UNDEF
, "Unknown frame"},
292 {FC_FTYPE_SWILS
, "SW_ILS"},
293 {FC_FTYPE_IP
, "IP/FC"},
294 {FC_FTYPE_SCSI
, "FCP"},
295 {FC_FTYPE_BLS
, "Basic Link Svc"},
296 {FC_FTYPE_ELS
, "ELS"},
297 {FC_FTYPE_FCCT
, "FC_CT"},
298 {FC_FTYPE_LINKDATA
, "Link Data"},
299 {FC_FTYPE_VDO
, "Video Data"},
300 {FC_FTYPE_LINKCTL
, "Link Ctl"},
301 {FC_FTYPE_SBCCS
, "SBCCS"},
302 {FC_FTYPE_OHMS
, "OHMS(Cisco MDS)"},
306 static const value_string fc_wka_vals
[] _U_
= {
307 {FC_WKA_MULTICAST
, "Multicast Server"},
308 {FC_WKA_CLKSYNC
, "Clock Sync Server"},
309 {FC_WKA_KEYDIST
, "Key Distribution Server"},
310 {FC_WKA_ALIAS
, "Alias Server"},
311 {FC_WKA_QOSF
, "QoS Facilitator"},
312 {FC_WKA_MGMT
, "Management Server"},
313 {FC_WKA_TIME
, "Time Server"},
314 {FC_WKA_DNS
, "Directory Server"},
315 {FC_WKA_FABRIC_CTRLR
, "Fabric Ctlr"},
316 {FC_WKA_FPORT
, "F_Port Server"},
317 {FC_WKA_BCAST
, "Broadcast ID"},
321 static const value_string fc_routing_val
[] = {
322 {FC_RCTL_DEV_DATA
, "Device_Data"},
323 {FC_RCTL_ELS
, "Extended Link Services"},
324 {FC_RCTL_LINK_DATA
, "FC-4 Link_Data"},
325 {FC_RCTL_VIDEO
, "Video_Data"},
326 {FC_RCTL_BLS
, "Basic Link Services"},
327 {FC_RCTL_LINK_CTL
, "Link_Control Frame"},
331 static const value_string fc_iu_val
[] = {
332 {FC_IU_UNCATEGORIZED
, "Uncategorized Data"},
333 {FC_IU_SOLICITED_DATA
, "Solicited Data"},
334 {FC_IU_UNSOLICITED_CTL
, "Unsolicited Control"},
335 {FC_IU_SOLICITED_CTL
, "Solicited Control"},
336 {FC_IU_UNSOLICITED_DATA
, "Solicited Data"},
337 {FC_IU_DATA_DESCRIPTOR
, "Data Descriptor"},
338 {FC_IU_UNSOLICITED_CMD
, "Unsolicited Command"},
339 {FC_IU_CMD_STATUS
, "Command Status"},
345 #define FC_SOFC1 0xBCB51717
346 #define FC_SOFI1 0xBCB55757
347 #define FC_SOFN1 0xBCB53737
348 #define FC_SOFI2 0xBCB55555
349 #define FC_SOFN2 0xBCB53535
350 #define FC_SOFI3 0xBCB55656
351 #define FC_SOFN3 0xBCB53636
352 #define FC_SOFC4 0xBCB51919
353 #define FC_SOFI4 0xBCB55959
354 #define FC_SOFN4 0xBCB53939
355 #define FC_SOFF 0xBCB55858
357 #define EOFT_NEG 0xBC957575
358 #define EOFT_POS 0xBCB57575
359 #define EOFDT_NEG 0xBC959595
360 #define EOFDT_POS 0xBCB59595
361 #define EOFA_NEG 0xBC95F5F5
362 #define EOFA_POS 0xBCB5F5F5
363 #define EOFN_NEG 0xBC95D5D5
364 #define EOFN_POS 0xBCB5D5D5
365 #define EOFNI_NEG 0xBC8AD5D5
366 #define EOFNI_POS 0xBCAAD5D5
367 #define EOFDTI_NEG 0xBC8A9595
368 #define EOFDTI_POS 0xBCAA9595
369 #define EOFRT_NEG 0xBC959999
370 #define EOFRT_POS 0xBCB59999
371 #define EOFRTI_NEG 0xBC8A9999
372 #define EOFRTI_POS 0xBCAA9999
374 static const value_string fc_sof_vals
[] = {
375 {FC_SOFC1
, "SOFc1 - SOF Connect Class 1 (Obsolete)" },
376 {FC_SOFI1
, "SOFi1 - SOF Initiate Class 1 (Obsolete)" },
377 {FC_SOFN1
, "SOFn1 - SOF Normal Class 1 (Obsolete)" },
378 {FC_SOFI2
, "SOFi2 - SOF Initiate Class 2" },
379 {FC_SOFN2
, "SOFn2 - SOF Normal Class 2" },
380 {FC_SOFI3
, "SOFi3 - SOF Initiate Class 3" },
381 {FC_SOFN3
, "SOFn3 - SOF Normal Class 3" },
382 {FC_SOFC4
, "SOFc4 - SOF Activate Class 4 (Obsolete)" },
383 {FC_SOFI4
, "SOFi4 - SOF Initiate Class 4 (Obsolete)" },
384 {FC_SOFN4
, "SOFn4 - SOF Normal Class 4 (Obsolete)" },
385 {FC_SOFF
, "SOFf - SOF Fabric" },
389 static const value_string fc_eof_vals
[] = {
390 {EOFT_NEG
, "EOFt- - EOF Terminate" },
391 {EOFT_POS
, "EOFt+ - EOF Terminate" },
392 {EOFDT_NEG
, "EOFdt- - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
393 {EOFDT_POS
, "EOFdt+ - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
394 {EOFA_NEG
, "EOFa- - EOF Abort" },
395 {EOFA_POS
, "EOFa+ - EOF Abort" },
396 {EOFN_NEG
, "EOFn- - EOF Normal" },
397 {EOFN_POS
, "EOFn+ - EOF Normal" },
398 {EOFNI_NEG
, "EOFni- - EOF Normal Invalid" },
399 {EOFNI_POS
, "EOFni+ - EOF Normal Invalid" },
400 {EOFDTI_NEG
, "EOFdti- - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
401 {EOFDTI_POS
, "EOFdti+ - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
402 {EOFRT_NEG
, "EOFrt- - EOF Remove-Terminate Class 4 (Obsolete)" },
403 {EOFRT_POS
, "EOFrt+ - EOF Remove-Terminate Class 4 (Obsolete)" },
404 {EOFRTI_NEG
, "EOFrti- - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
405 {EOFRTI_POS
, "EOFrti+ - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
409 /* BA_ACC & BA_RJT are decoded in this file itself instead of a traditional
410 * dedicated file and dissector format because the dissector would require some
411 * fields of the FC_HDR such as param in some cases, type in some others, the
412 * lower 4 bits of r_ctl in some other cases etc. So, we decode BLS & Link Ctl
413 * in this file itself.
416 dissect_fc_ba_acc (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
418 /* Set up structures needed to add the protocol subtree and manage it */
419 proto_tree
*acc_tree
;
422 /* Make entries in Protocol column and Info column on summary display */
423 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BLS");
425 col_set_str(pinfo
->cinfo
, COL_INFO
, "BA_ACC");
428 acc_tree
= proto_tree_add_subtree(tree
, tvb
, 0, -1, ett_fcbls
, NULL
, "Basic Link Svc");
430 proto_tree_add_item (acc_tree
, hf_fc_bls_seqid_vld
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
431 proto_tree_add_item (acc_tree
, hf_fc_bls_lastvld_seqid
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
432 offset
+= 2; /* Skip reserved field */
433 proto_tree_add_item (acc_tree
, hf_fc_bls_oxid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
435 proto_tree_add_item (acc_tree
, hf_fc_bls_rxid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
437 proto_tree_add_item (acc_tree
, hf_fc_bls_lowseqcnt
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
439 proto_tree_add_item (acc_tree
, hf_fc_bls_hiseqcnt
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
444 dissect_fc_ba_rjt (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
446 /* Set up structures needed to add the protocol subtree and manage it */
447 proto_tree
*rjt_tree
;
450 /* Make entries in Protocol column and Info column on summary display */
451 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BLS");
453 col_set_str(pinfo
->cinfo
, COL_INFO
, "BA_RJT");
456 rjt_tree
= proto_tree_add_subtree(tree
, tvb
, 0, -1, ett_fcbls
, NULL
, "Basic Link Svc");
458 proto_tree_add_item (rjt_tree
, hf_fc_bls_rjtcode
, tvb
, offset
+1, 1, ENC_BIG_ENDIAN
);
459 proto_tree_add_item (rjt_tree
, hf_fc_bls_rjtdetail
, tvb
, offset
+2, 1, ENC_BIG_ENDIAN
);
460 proto_tree_add_item (rjt_tree
, hf_fc_bls_vendor
, tvb
, offset
+3, 1, ENC_BIG_ENDIAN
);
465 fc_get_ftype (uint8_t r_ctl
, uint8_t type
)
467 /* A simple attempt to determine the upper level protocol based on the
468 * r_ctl & type fields.
470 switch (r_ctl
& 0xF0) {
471 case FC_RCTL_DEV_DATA
:
474 if ((r_ctl
== 0x2) || (r_ctl
== 0x3))
475 return FC_FTYPE_SWILS
;
477 return FC_FTYPE_UNDEF
;
481 return FC_FTYPE_SCSI
;
483 return FC_FTYPE_FCCT
;
484 case FC_TYPE_SB_FROM_CU
:
485 case FC_TYPE_SB_TO_CU
:
486 return FC_FTYPE_SBCCS
;
488 return FC_FTYPE_OHMS
;
490 return FC_FTYPE_UNDEF
;
493 if (((r_ctl
& 0x0F) == 0x2) || ((r_ctl
& 0x0F) == 0x3))
495 else if (type
== FC_TYPE_ELS
)
496 return FC_FTYPE_OHMS
;
498 return FC_FTYPE_UNDEF
;
499 case FC_RCTL_LINK_DATA
:
502 return FC_FTYPE_SCSI
;
504 return FC_FTYPE_LINKDATA
;
512 return FC_FTYPE_UNDEF
;
513 case FC_RCTL_LINK_CTL
:
514 return FC_FTYPE_LINKCTL
;
516 return FC_FTYPE_UNDEF
;
520 static const value_string abts_ack_vals
[] = {
521 {0x000000, "ABTS - Cont"},
522 {0x000010, "ABTS - Abort"},
523 {0x000020, "ABTS - Stop"},
524 {0x000030, "ABTS - Imm Seq Retx"},
528 static const value_string abts_not_ack_vals
[] = {
529 {0x000000, "ABTS - Abort/MS"},
530 {0x000010, "ABTS - Abort/SS"},
531 {0x000020, "ABTS - Process/IB"},
532 {0x000030, "ABTS - Discard/MS/Imm Retx"},
536 static const value_string last_data_frame_vals
[] = {
537 {0x000000, "Last Data Frame - No Info"},
538 {0x004000, "Last Data Frame - Seq Imm"},
539 {0x008000, "Last Data Frame - Seq Soon"},
540 {0x00c000, "Last Data Frame - Seq Delyd"},
543 static const value_string ack_0_1_vals
[] = {
544 {0x003000, "ACK_0 Required"},
545 {0x002000, "ACK_0 Required"},
546 {0x001000, "ACK_1 Required"},
547 {0x000000, "no ack required"},
550 static const true_false_string tfs_fc_fctl_exchange_responder
= {
551 "Exchange Responder",
552 "Exchange Originator"
554 static const true_false_string tfs_fc_fctl_seq_recipient
= {
558 static const true_false_string tfs_fc_fctl_exchange_first
= {
562 static const true_false_string tfs_fc_fctl_exchange_last
= {
566 static const true_false_string tfs_fc_fctl_seq_last
= {
570 static const true_false_string tfs_fc_fctl_priority
= {
574 static const true_false_string tfs_fc_fctl_transfer_seq_initiative
= {
575 "Transfer Seq Initiative",
576 "NOT transfer seq initiative"
578 static const true_false_string tfs_fc_fctl_rexmitted_seq
= {
579 "Retransmitted Sequence",
580 "NOT retransmitted sequence"
582 static const true_false_string tfs_fc_fctl_rel_offset
= {
588 * Dissect the VFT header.
591 dissect_fc_vft(proto_tree
*parent_tree
,
592 tvbuff_t
*tvb
, int offset
)
603 rctl
= tvb_get_uint8(tvb
, offset
);
604 type
= tvb_get_uint8(tvb
, offset
+ 1);
605 ver
= (type
>> 6) & 3;
606 type
= (type
>> 2) & 0xf;
607 vf_id
= tvb_get_ntohs(tvb
, offset
+ 2);
608 pri
= (vf_id
>> 13) & 7;
609 vf_id
= (vf_id
>> 1) & 0xfff;
610 hop_ct
= tvb_get_uint8(tvb
, offset
+ 4);
612 item
= proto_tree_add_uint_format_value(parent_tree
, hf_fc_vft
, tvb
, offset
,
613 8, vf_id
, "VF_ID %d Pri %d Hop Count %d",
615 tree
= proto_item_add_subtree(item
, ett_fc_vft
);
616 proto_tree_add_uint(tree
, hf_fc_vft_rctl
, tvb
, offset
, 1, rctl
);
617 proto_tree_add_uint(tree
, hf_fc_vft_ver
, tvb
, offset
+ 1, 1, ver
);
618 proto_tree_add_uint(tree
, hf_fc_vft_type
, tvb
, offset
+ 1, 1, type
);
619 proto_tree_add_uint(tree
, hf_fc_vft_pri
, tvb
, offset
+ 2, 1, pri
);
620 proto_tree_add_uint(tree
, hf_fc_vft_vf_id
, tvb
, offset
+ 2, 2, vf_id
);
621 proto_tree_add_uint(tree
, hf_fc_vft_hop_ct
, tvb
, offset
+ 4, 1, hop_ct
);
624 /* code to dissect the F_CTL bitmask */
626 dissect_fc_fctl(packet_info
*pinfo _U_
, proto_tree
*parent_tree
, tvbuff_t
*tvb
, int offset
)
628 static int * const flags
[] = {
629 &hf_fc_fctl_exchange_responder
,
630 &hf_fc_fctl_seq_recipient
,
631 &hf_fc_fctl_exchange_first
,
632 &hf_fc_fctl_exchange_last
,
633 &hf_fc_fctl_seq_last
,
634 &hf_fc_fctl_priority
,
635 &hf_fc_fctl_transfer_seq_initiative
,
636 &hf_fc_fctl_last_data_frame
,
638 &hf_fc_fctl_rexmitted_seq
,
639 &hf_fc_fctl_abts_ack
,
640 &hf_fc_fctl_rel_offset
,
644 proto_tree_add_bitmask_with_flags(parent_tree
, tvb
, offset
, hf_fc_fctl
,
645 ett_fctl
, flags
, ENC_BIG_ENDIAN
, BMT_NO_INT
);
648 static const value_string fc_bls_proto_val
[] = {
649 {FC_BLS_NOP
, "NOP"},
650 {FC_BLS_ABTS
, "ABTS"},
651 {FC_BLS_RMC
, "RMC"},
652 {FC_BLS_BAACC
, "BA_ACC"},
653 {FC_BLS_BARJT
, "BA_RJT"},
654 {FC_BLS_PRMT
, "PRMT"},
658 static const value_string fc_els_proto_val
[] = {
659 {0x01 , "Solicited Data"},
665 /* Code to actually dissect the packets */
667 dissect_fc_helper (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, bool is_ifcp
, fc_data_t
* fc_data
)
669 /* Set up structures needed to add the protocol subtree and manage it */
670 proto_item
*ti
, *hidden_item
;
673 int offset
= 0, next_offset
;
675 bool is_lastframe_inseq
, is_1frame_inseq
, is_exchg_resp
= 0;
676 fragment_head
*fcfrag_head
;
677 uint32_t frag_id
, frag_size
;
678 uint8_t df_ctl
, seq_id
;
682 uint32_t param
, exchange_key
;
683 uint16_t real_seqcnt
;
686 fc_hdr
* fchdr
= wmem_new(pinfo
->pool
, fc_hdr
); /* Needed by conversations, not just tap */
687 fc_exchange_t
*fc_ex
;
688 fc_conv_data_t
*fc_conv_data
=NULL
;
690 conversation_t
*conversation
;
691 fcseq_conv_data_t
*cdata
;
692 fcseq_conv_key_t ckey
, *req_key
;
694 /* Make entries in Protocol column and Info column on summary display */
695 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FC");
697 fchdr
->r_ctl
= tvb_get_uint8 (tvb
, offset
);
701 * If the frame contains a VFT (virtual fabric tag), decode it
702 * as a separate header before the FC frame header.
704 * This used to be called the Cisco-proprietary EISL field, but is now
705 * standardized in FC-FS-2. See section 10.2.4.
707 if (fchdr
->r_ctl
== FC_RCTL_VFT
) {
710 fchdr
->r_ctl
= tvb_get_uint8 (tvb
, offset
);
713 /* Each fc endpoint pair gets its own TCP session in iFCP but
714 * the src/dst ids are undefined(==semi-random) in the FC header.
715 * This means we can no track conversations for FC over iFCP by using
716 * the FC src/dst addresses.
717 * For iFCP: Do not update the pinfo src/dst struct and let it remain
718 * being tcpip src/dst so that request/response matching in the FCP layer
719 * will use ip addresses instead and still work.
722 set_address_tvb (&pinfo
->dst
, AT_FC
, 3, tvb
, offset
+1);
723 set_address_tvb (&pinfo
->src
, AT_FC
, 3, tvb
, offset
+5);
724 conversation_set_conv_addr_port_endpoints(pinfo
, &pinfo
->src
, &pinfo
->dst
, CONVERSATION_EXCHG
, 0, 0);
726 conversation_set_conv_addr_port_endpoints(pinfo
, &pinfo
->src
, &pinfo
->dst
, CONVERSATION_EXCHG
, pinfo
->srcport
, pinfo
->destport
);
728 set_address(&fchdr
->d_id
, pinfo
->dst
.type
, pinfo
->dst
.len
, pinfo
->dst
.data
);
729 set_address(&fchdr
->s_id
, pinfo
->src
.type
, pinfo
->src
.len
, pinfo
->src
.data
);
731 fchdr
->cs_ctl
= tvb_get_uint8 (tvb
, offset
+4);
732 fchdr
->type
= tvb_get_uint8 (tvb
, offset
+8);
733 fchdr
->fctl
=tvb_get_ntoh24(tvb
,offset
+9);
734 fchdr
->seqcnt
= tvb_get_ntohs (tvb
, offset
+14);
735 fchdr
->oxid
=tvb_get_ntohs(tvb
,offset
+16);
736 fchdr
->rxid
=tvb_get_ntohs(tvb
,offset
+18);
737 fchdr
->relative_offset
=0;
738 param
= tvb_get_ntohl (tvb
, offset
+20);
739 seq_id
= tvb_get_uint8 (tvb
, offset
+12);
741 /* set up a conversation and conversation data */
742 /* TODO treat the fc address s_id==00.00.00 as a wildcard matching anything */
743 conversation
=find_or_create_conversation(pinfo
);
744 fc_conv_data
=(fc_conv_data_t
*)conversation_get_proto_data(conversation
, proto_fc
);
746 fc_conv_data
=wmem_new(wmem_file_scope(), fc_conv_data_t
);
747 fc_conv_data
->exchanges
=wmem_tree_new(wmem_file_scope());
748 fc_conv_data
->luns
=wmem_tree_new(wmem_file_scope());
749 conversation_add_proto_data(conversation
, proto_fc
, fc_conv_data
);
752 /* Set up LUN data. OXID + LUN make up unique exchanges, but LUN is populated in subdissectors
753 and not necessarily in every frame. Stub it here for now */
755 if (pinfo
->fd
->visited
) {
756 fchdr
->lun
= (uint16_t)GPOINTER_TO_UINT(wmem_tree_lookup32(fc_conv_data
->luns
, fchdr
->oxid
));
759 /* In the interest of speed, if "tree" is NULL, don't do any work not
760 necessary to generate protocol tree items. */
761 ti
= proto_tree_add_protocol_format (tree
, proto_fc
, tvb
, offset
, FC_HEADER_SIZE
, "Fibre Channel");
762 fc_tree
= proto_item_add_subtree (ti
, ett_fc
);
764 /*is_ack = ((fchdr->r_ctl == 0xC0) || (fchdr->r_ctl == 0xC1));*/
766 /* There are two ways to determine if this is the first frame of a
768 * (i) The SOF bits indicate that this is the first frame OR
769 * (ii) This is an SOFf frame and seqcnt is 0.
771 is_1frame_inseq
= (((fc_data
->sof_eof
& FC_DATA_SOF_FIRST_FRAME
) == FC_DATA_SOF_FIRST_FRAME
) ||
772 (((fc_data
->sof_eof
& FC_DATA_SOF_SOFF
) == FC_DATA_SOF_SOFF
) &&
773 (fchdr
->seqcnt
== 0)));
775 is_lastframe_inseq
= ((fc_data
->sof_eof
& FC_DATA_EOF_LAST_FRAME
) == FC_DATA_EOF_LAST_FRAME
);
777 is_lastframe_inseq
|= fchdr
->fctl
& FC_FCTL_SEQ_LAST
;
778 /*is_valid_frame = ((pinfo->sof_eof & 0x40) == 0x40);*/
780 ftype
= fc_get_ftype (fchdr
->r_ctl
, fchdr
->type
);
782 col_add_str (pinfo
->cinfo
, COL_INFO
, val_to_str (ftype
, fc_ftype_vals
,
783 "Unknown Type (0x%x)"));
785 if (ftype
== FC_FTYPE_LINKCTL
)
786 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", %s",
787 val_to_str ((fchdr
->r_ctl
& 0x0F),
791 if (vft_offset
>= 0) {
792 dissect_fc_vft(fc_tree
, tvb
, vft_offset
);
794 switch (fchdr
->r_ctl
& 0xF0) {
796 case FC_RCTL_DEV_DATA
:
797 case FC_RCTL_LINK_DATA
:
799 /* the lower 4 bits of R_CTL are the information category */
800 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
801 FC_RCTL_SIZE
, fchdr
->r_ctl
,
804 val_to_str ((fchdr
->r_ctl
& 0xF0),
805 fc_routing_val
, "0x%x"),
806 val_to_str ((fchdr
->r_ctl
& 0x0F),
810 case FC_RCTL_LINK_CTL
:
811 /* the lower 4 bits of R_CTL indicate the type of link ctl frame */
812 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
813 FC_RCTL_SIZE
, fchdr
->r_ctl
,
816 val_to_str ((fchdr
->r_ctl
& 0xF0),
817 fc_routing_val
, "0x%x"),
818 val_to_str ((fchdr
->r_ctl
& 0x0F),
819 fc_lctl_proto_val
, "0x%x"));
823 switch (fchdr
->type
) {
826 /* the lower 4 bits of R_CTL indicate the type of BLS frame */
827 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
828 FC_RCTL_SIZE
, fchdr
->r_ctl
,
831 val_to_str ((fchdr
->r_ctl
& 0xF0),
832 fc_routing_val
, "0x%x"),
833 val_to_str ((fchdr
->r_ctl
& 0x0F),
834 fc_bls_proto_val
, "0x%x"));
838 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
839 FC_RCTL_SIZE
, fchdr
->r_ctl
,
842 val_to_str ((fchdr
->r_ctl
& 0xF0),
843 fc_routing_val
, "0x%x"),
844 fchdr
->r_ctl
& 0x0F);
850 switch (fchdr
->type
) {
853 /* the lower 4 bits of R_CTL indicate the type of ELS frame */
854 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
855 FC_RCTL_SIZE
, fchdr
->r_ctl
,
858 val_to_str ((fchdr
->r_ctl
& 0xF0),
859 fc_routing_val
, "0x%x"),
860 val_to_str ((fchdr
->r_ctl
& 0x0F),
861 fc_els_proto_val
, "0x%x"));
865 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
866 FC_RCTL_SIZE
, fchdr
->r_ctl
,
869 val_to_str ((fchdr
->r_ctl
& 0xF0),
870 fc_routing_val
, "0x%x"),
871 fchdr
->r_ctl
& 0x0F);
877 proto_tree_add_uint_format_value(fc_tree
, hf_fc_rctl
, tvb
, offset
,
878 FC_RCTL_SIZE
, fchdr
->r_ctl
,
881 val_to_str ((fchdr
->r_ctl
& 0xF0),
882 fc_routing_val
, "0x%x"),
883 fchdr
->r_ctl
& 0x0F);
887 hidden_item
= proto_tree_add_uint (fc_tree
, hf_fc_ftype
, tvb
, offset
, 1,
889 proto_item_set_hidden(hidden_item
);
891 /* XXX - use "fc_wka_vals[]" on this? */
892 set_address(&addr
, AT_FC
, 3, fchdr
->d_id
.data
);
893 proto_tree_add_item(fc_tree
, hf_fc_did
, tvb
, offset
+1, 3, ENC_NA
);
894 hidden_item
= proto_tree_add_item (fc_tree
, hf_fc_id
, tvb
, offset
+1, 3, ENC_NA
);
895 proto_item_set_hidden(hidden_item
);
897 proto_tree_add_uint (fc_tree
, hf_fc_csctl
, tvb
, offset
+4, 1, fchdr
->cs_ctl
);
899 /* XXX - use "fc_wka_vals[]" on this? */
900 set_address(&addr
, AT_FC
, 3, fchdr
->s_id
.data
);
901 proto_tree_add_item(fc_tree
, hf_fc_sid
, tvb
, offset
+5, 3, ENC_NA
);
902 hidden_item
= proto_tree_add_item (fc_tree
, hf_fc_id
, tvb
, offset
+5, 3, ENC_NA
);
903 proto_item_set_hidden(hidden_item
);
905 if (ftype
== FC_FTYPE_LINKCTL
) {
906 if (((fchdr
->r_ctl
& 0x0F) == FC_LCTL_FBSYB
) ||
907 ((fchdr
->r_ctl
& 0x0F) == FC_LCTL_FBSYL
)) {
908 /* for F_BSY frames, the upper 4 bits of the type field specify the
909 * reason for the BSY.
911 proto_tree_add_uint_format_value(fc_tree
, hf_fc_type
, tvb
,
912 offset
+8, FC_TYPE_SIZE
,
913 fchdr
->type
,"0x%x(%s)", fchdr
->type
,
914 fclctl_get_typestr ((uint8_t) (fchdr
->r_ctl
& 0x0F),
917 proto_tree_add_item (fc_tree
, hf_fc_type
, tvb
, offset
+8, 1, ENC_BIG_ENDIAN
);
920 proto_tree_add_item (fc_tree
, hf_fc_type
, tvb
, offset
+8, 1, ENC_BIG_ENDIAN
);
924 dissect_fc_fctl(pinfo
, fc_tree
, tvb
, offset
+9);
925 f_ctl
= tvb_get_ntoh24(tvb
, offset
+9);
928 proto_tree_add_item (fc_tree
, hf_fc_seqid
, tvb
, offset
+12, 1, ENC_BIG_ENDIAN
);
930 df_ctl
= tvb_get_uint8(tvb
, offset
+13);
932 proto_tree_add_uint (fc_tree
, hf_fc_dfctl
, tvb
, offset
+13, 1, df_ctl
);
933 proto_tree_add_uint (fc_tree
, hf_fc_seqcnt
, tvb
, offset
+14, 2, fchdr
->seqcnt
);
934 proto_tree_add_uint (fc_tree
, hf_fc_oxid
, tvb
, offset
+16, 2, fchdr
->oxid
);
935 proto_tree_add_uint (fc_tree
, hf_fc_rxid
, tvb
, offset
+18, 2, fchdr
->rxid
);
937 if (ftype
== FC_FTYPE_LINKCTL
) {
938 if (((fchdr
->r_ctl
& 0x0F) == FC_LCTL_FRJT
) ||
939 ((fchdr
->r_ctl
& 0x0F) == FC_LCTL_PRJT
) ||
940 ((fchdr
->r_ctl
& 0x0F) == FC_LCTL_PBSY
)) {
941 /* In all these cases of Link Ctl frame, the parameter field
942 * encodes the detailed error message
944 proto_tree_add_uint_format_value(fc_tree
, hf_fc_param
, tvb
,
947 fclctl_get_paramstr (pinfo
->pool
, (fchdr
->r_ctl
& 0x0F),
950 proto_tree_add_item (fc_tree
, hf_fc_param
, tvb
, offset
+20, 4, ENC_BIG_ENDIAN
);
952 } else if (ftype
== FC_FTYPE_BLS
) {
953 if ((fchdr
->r_ctl
& 0x0F) == FC_BLS_ABTS
) {
954 proto_tree_add_uint_format_value(fc_tree
, hf_fc_param
, tvb
,
957 ((param
& 0x0F) == 1 ? "Abort Sequence" :
960 proto_tree_add_item (fc_tree
, hf_fc_param
, tvb
, offset
+20,
963 } else if (ftype
== FC_FTYPE_SCSI
) {
964 if (f_ctl
&FC_FCTL_REL_OFFSET
){
965 proto_tree_add_item (fc_tree
, hf_fc_relative_offset
, tvb
, offset
+20, 4, ENC_BIG_ENDIAN
);
966 fchdr
->relative_offset
=tvb_get_ntohl(tvb
, offset
+20);
968 proto_tree_add_item (fc_tree
, hf_fc_param
, tvb
, offset
+20, 4, ENC_BIG_ENDIAN
);
971 proto_tree_add_item (fc_tree
, hf_fc_param
, tvb
, offset
+20, 4, ENC_BIG_ENDIAN
);
974 /* Skip the Frame_Header */
975 next_offset
= offset
+ FC_HEADER_SIZE
;
977 /* Network_Header present? */
978 if (df_ctl
& FC_DFCTL_NH
) {
979 proto_tree_add_item(fc_tree
, hf_fc_nh_da
, tvb
, next_offset
, 8, ENC_NA
);
980 proto_tree_add_item(fc_tree
, hf_fc_nh_sa
, tvb
, next_offset
+8, 8, ENC_NA
);
984 /* XXX - handle Association_Header and Device_Header here */
986 if (ftype
== FC_FTYPE_LINKCTL
) {
987 /* ACK_1 frames and other LINK_CTL frames echo the last seq bit if the
988 * packet they're ack'ing did not have it set. So, we'll incorrectly
989 * flag them as being fragmented when they're not. This fixes the
992 is_lastframe_inseq
= true;
994 is_exchg_resp
= (f_ctl
& FC_FCTL_EXCHANGE_RESPONDER
) != 0;
997 if (tvb_reported_length (tvb
) < FC_HEADER_SIZE
) {
998 proto_tree_add_expert(fc_tree
, pinfo
, &ei_short_hdr
,
999 tvb
, 0, tvb_reported_length(tvb
));
1003 frag_size
= tvb_reported_length (tvb
)-FC_HEADER_SIZE
;
1005 /* If there is an MDS header, we need to subtract the MDS trailer size
1006 * Link Ctl, BLS & OHMS are all (encap header + FC Header + encap trailer)
1007 * and are never fragmented and so we ignore the frag_size assertion for
1010 if (fc_data
->ethertype
== ETHERTYPE_FCFT
) {
1011 if ((frag_size
< MDSHDR_TRAILER_SIZE
) ||
1012 ((frag_size
== MDSHDR_TRAILER_SIZE
) && (ftype
!= FC_FTYPE_LINKCTL
) &&
1013 (ftype
!= FC_FTYPE_BLS
) && (ftype
!= FC_FTYPE_OHMS
))) {
1014 proto_tree_add_expert(fc_tree
, pinfo
, &ei_short_hdr
,
1015 tvb
, FC_HEADER_SIZE
, frag_size
);
1018 frag_size
-= MDSHDR_TRAILER_SIZE
;
1019 } else if (fc_data
->ethertype
== ETHERTYPE_BRDWALK
) {
1020 if (frag_size
<= 8) {
1021 proto_tree_add_expert(fc_tree
, pinfo
, &ei_short_hdr
,
1022 tvb
, FC_HEADER_SIZE
, frag_size
);
1025 frag_size
-= 8; /* 4 byte of FC CRC +
1026 4 bytes of error+EOF = 8 bytes */
1029 if (!is_lastframe_inseq
) {
1030 /* Show this only as a fragmented FC frame */
1031 col_append_str (pinfo
->cinfo
, COL_INFO
, " (Fragmented)");
1034 /* If this is a fragment, attempt to check if fully reassembled frame is
1035 * present, if we're configured to reassemble.
1037 if ((ftype
!= FC_FTYPE_LINKCTL
) && (ftype
!= FC_FTYPE_BLS
) &&
1038 (ftype
!= FC_FTYPE_OHMS
) &&
1039 (!is_lastframe_inseq
|| !is_1frame_inseq
) && fc_reassemble
&&
1040 tvb_bytes_exist(tvb
, FC_HEADER_SIZE
, frag_size
) && tree
) {
1041 /* Add this to the list of fragments */
1043 /* In certain cases such as FICON, the SEQ_CNT is streaming
1044 * i.e. continuously increasing. So, zero does not signify the
1045 * first frame of the sequence. To fix this, we need to save the
1046 * SEQ_CNT of the first frame in sequence and use this value to
1047 * determine the actual offset into a frame.
1049 ckey
.conv_idx
= conversation
->conv_index
;
1051 cdata
= (fcseq_conv_data_t
*)wmem_map_lookup (fcseq_req_hash
,
1054 if (is_1frame_inseq
) {
1056 /* Since we never free the memory used by an exchange, this maybe a
1057 * case of another request using the same exchange as a previous
1060 cdata
->seq_cnt
= fchdr
->seqcnt
;
1063 req_key
= wmem_new(wmem_file_scope(), fcseq_conv_key_t
);
1064 req_key
->conv_idx
= conversation
->conv_index
;
1066 cdata
= wmem_new(wmem_file_scope(), fcseq_conv_data_t
);
1067 cdata
->seq_cnt
= fchdr
->seqcnt
;
1069 wmem_map_insert (fcseq_req_hash
, req_key
, cdata
);
1073 else if (cdata
!= NULL
) {
1074 real_seqcnt
= fchdr
->seqcnt
- cdata
->seq_cnt
;
1077 real_seqcnt
= fchdr
->seqcnt
;
1080 /* Verify that this is a valid fragment */
1081 if (is_lastframe_inseq
&& !is_1frame_inseq
&& !real_seqcnt
) {
1082 /* This is a frame that purports to be the last frame in a
1083 * sequence, is not the first frame, but has a seqcnt that is
1084 * 0. This is a bogus frame, don't attempt to reassemble it.
1086 next_tvb
= tvb_new_subset_remaining (tvb
, next_offset
);
1087 col_append_str (pinfo
->cinfo
, COL_INFO
, " (Bogus Fragment)");
1090 frag_id
= ((fchdr
->oxid
<< 16) ^ seq_id
) | is_exchg_resp
;
1092 /* We assume that all frames are of the same max size */
1093 fcfrag_head
= fragment_add (&fc_reassembly_table
,
1094 tvb
, FC_HEADER_SIZE
,
1095 pinfo
, frag_id
, NULL
,
1096 real_seqcnt
* fc_max_frame_size
,
1098 !is_lastframe_inseq
);
1101 next_tvb
= tvb_new_chain(tvb
, fcfrag_head
->tvb_data
);
1103 /* Add the defragmented data to the data source list. */
1104 add_new_data_source(pinfo
, next_tvb
, "Reassembled FC");
1106 hidden_item
= proto_tree_add_boolean (fc_tree
, hf_fc_reassembled
,
1107 tvb
, offset
+9, 1, 1);
1108 proto_item_set_hidden(hidden_item
);
1111 hidden_item
= proto_tree_add_boolean (fc_tree
, hf_fc_reassembled
,
1112 tvb
, offset
+9, 1, 0);
1113 proto_item_set_hidden(hidden_item
);
1114 next_tvb
= tvb_new_subset_remaining (tvb
, next_offset
);
1115 call_data_dissector(next_tvb
, pinfo
, tree
);
1120 hidden_item
= proto_tree_add_boolean (fc_tree
, hf_fc_reassembled
,
1121 tvb
, offset
+9, 1, 0);
1122 proto_item_set_hidden(hidden_item
);
1123 next_tvb
= tvb_new_subset_remaining (tvb
, next_offset
);
1126 if ((ftype
!= FC_FTYPE_LINKCTL
) && (ftype
!= FC_FTYPE_BLS
)) {
1127 /* If relative offset is used, only dissect the pdu with
1128 * offset 0 (param) */
1129 if( (fchdr
->fctl
&FC_FCTL_REL_OFFSET
) && param
){
1130 call_data_dissector(next_tvb
, pinfo
, tree
);
1132 if (!dissector_try_uint_new (fcftype_dissector_table
, ftype
,
1133 next_tvb
, pinfo
, tree
, false, fchdr
)) {
1134 call_data_dissector(next_tvb
, pinfo
, tree
);
1137 } else if (ftype
== FC_FTYPE_BLS
) {
1138 if ((fchdr
->r_ctl
& 0x0F) == FC_BLS_BAACC
) {
1139 dissect_fc_ba_acc (next_tvb
, pinfo
, tree
);
1140 } else if ((fchdr
->r_ctl
& 0x0F) == FC_BLS_BARJT
) {
1141 dissect_fc_ba_rjt (next_tvb
, pinfo
, tree
);
1142 } else if ((fchdr
->r_ctl
& 0x0F) == FC_BLS_ABTS
) {
1143 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BLS");
1144 col_set_str(pinfo
->cinfo
, COL_INFO
, "ABTS");
1148 /* Lun is only populated by subdissectors, and subsequent packets assume the same lun.
1149 The only way that consistently works is to save the lun on the first pass (with OXID as
1150 key) when packets are guaranteed to be parsed consecutively */
1152 /* Set up LUN data */
1153 if (!pinfo
->fd
->visited
) {
1154 wmem_tree_insert32(fc_conv_data
->luns
, fchdr
->oxid
, GUINT_TO_POINTER((unsigned)fchdr
->lun
));
1157 exchange_key
= ((fchdr
->oxid
& 0xFFFF) | ((fchdr
->lun
<< 16) & 0xFFFF0000));
1159 /* set up the exchange data */
1160 /* XXX we should come up with a way to handle when the 16bit oxid wraps
1161 * so that large traces will work
1163 fc_ex
=(fc_exchange_t
*)wmem_tree_lookup32(fc_conv_data
->exchanges
, exchange_key
);
1165 fc_ex
=wmem_new(wmem_file_scope(), fc_exchange_t
);
1166 fc_ex
->first_exchange_frame
=0;
1167 fc_ex
->last_exchange_frame
=0;
1168 fc_ex
->fc_time
=pinfo
->abs_ts
;
1170 wmem_tree_insert32(fc_conv_data
->exchanges
, exchange_key
, fc_ex
);
1173 fchdr
->fc_ex
= fc_ex
;
1175 /* XXX: The ACK_1 frames (and other LINK_CONTROL frames) should
1176 * probably be ignored (or treated specially) for SRT purposes,
1177 * and not used to change the first exchange frame or start time
1181 /* populate the exchange struct */
1182 if(!pinfo
->fd
->visited
){
1183 if(fchdr
->fctl
&FC_FCTL_EXCHANGE_FIRST
){
1184 fc_ex
->first_exchange_frame
=pinfo
->num
;
1185 fc_ex
->fc_time
= pinfo
->abs_ts
;
1187 if(fchdr
->fctl
&FC_FCTL_EXCHANGE_LAST
){
1188 fc_ex
->last_exchange_frame
=pinfo
->num
;
1192 /* put some nice exchange data in the tree */
1193 if(!(fchdr
->fctl
&FC_FCTL_EXCHANGE_FIRST
)){
1195 it
=proto_tree_add_uint(fc_tree
, hf_fc_exchange_first_frame
, tvb
, 0, 0, fc_ex
->first_exchange_frame
);
1196 proto_item_set_generated(it
);
1197 if(fchdr
->fctl
&FC_FCTL_EXCHANGE_LAST
){
1199 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &fc_ex
->fc_time
);
1200 it
=proto_tree_add_time(ti
, hf_fc_time
, tvb
, 0, 0, &delta_ts
);
1201 proto_item_set_generated(it
);
1204 if(!(fchdr
->fctl
&FC_FCTL_EXCHANGE_LAST
)){
1206 it
=proto_tree_add_uint(fc_tree
, hf_fc_exchange_last_frame
, tvb
, 0, 0, fc_ex
->last_exchange_frame
);
1207 proto_item_set_generated(it
);
1210 tap_queue_packet(fc_tap
, pinfo
, fchdr
);
1214 dissect_fc (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
1216 fc_data_t
* fc_data
= (fc_data_t
*)data
;
1221 dissect_fc_helper (tvb
, pinfo
, tree
, false, fc_data
);
1222 return tvb_captured_length(tvb
);
1226 dissect_fc_wtap (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
1230 fc_data
.ethertype
= ETHERTYPE_UNK
;
1231 fc_data
.sof_eof
= 0;
1233 dissect_fc_helper (tvb
, pinfo
, tree
, false, &fc_data
);
1234 return tvb_captured_length(tvb
);
1238 dissect_fc_ifcp (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
, true, fc_data
);
1246 return tvb_captured_length(tvb
);
1250 dissect_fcsof(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
) {
1253 proto_tree
*fcsof_tree
;
1256 uint32_t crc_computed
;
1258 const int FCSOF_TRAILER_LEN
= 8;
1259 const int FCSOF_HEADER_LEN
= 4;
1260 int crc_offset
= tvb_reported_length(tvb
) - FCSOF_TRAILER_LEN
;
1261 int eof_offset
= crc_offset
+ 4;
1263 int frame_len_for_checksum
;
1266 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FC");
1269 sof
= tvb_get_ntohl(tvb
, 0);
1271 /* GET Computed CRC */
1272 frame_len_for_checksum
= crc_offset
- FCSOF_HEADER_LEN
;
1273 crc_computed
= crc32_802_tvb(tvb_new_subset_length(tvb
, 4, frame_len_for_checksum
), frame_len_for_checksum
);
1276 eof
= tvb_get_ntohl(tvb
, eof_offset
);
1278 it
= proto_tree_add_protocol_format(tree
, proto_fcsof
, tvb
, 0,
1279 4, "Fibre Channel Delimiter: SOF: %s EOF: %s",
1280 val_to_str(sof
, fc_sof_vals
, "0x%x"),
1281 val_to_str(eof
, fc_eof_vals
, "0x%x"));
1283 fcsof_tree
= proto_item_add_subtree(it
, ett_fcsof
);
1285 proto_tree_add_uint(fcsof_tree
, hf_fcsof
, tvb
, sof_offset
, 4, sof
);
1287 proto_tree_add_checksum(fcsof_tree
, tvb
, crc_offset
, hf_fccrc
, hf_fccrc_status
, &ei_fccrc
, pinfo
, crc_computed
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
1289 proto_tree_add_uint(fcsof_tree
, hf_fceof
, tvb
, eof_offset
, 4, eof
);
1291 next_tvb
= tvb_new_subset_length(tvb
, 4, crc_offset
-4);
1293 fc_data
.ethertype
= ETHERTYPE_UNK
;
1294 fc_data
.sof_eof
= 0;
1295 if (sof
== FC_SOFI2
|| sof
== FC_SOFI3
) {
1296 fc_data
.sof_eof
= FC_DATA_SOF_FIRST_FRAME
;
1297 } else if (sof
== FC_SOFF
) {
1298 fc_data
.sof_eof
= FC_DATA_SOF_SOFF
;
1301 if (eof
== EOFT_POS
|| eof
== EOFT_NEG
) {
1302 fc_data
.sof_eof
|= FC_DATA_EOF_LAST_FRAME
;
1303 } else if (eof
== EOFDTI_NEG
|| eof
== EOFDTI_POS
) {
1304 fc_data
.sof_eof
|= FC_DATA_EOF_INVALID
;
1307 /* Call FC dissector */
1308 call_dissector_with_data(fc_handle
, next_tvb
, pinfo
, tree
, &fc_data
);
1309 return tvb_captured_length(tvb
);
1312 /* Register the protocol with Wireshark */
1314 /* this format is require because a script is used to build the C function
1315 that calls all the protocol registration.
1319 proto_register_fc(void)
1322 /* Setup list of header fields See Section 1.6.1 for details*/
1323 static hf_register_info hf
[] = {
1325 { "R_CTL", "fc.r_ctl", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1328 {"Frame type", "fc.ftype", FT_UINT8
, BASE_HEX
, VALS(fc_ftype_vals
),
1329 0x0, "Derived Type", HFILL
}},
1331 { "Dest Addr", "fc.d_id", FT_BYTES
, SEP_DOT
, NULL
, 0x0,
1332 "Destination Address", HFILL
}},
1334 {"CS_CTL", "fc.cs_ctl", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1337 {"Src Addr", "fc.s_id", FT_BYTES
, SEP_DOT
, NULL
, 0x0,
1338 "Source Address", HFILL
}},
1340 {"Addr", "fc.id", FT_BYTES
, SEP_DOT
, NULL
, 0x0,
1341 "Source or Destination Address", HFILL
}},
1343 {"Type", "fc.type", FT_UINT8
, BASE_HEX
, VALS (fc_fc4_val
), 0x0,
1346 {"F_CTL", "fc.f_ctl", FT_UINT24
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1348 {"SEQ_ID", "fc.seq_id", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1349 "Sequence ID", HFILL
}},
1351 {"DF_CTL", "fc.df_ctl", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1353 {"SEQ_CNT", "fc.seq_cnt", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1354 "Sequence Count", HFILL
}},
1356 {"OX_ID", "fc.ox_id", FT_UINT16
, BASE_HEX
, NULL
, 0x0, "Originator ID",
1359 {"RX_ID", "fc.rx_id", FT_UINT16
, BASE_HEX
, NULL
, 0x0, "Receiver ID",
1362 {"Parameter", "fc.parameter", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
,
1365 { &hf_fc_reassembled
,
1366 {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN
, BASE_NONE
, NULL
,
1369 {"Network DA", "fc.nethdr.da", FT_FCWWN
, BASE_NONE
, NULL
,
1372 {"Network SA", "fc.nethdr.sa", FT_FCWWN
, BASE_NONE
, NULL
,
1375 /* Basic Link Svc field definitions */
1376 { &hf_fc_bls_seqid_vld
,
1377 {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8
, BASE_HEX
,
1378 VALS (fc_bls_seqid_val
), 0x0, NULL
, HFILL
}},
1379 { &hf_fc_bls_lastvld_seqid
,
1380 {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8
, BASE_HEX
, NULL
,
1383 {"OXID", "fc.bls_oxid", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1385 {"RXID", "fc.bls_rxid", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1386 { &hf_fc_bls_lowseqcnt
,
1387 {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
,
1389 { &hf_fc_bls_hiseqcnt
,
1390 {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
,
1392 { &hf_fc_bls_rjtcode
,
1393 {"Reason", "fc.bls_reason", FT_UINT8
, BASE_HEX
, VALS(fc_bls_barjt_val
),
1395 { &hf_fc_bls_rjtdetail
,
1396 {"Reason Explanation", "fc.bls_rjtdetail", FT_UINT8
, BASE_HEX
,
1397 VALS (fc_bls_barjt_det_val
), 0x0, NULL
, HFILL
}},
1398 { &hf_fc_bls_vendor
,
1399 {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8
, BASE_HEX
, NULL
,
1401 { &hf_fc_fctl_exchange_responder
,
1402 {"ExgRpd", "fc.fctl.exchange_responder", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_exchange_responder
),
1403 FC_FCTL_EXCHANGE_RESPONDER
, "Exchange Responder?", HFILL
}},
1404 { &hf_fc_fctl_seq_recipient
,
1405 {"SeqRec", "fc.fctl.seq_recipient", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_seq_recipient
),
1406 FC_FCTL_SEQ_RECIPIENT
, "Seq Recipient?", HFILL
}},
1407 { &hf_fc_fctl_exchange_first
,
1408 {"ExgFst", "fc.fctl.exchange_first", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_exchange_first
),
1409 FC_FCTL_EXCHANGE_FIRST
, "First Exchange?", HFILL
}},
1410 { &hf_fc_fctl_exchange_last
,
1411 {"ExgLst", "fc.fctl.exchange_last", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_exchange_last
),
1412 FC_FCTL_EXCHANGE_LAST
, "Last Exchange?", HFILL
}},
1413 { &hf_fc_fctl_seq_last
,
1414 {"SeqLst", "fc.fctl.seq_last", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_seq_last
),
1415 FC_FCTL_SEQ_LAST
, "Last Sequence?", HFILL
}},
1416 { &hf_fc_fctl_priority
,
1417 {"Pri", "fc.fctl.priority", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_priority
),
1418 FC_FCTL_PRIORITY
, "Priority", HFILL
}},
1419 { &hf_fc_fctl_transfer_seq_initiative
,
1420 {"TSI", "fc.fctl.transfer_seq_initiative", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_transfer_seq_initiative
),
1421 FC_FCTL_TRANSFER_SEQ_INITIATIVE
, "Transfer Seq Initiative", HFILL
}},
1422 { &hf_fc_fctl_rexmitted_seq
,
1423 {"RetSeq", "fc.fctl.rexmitted_seq", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_rexmitted_seq
),
1424 FC_FCTL_REXMITTED_SEQ
, "Retransmitted Sequence", HFILL
}},
1425 { &hf_fc_fctl_rel_offset
,
1426 {"RelOff", "fc.fctl.rel_offset", FT_BOOLEAN
, 24, TFS(&tfs_fc_fctl_rel_offset
),
1427 FC_FCTL_REL_OFFSET
, "rel offset", HFILL
}},
1428 { &hf_fc_fctl_last_data_frame
,
1429 {"LDF", "fc.fctl.last_data_frame", FT_UINT24
, BASE_HEX
, VALS(last_data_frame_vals
),
1430 FC_FCTL_LAST_DATA_FRAME_MASK
, "Last Data Frame?", HFILL
}},
1431 { &hf_fc_fctl_ack_0_1
,
1432 {"A01", "fc.fctl.ack_0_1", FT_UINT24
, BASE_HEX
, VALS(ack_0_1_vals
),
1433 FC_FCTL_ACK_0_1_MASK
, "Ack 0/1 value", HFILL
}},
1434 { &hf_fc_fctl_abts_ack
,
1435 {"AA", "fc.fctl.abts_ack", FT_UINT24
, BASE_HEX
, VALS(abts_ack_vals
),
1436 FC_FCTL_ABTS_MASK
, "ABTS ACK values", HFILL
}},
1438 { &hf_fc_fctl_abts_not_ack
,
1439 {"AnA", "fc.fctl.abts_not_ack", FT_UINT24
, BASE_HEX
, VALS(abts_not_ack_vals
),
1440 FC_FCTL_ABTS_MASK
, "ABTS not ACK vals", HFILL
}},
1442 { &hf_fc_exchange_first_frame
,
1443 { "Exchange First In", "fc.exchange_first_frame", FT_FRAMENUM
, BASE_NONE
, NULL
,
1444 0, "The first frame of this exchange is in this frame", HFILL
}},
1445 { &hf_fc_exchange_last_frame
,
1446 { "Exchange Last In", "fc.exchange_last_frame", FT_FRAMENUM
, BASE_NONE
, NULL
,
1447 0, "The last frame of this exchange is in this frame", HFILL
}},
1449 { "Time from Exchange First", "fc.time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
,
1450 0, "Time since the first frame of the Exchange", HFILL
}},
1451 { &hf_fc_relative_offset
,
1452 {"Relative Offset", "fc.relative_offset", FT_UINT32
, BASE_DEC
, NULL
,
1453 0, "Relative offset of data", HFILL
}},
1455 {"VFT Header", "fc.vft", FT_UINT16
, BASE_DEC
, NULL
,
1458 {"R_CTL", "fc.vft.rctl", FT_UINT8
, BASE_HEX
, NULL
,
1461 {"Version", "fc.vft.ver", FT_UINT8
, BASE_DEC
, NULL
,
1462 0, "Version of VFT header", HFILL
}},
1464 {"Type", "fc.vft.type", FT_UINT8
, BASE_DEC
, NULL
,
1465 0, "Type of tagged frame", HFILL
}},
1467 {"Priority", "fc.vft.pri", FT_UINT8
, BASE_DEC
, NULL
,
1468 0, "QoS Priority", HFILL
}},
1470 {"VF_ID", "fc.vft.vf_id", FT_UINT16
, BASE_DEC
, NULL
,
1471 0, "Virtual Fabric ID", HFILL
}},
1472 { &hf_fc_vft_hop_ct
,
1473 {"HopCT", "fc.vft.hop_ct", FT_UINT8
, BASE_DEC
, NULL
,
1474 0, "Hop Count", HFILL
}},
1477 /* Setup protocol subtree array */
1478 static int *ett
[] = {
1485 static ei_register_info ei
[] = {
1487 { "fc.crc.bad", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
1489 { "fc.short_hdr", PI_MALFORMED
, PI_ERROR
,
1490 "Packet length is shorter than the required header", EXPFILL
}},
1493 { "fc.frag_size", PI_MALFORMED
, PI_ERROR
,
1494 "Invalid fragment size", EXPFILL
}}
1498 module_t
*fc_module
;
1499 expert_module_t
* expert_fc
;
1503 static hf_register_info sof_hf
[] = {
1505 { "SOF", "fc.sof", FT_UINT32
, BASE_HEX
, VALS(fc_sof_vals
), 0,
1508 { "EOF", "fc.eof", FT_UINT32
, BASE_HEX
, VALS(fc_eof_vals
), 0,
1511 { "CRC", "fc.crc", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1513 { "CRC Status", "fc.crc.status", FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0, NULL
, HFILL
}},
1516 static int *sof_ett
[] = {
1523 /* Register the protocol name and description */
1524 proto_fc
= proto_register_protocol ("Fibre Channel", "FC", "fc");
1525 fc_handle
= register_dissector ("fc", dissect_fc
, proto_fc
);
1526 register_dissector ("fc_ifcp", dissect_fc_ifcp
, proto_fc
);
1527 fc_tap
= register_tap("fc");
1529 /* Required function calls to register the header fields and subtrees used */
1530 proto_register_field_array(proto_fc
, hf
, array_length(hf
));
1531 proto_register_subtree_array(ett
, array_length(ett
));
1532 expert_fc
= expert_register_protocol(proto_fc
);
1533 expert_register_field_array(expert_fc
, ei
, array_length(ei
));
1535 /* subdissectors called through this table will find the fchdr structure
1536 * through data parameter of dissector
1538 fcftype_dissector_table
= register_dissector_table ("fc.ftype",
1540 proto_fc
, FT_UINT8
, BASE_HEX
);
1542 /* Register preferences */
1543 fc_module
= prefs_register_protocol (proto_fc
, NULL
);
1544 prefs_register_bool_preference (fc_module
,
1546 "Reassemble multi-frame sequences",
1547 "If enabled, reassembly of multi-frame "
1548 "sequences is done",
1550 prefs_register_uint_preference (fc_module
,
1551 "max_frame_size", "Max FC Frame Size",
1552 "This is the size of non-last frames in a "
1553 "multi-frame sequence", 10,
1554 &fc_max_frame_size
);
1556 fcseq_req_hash
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), fcseq_hash
, fcseq_equal
);
1558 reassembly_table_register(&fc_reassembly_table
,
1559 &addresses_reassembly_table_functions
);
1562 /* Register FC SOF/EOF */
1563 proto_fcsof
= proto_register_protocol("Fibre Channel Delimiters", "FCSoF", "fcsof");
1565 proto_register_field_array(proto_fcsof
, sof_hf
, array_length(sof_hf
));
1566 proto_register_subtree_array(sof_ett
, array_length(sof_ett
));
1568 fcsof_handle
= register_dissector("fcsof", dissect_fcsof
, proto_fcsof
);
1570 register_conversation_table(proto_fc
, true, fc_conversation_packet
, fc_endpoint_packet
);
1571 register_srt_table(proto_fc
, NULL
, 1, fcstat_packet
, fcstat_init
, NULL
);
1575 /* If this dissector uses sub-dissector registration add a registration routine.
1576 This format is required because a script is used to find these routines and
1577 create the code that calls these routines.
1580 proto_reg_handoff_fc (void)
1582 dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2
,
1583 create_dissector_handle(dissect_fc_wtap
, proto_fc
));
1585 dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS
, fcsof_handle
);
1589 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1594 * indent-tabs-mode: nil
1597 * vi: set shiftwidth=4 tabstop=8 expandtab:
1598 * :indentSize=4:tabSize=8:noTabs=true: