epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / epan / dissectors / packet-fc.c
blob1d935ab8db54b4441364c9a0a80b976411e23110
1 /* packet-fc.c
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
14 #include "config.h"
16 #include <epan/packet.h>
17 #include <epan/prefs.h>
18 #include <epan/tfs.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
38 #define FC_DID_SIZE 3
39 #define FC_CSCTL_SIZE 1
40 #define FC_SID_SIZE 3
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 */
51 static int proto_fc;
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;
56 static int hf_fc_did;
57 static int hf_fc_csctl;
58 static int hf_fc_sid;
59 static int hf_fc_id;
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;
85 /* VFT fields */
86 static int hf_fc_vft;
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;
109 /* For FC SOF */
110 static int proto_fcsof;
112 static int hf_fcsof;
113 static int hf_fceof;
114 static int hf_fccrc;
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 */
123 static int ett_fc;
124 static int ett_fctl;
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;
135 static int fc_tap;
137 typedef struct _fc_conv_data_t {
138 wmem_tree_t *exchanges;
139 wmem_tree_t *luns;
140 } fc_conv_data_t;
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 {
148 uint32_t conv_idx;
149 } fcseq_conv_key_t;
151 typedef struct _fcseq_conv_data {
152 uint32_t seq_cnt;
153 } fcseq_conv_data_t;
155 static wmem_map_t *fcseq_req_hash;
158 * Hash Functions
160 static int
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);
169 static unsigned
170 fcseq_hash (const void *v)
172 const fcseq_conv_key_t *key = (const fcseq_conv_key_t *)v;
173 unsigned val;
175 val = key->conv_idx;
177 return val;
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))
183 return "fc.s_id";
185 if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_FC))
186 return "fc.d_id";
188 if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_FC))
189 return "fc.id";
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;
200 hash->flags = flags;
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))
211 return "fc.id";
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;
222 hash->flags = flags;
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
236 static void
237 fcstat_init(struct register_srt* srt _U_, GArray* srt_array)
239 srt_stat_table *fc_srt_table;
240 uint32_t i;
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_)
254 unsigned i = 0;
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"},
283 {FC_TYPE_AL, "AL"},
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)"},
287 {0, NULL}
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)"},
303 {0, NULL}
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"},
318 {0, NULL}
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"},
328 {0, NULL}
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"},
340 {0, NULL}
344 /* For FC SOF */
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" },
386 {0, NULL}
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)" },
406 {0, NULL}
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.
415 static void
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;
420 int offset = 0;
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");
427 if (tree) {
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);
434 offset += 2;
435 proto_tree_add_item (acc_tree, hf_fc_bls_rxid, tvb, offset, 2, ENC_BIG_ENDIAN);
436 offset += 2;
437 proto_tree_add_item (acc_tree, hf_fc_bls_lowseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
438 offset += 2;
439 proto_tree_add_item (acc_tree, hf_fc_bls_hiseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
443 static void
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;
448 int offset = 0;
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");
455 if (tree) {
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);
464 static uint8_t
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:
472 switch (type) {
473 case FC_TYPE_SWILS:
474 if ((r_ctl == 0x2) || (r_ctl == 0x3))
475 return FC_FTYPE_SWILS;
476 else
477 return FC_FTYPE_UNDEF;
478 case FC_TYPE_IP:
479 return FC_FTYPE_IP;
480 case FC_TYPE_SCSI:
481 return FC_FTYPE_SCSI;
482 case FC_TYPE_FCCT:
483 return FC_FTYPE_FCCT;
484 case FC_TYPE_SB_FROM_CU:
485 case FC_TYPE_SB_TO_CU:
486 return FC_FTYPE_SBCCS;
487 case FC_TYPE_VENDOR:
488 return FC_FTYPE_OHMS;
489 default:
490 return FC_FTYPE_UNDEF;
492 case FC_RCTL_ELS:
493 if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3))
494 return FC_FTYPE_ELS;
495 else if (type == FC_TYPE_ELS)
496 return FC_FTYPE_OHMS;
497 else
498 return FC_FTYPE_UNDEF;
499 case FC_RCTL_LINK_DATA:
500 switch (type) {
501 case FC_TYPE_SCSI:
502 return FC_FTYPE_SCSI;
503 default:
504 return FC_FTYPE_LINKDATA;
506 case FC_RCTL_VIDEO:
507 return FC_FTYPE_VDO;
508 case FC_RCTL_BLS:
509 if (type == 0)
510 return FC_FTYPE_BLS;
511 else
512 return FC_FTYPE_UNDEF;
513 case FC_RCTL_LINK_CTL:
514 return FC_FTYPE_LINKCTL;
515 default:
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"},
525 {0,NULL}
527 #if 0
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"},
533 {0,NULL}
535 #endif
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"},
541 {0,NULL}
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"},
548 {0,NULL}
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 = {
555 "Seq Recipient",
556 "Seq Initiator"
558 static const true_false_string tfs_fc_fctl_exchange_first = {
559 "Exchg First",
560 "NOT exchg first"
562 static const true_false_string tfs_fc_fctl_exchange_last = {
563 "Exchg Last",
564 "NOT exchg last"
566 static const true_false_string tfs_fc_fctl_seq_last = {
567 "Seq Last",
568 "NOT seq last"
570 static const true_false_string tfs_fc_fctl_priority = {
571 "Priority",
572 "CS_CTL"
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 = {
583 "Rel Offset SET",
584 "Rel Offset NOT set"
588 * Dissect the VFT header.
590 static void
591 dissect_fc_vft(proto_tree *parent_tree,
592 tvbuff_t *tvb, int offset)
594 proto_item *item;
595 proto_tree *tree;
596 uint8_t rctl;
597 uint8_t ver;
598 uint8_t type;
599 uint8_t pri;
600 uint16_t vf_id;
601 uint8_t hop_ct;
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",
614 vf_id, pri, hop_ct);
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 */
625 static void
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,
637 &hf_fc_fctl_ack_0_1,
638 &hf_fc_fctl_rexmitted_seq,
639 &hf_fc_fctl_abts_ack,
640 &hf_fc_fctl_rel_offset,
641 NULL
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"},
655 {0, NULL}
658 static const value_string fc_els_proto_val[] = {
659 {0x01 , "Solicited Data"},
660 {0x02 , "Request"},
661 {0x03 , "Reply"},
662 {0, NULL}
665 /* Code to actually dissect the packets */
666 static void
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;
671 proto_tree *fc_tree;
672 tvbuff_t *next_tvb;
673 int offset = 0, next_offset;
674 int vft_offset = -1;
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;
679 uint32_t f_ctl;
680 address addr;
682 uint32_t param, exchange_key;
683 uint16_t real_seqcnt;
684 uint8_t ftype;
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);
698 fchdr->fc_ex = NULL;
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) {
708 vft_offset = offset;
709 offset += 8;
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.
721 if(!is_ifcp){
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);
725 } else {
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);
745 if(!fc_conv_data){
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 */
754 fchdr->lun = 0xFFFF;
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
767 * sequence. Either:
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),
788 fc_lctl_proto_val,
789 "LCTL 0x%x"));
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:
798 case FC_RCTL_VIDEO:
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,
802 "0x%x(%s/%s)",
803 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),
807 fc_iu_val, "0x%x"));
808 break;
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,
814 "0x%x(%s/%s)",
815 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"));
820 break;
822 case FC_RCTL_BLS:
823 switch (fchdr->type) {
825 case 0x00:
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,
829 "0x%x(%s/%s)",
830 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"));
835 break;
837 default:
838 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
839 FC_RCTL_SIZE, fchdr->r_ctl,
840 "0x%x(%s/0x%x)",
841 fchdr->r_ctl,
842 val_to_str ((fchdr->r_ctl & 0xF0),
843 fc_routing_val, "0x%x"),
844 fchdr->r_ctl & 0x0F);
845 break;
847 break;
849 case FC_RCTL_ELS:
850 switch (fchdr->type) {
852 case 0x01:
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,
856 "0x%x(%s/%s)",
857 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"));
862 break;
864 default:
865 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
866 FC_RCTL_SIZE, fchdr->r_ctl,
867 "0x%x(%s/0x%x)",
868 fchdr->r_ctl,
869 val_to_str ((fchdr->r_ctl & 0xF0),
870 fc_routing_val, "0x%x"),
871 fchdr->r_ctl & 0x0F);
872 break;
874 break;
876 default:
877 proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
878 FC_RCTL_SIZE, fchdr->r_ctl,
879 "0x%x(%s/0x%x)",
880 fchdr->r_ctl,
881 val_to_str ((fchdr->r_ctl & 0xF0),
882 fc_routing_val, "0x%x"),
883 fchdr->r_ctl & 0x0F);
884 break;
887 hidden_item = proto_tree_add_uint (fc_tree, hf_fc_ftype, tvb, offset, 1,
888 ftype);
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),
915 fchdr->type));
916 } else {
917 proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
919 } else {
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,
945 offset+20, 4, param,
946 "0x%x(%s)", param,
947 fclctl_get_paramstr (pinfo->pool, (fchdr->r_ctl & 0x0F),
948 param));
949 } else {
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,
955 offset+20, 4, param,
956 "0x%x(%s)", param,
957 ((param & 0x0F) == 1 ? "Abort Sequence" :
958 "Abort Exchange"));
959 } else {
960 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20,
961 4, ENC_BIG_ENDIAN);
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);
967 } else {
968 proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
970 } else {
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);
981 next_offset += 16;
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
990 * problem
992 is_lastframe_inseq = true;
993 } else {
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));
1000 return;
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
1008 * these frames.
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);
1016 return;
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);
1023 return;
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,
1052 &ckey);
1054 if (is_1frame_inseq) {
1055 if (cdata) {
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
1058 * req.
1060 cdata->seq_cnt = fchdr->seqcnt;
1062 else {
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);
1071 real_seqcnt = 0;
1073 else if (cdata != NULL) {
1074 real_seqcnt = fchdr->seqcnt - cdata->seq_cnt ;
1076 else {
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)");
1088 } else {
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,
1097 frag_size,
1098 !is_lastframe_inseq);
1100 if (fcfrag_head) {
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);
1110 else {
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);
1116 return;
1119 } else {
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);
1131 } else {
1132 if (!dissector_try_uint_with_data (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);
1164 if(!fc_ex){
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
1178 * of an exchange.
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)){
1194 proto_item *it;
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){
1198 nstime_t delta_ts;
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)){
1205 proto_item *it;
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);
1213 static int
1214 dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1216 fc_data_t* fc_data = (fc_data_t*)data;
1218 if (!fc_data)
1219 return 0;
1221 dissect_fc_helper (tvb, pinfo, tree, false, fc_data);
1222 return tvb_captured_length(tvb);
1225 static int
1226 dissect_fc_wtap (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1228 fc_data_t fc_data;
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);
1237 static int
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;
1242 if (!fc_data)
1243 return 0;
1245 dissect_fc_helper (tvb, pinfo, tree, true, fc_data);
1246 return tvb_captured_length(tvb);
1249 static int
1250 dissect_fcsof(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
1252 proto_item *it;
1253 proto_tree *fcsof_tree;
1254 tvbuff_t *next_tvb;
1255 uint32_t sof;
1256 uint32_t crc_computed;
1257 uint32_t eof;
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;
1262 int sof_offset = 0;
1263 int frame_len_for_checksum;
1264 fc_data_t fc_data;
1266 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
1268 /* Get SOF */
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);
1275 /* Get EOF */
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.
1318 void
1319 proto_register_fc(void)
1322 /* Setup list of header fields See Section 1.6.1 for details*/
1323 static hf_register_info hf[] = {
1324 { &hf_fc_rctl,
1325 { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1326 NULL, HFILL }},
1327 { &hf_fc_ftype,
1328 {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
1329 0x0, "Derived Type", HFILL}},
1330 { &hf_fc_did,
1331 { "Dest Addr", "fc.d_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1332 "Destination Address", HFILL}},
1333 { &hf_fc_csctl,
1334 {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1335 NULL, HFILL}},
1336 { &hf_fc_sid,
1337 {"Src Addr", "fc.s_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1338 "Source Address", HFILL}},
1339 { &hf_fc_id,
1340 {"Addr", "fc.id", FT_BYTES, SEP_DOT, NULL, 0x0,
1341 "Source or Destination Address", HFILL}},
1342 { &hf_fc_type,
1343 {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
1344 NULL, HFILL}},
1345 { &hf_fc_fctl,
1346 {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1347 { &hf_fc_seqid,
1348 {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
1349 "Sequence ID", HFILL}},
1350 { &hf_fc_dfctl,
1351 {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1352 { &hf_fc_seqcnt,
1353 {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
1354 "Sequence Count", HFILL}},
1355 { &hf_fc_oxid,
1356 {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
1357 HFILL}},
1358 { &hf_fc_rxid,
1359 {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
1360 HFILL}},
1361 { &hf_fc_param,
1362 {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL,
1363 HFILL}},
1365 { &hf_fc_reassembled,
1366 {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_NONE, NULL,
1367 0x0, NULL, HFILL}},
1368 { &hf_fc_nh_da,
1369 {"Network DA", "fc.nethdr.da", FT_FCWWN, BASE_NONE, NULL,
1370 0x0, NULL, HFILL}},
1371 { &hf_fc_nh_sa,
1372 {"Network SA", "fc.nethdr.sa", FT_FCWWN, BASE_NONE, NULL,
1373 0x0, NULL, HFILL}},
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,
1381 0x0, NULL, HFILL}},
1382 { &hf_fc_bls_oxid,
1383 {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1384 { &hf_fc_bls_rxid,
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,
1388 HFILL}},
1389 { &hf_fc_bls_hiseqcnt,
1390 {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1391 HFILL}},
1392 { &hf_fc_bls_rjtcode,
1393 {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
1394 0x0, NULL, HFILL}},
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,
1400 0x0, NULL, HFILL}},
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}},
1437 #if 0
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}},
1441 #endif
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 }},
1448 { &hf_fc_time,
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}},
1454 { &hf_fc_vft,
1455 {"VFT Header", "fc.vft", FT_UINT16, BASE_DEC, NULL,
1456 0, NULL, HFILL}},
1457 { &hf_fc_vft_rctl,
1458 {"R_CTL", "fc.vft.rctl", FT_UINT8, BASE_HEX, NULL,
1459 0, NULL, HFILL}},
1460 { &hf_fc_vft_ver,
1461 {"Version", "fc.vft.ver", FT_UINT8, BASE_DEC, NULL,
1462 0, "Version of VFT header", HFILL}},
1463 { &hf_fc_vft_type,
1464 {"Type", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1465 0, "Type of tagged frame", HFILL}},
1466 { &hf_fc_vft_pri,
1467 {"Priority", "fc.vft.pri", FT_UINT8, BASE_DEC, NULL,
1468 0, "QoS Priority", HFILL}},
1469 { &hf_fc_vft_vf_id,
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[] = {
1479 &ett_fc,
1480 &ett_fcbls,
1481 &ett_fc_vft,
1482 &ett_fctl
1485 static ei_register_info ei[] = {
1486 { &ei_fccrc,
1487 { "fc.crc.bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1488 { &ei_short_hdr,
1489 { "fc.short_hdr", PI_MALFORMED, PI_ERROR,
1490 "Packet length is shorter than the required header", EXPFILL }},
1491 #if 0
1492 { &ei_frag_size,
1493 { "fc.frag_size", PI_MALFORMED, PI_ERROR,
1494 "Invalid fragment size", EXPFILL }}
1495 #endif
1498 module_t *fc_module;
1499 expert_module_t* expert_fc;
1501 /* FC SOF */
1503 static hf_register_info sof_hf[] = {
1504 { &hf_fcsof,
1505 { "SOF", "fc.sof", FT_UINT32, BASE_HEX, VALS(fc_sof_vals), 0,
1506 NULL, HFILL }},
1507 { &hf_fceof,
1508 { "EOF", "fc.eof", FT_UINT32, BASE_HEX, VALS(fc_eof_vals), 0,
1509 NULL, HFILL }},
1510 { &hf_fccrc,
1511 { "CRC", "fc.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
1512 { &hf_fccrc_status,
1513 { "CRC Status", "fc.crc.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0, NULL, HFILL }},
1516 static int *sof_ett[] = {
1517 &ett_fcsof,
1518 &ett_fceof,
1519 &ett_fccrc
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",
1539 "FC Frame Type",
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,
1545 "reassemble",
1546 "Reassemble multi-frame sequences",
1547 "If enabled, reassembly of multi-frame "
1548 "sequences is done",
1549 &fc_reassemble);
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.
1579 void
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
1591 * Local variables:
1592 * c-basic-offset: 4
1593 * tab-width: 8
1594 * indent-tabs-mode: nil
1595 * End:
1597 * vi: set shiftwidth=4 tabstop=8 expandtab:
1598 * :indentSize=4:tabSize=8:noTabs=true: