38f1432bc39611a2b5c304312e67c2786902bd1d
[gd/wireshark/.git] / epan / dissectors / packet-fc.c
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
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13
14 #include "config.h"
15
16 #include <epan/packet.h>
17 #include <epan/exceptions.h>
18 #include <epan/prefs.h>
19 #include <epan/to_str.h>
20 #include <wiretap/wtap.h>
21 #include <epan/reassemble.h>
22 #include <epan/conversation_table.h>
23 #include <epan/etypes.h>
24 #include <epan/srt_table.h>
25 #include "packet-fc.h"
26 #include "packet-fclctl.h"
27 #include "packet-fcbls.h"
28 #include <epan/crc32-tvb.h>
29 #include <epan/expert.h>
30
31 void proto_register_fc(void);
32 void proto_reg_handoff_fc(void);
33
34 #define FC_HEADER_SIZE         24
35 #define FC_RCTL_VFT            0x50
36 #define MDSHDR_TRAILER_SIZE    6
37
38 /* Size of various fields in FC header in bytes */
39 #define FC_RCTL_SIZE           1
40 #define FC_DID_SIZE            3
41 #define FC_CSCTL_SIZE          1
42 #define FC_SID_SIZE            3
43 #define FC_TYPE_SIZE           1
44 #define FC_FCTL_SIZE           3
45 #define FC_SEQID_SIZE          1
46 #define FC_DFCTL_SIZE          1
47 #define FC_SEQCNT_SIZE         2
48 #define FC_OXID_SIZE           2
49 #define FC_RXID_SIZE           2
50 #define FC_PARAM_SIZE          4
51
52 /* Initialize the protocol and registered fields */
53 static int proto_fc = -1;
54 static int hf_fc_time = -1;
55 static int hf_fc_exchange_first_frame = -1;
56 static int hf_fc_exchange_last_frame = -1;
57 static int hf_fc_rctl = -1;
58 static int hf_fc_did = -1;
59 static int hf_fc_csctl = -1;
60 static int hf_fc_sid = -1;
61 static int hf_fc_id = -1;
62 static int hf_fc_type = -1;
63 static int hf_fc_fctl = -1;
64 static int hf_fc_fctl_exchange_responder = -1;
65 static int hf_fc_fctl_seq_recipient = -1;
66 static int hf_fc_fctl_exchange_first = -1;
67 static int hf_fc_fctl_exchange_last = -1;
68 static int hf_fc_fctl_seq_last = -1;
69 static int hf_fc_fctl_priority = -1;
70 static int hf_fc_fctl_transfer_seq_initiative = -1;
71 static int hf_fc_fctl_rexmitted_seq = -1;
72 static int hf_fc_fctl_rel_offset = -1;
73 static int hf_fc_fctl_abts_ack = -1;
74 /* static int hf_fc_fctl_abts_not_ack = -1; */
75 static int hf_fc_fctl_last_data_frame = -1;
76 static int hf_fc_fctl_ack_0_1 = -1;
77 static int hf_fc_seqid = -1;
78 static int hf_fc_dfctl = -1;
79 static int hf_fc_seqcnt = -1;
80 static int hf_fc_oxid = -1;
81 static int hf_fc_rxid = -1;
82 static int hf_fc_param = -1;
83 static int hf_fc_ftype = -1;    /* Derived field, non-existent in FC hdr */
84 static int hf_fc_reassembled = -1;
85 static int hf_fc_relative_offset = -1;
86
87 /* VFT fields */
88 static int hf_fc_vft = -1;
89 static int hf_fc_vft_rctl = -1;
90 static int hf_fc_vft_ver = -1;
91 static int hf_fc_vft_type = -1;
92 static int hf_fc_vft_pri = -1;
93 static int hf_fc_vft_vf_id = -1;
94 static int hf_fc_vft_hop_ct = -1;
95
96 /* Network_Header fields */
97 static int hf_fc_nh_da = -1;
98 static int hf_fc_nh_sa = -1;
99
100 /* For Basic Link Svc */
101 static int hf_fc_bls_seqid_vld = -1;
102 static int hf_fc_bls_lastvld_seqid = -1;
103 static int hf_fc_bls_oxid = -1;
104 static int hf_fc_bls_rxid = -1;
105 static int hf_fc_bls_lowseqcnt = -1;
106 static int hf_fc_bls_hiseqcnt = -1;
107 static int hf_fc_bls_rjtcode = -1;
108 static int hf_fc_bls_rjtdetail = -1;
109 static int hf_fc_bls_vendor = -1;
110
111 /* For FC SOF */
112 static int proto_fcsof = -1;
113
114 static int hf_fcsof = -1;
115 static int hf_fceof = -1;
116 static int hf_fccrc = -1;
117 static int hf_fccrc_status = -1;
118
119 static int ett_fcsof = -1;
120 static int ett_fceof = -1;
121 static int ett_fccrc = -1;
122
123
124 /* Initialize the subtree pointers */
125 static gint ett_fc = -1;
126 static gint ett_fctl = -1;
127 static gint ett_fcbls = -1;
128 static gint ett_fc_vft = -1;
129
130 static expert_field ei_fccrc = EI_INIT;
131 static expert_field ei_short_hdr = EI_INIT;
132 /* static expert_field ei_frag_size = EI_INIT; */
133
134 static dissector_handle_t fc_handle, fcsof_handle;
135 static dissector_table_t fcftype_dissector_table;
136
137 static int fc_tap = -1;
138
139 typedef struct _fc_conv_data_t {
140     wmem_tree_t *exchanges;
141     wmem_tree_t *luns;
142 } fc_conv_data_t;
143
144 /* Reassembly stuff */
145 static gboolean fc_reassemble = TRUE;
146 static guint32  fc_max_frame_size = 1024;
147 static reassembly_table fc_reassembly_table;
148
149 typedef struct _fcseq_conv_key {
150     guint32 conv_idx;
151 } fcseq_conv_key_t;
152
153 typedef struct _fcseq_conv_data {
154     guint32 seq_cnt;
155 } fcseq_conv_data_t;
156
157 static wmem_map_t *fcseq_req_hash = NULL;
158
159 /*
160  * Hash Functions
161  */
162 static gint
163 fcseq_equal(gconstpointer v, gconstpointer w)
164 {
165     const fcseq_conv_key_t *v1 = (const fcseq_conv_key_t *)v;
166     const fcseq_conv_key_t *v2 = (const fcseq_conv_key_t *)w;
167
168     return (v1->conv_idx == v2->conv_idx);
169 }
170
171 static guint
172 fcseq_hash (gconstpointer v)
173 {
174     const fcseq_conv_key_t *key = (const fcseq_conv_key_t *)v;
175     guint val;
176
177     val = key->conv_idx;
178
179     return val;
180 }
181
182 static const char* fc_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
183 {
184     if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_FC))
185         return "fc.s_id";
186
187     if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_FC))
188         return "fc.d_id";
189
190     if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_FC))
191         return "fc.id";
192
193     return CONV_FILTER_INVALID;
194 }
195
196 static ct_dissector_info_t fc_ct_dissector_info = {&fc_conv_get_filter_type};
197
198 static int
199 fc_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
200 {
201     conv_hash_t *hash = (conv_hash_t*) pct;
202     const fc_hdr *fchdr=(const fc_hdr *)vip;
203
204     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, ENDPOINT_NONE);
205
206     return 1;
207 }
208
209 static const char* fc_host_get_filter_type(hostlist_talker_t* host, conv_filter_type_e filter)
210 {
211     if ((filter == CONV_FT_ANY_ADDRESS) && (host->myaddress.type == AT_FC))
212         return "fc.id";
213
214     return CONV_FILTER_INVALID;
215 }
216
217 static hostlist_dissector_info_t fc_host_dissector_info = {&fc_host_get_filter_type};
218
219 static int
220 fc_hostlist_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
221 {
222     conv_hash_t *hash = (conv_hash_t*) pit;
223     const fc_hdr *fchdr=(const fc_hdr *)vip;
224
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 hostlist_table */
228     add_hostlist_table_data(hash, &fchdr->s_id, 0, TRUE, 1, pinfo->fd->pkt_len, &fc_host_dissector_info, ENDPOINT_NONE);
229     add_hostlist_table_data(hash, &fchdr->d_id, 0, FALSE, 1, pinfo->fd->pkt_len, &fc_host_dissector_info, ENDPOINT_NONE);
230
231     return 1;
232 }
233
234 #define FC_NUM_PROCEDURES     256
235
236 static void
237 fcstat_init(struct register_srt* srt _U_, GArray* srt_array)
238 {
239     srt_stat_table *fc_srt_table;
240     guint32 i;
241
242     fc_srt_table = init_srt_table("Fibre Channel Types", NULL, srt_array, FC_NUM_PROCEDURES, NULL, NULL, NULL);
243     for (i = 0; i < FC_NUM_PROCEDURES; i++)
244     {
245         gchar* 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);
248     }
249 }
250
251 static int
252 fcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
253 {
254     guint 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;
258
259     /* we are only interested in reply packets */
260     if(!(fc->fctl&FC_FCTL_EXCHANGE_RESPONDER)){
261             return 0;
262     }
263     /* if we havnt seen the request, just ignore it */
264     if ( (!fc->fc_ex) || (fc->fc_ex->first_exchange_frame==0) ){
265             return 0;
266     }
267
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);
270
271     return 1;
272 }
273
274
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}
288 };
289
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}
304 };
305
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}
319 };
320
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}
329 };
330
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}
341 };
342
343
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
356
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
373
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}
387 };
388
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}
407 };
408
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.
414  */
415 static void
416 dissect_fc_ba_acc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
417 {
418     /* Set up structures needed to add the protocol subtree and manage it */
419     proto_tree *acc_tree;
420     int offset = 0;
421
422     /* Make entries in Protocol column and Info column on summary display */
423     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
424
425     col_set_str(pinfo->cinfo, COL_INFO, "BA_ACC");
426
427     if (tree) {
428         acc_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_fcbls, NULL, "Basic Link Svc");
429
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);
440     }
441 }
442
443 static void
444 dissect_fc_ba_rjt (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
445 {
446     /* Set up structures needed to add the protocol subtree and manage it */
447     proto_tree *rjt_tree;
448     int offset = 0;
449
450     /* Make entries in Protocol column and Info column on summary display */
451     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
452
453     col_set_str(pinfo->cinfo, COL_INFO, "BA_RJT");
454
455     if (tree) {
456         rjt_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_fcbls, NULL, "Basic Link Svc");
457
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);
461     }
462 }
463
464 static guint8
465 fc_get_ftype (guint8 r_ctl, guint8 type)
466 {
467     /* A simple attempt to determine the upper level protocol based on the
468      * r_ctl & type fields.
469      */
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;
491         }
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;
505         }
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;
517     }
518 }
519
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}
526 };
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}
534 };
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}
542 };
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}
549 };
550 static const true_false_string tfs_fc_fctl_exchange_responder = {
551     "Exchange Responder",
552     "Exchange Originator"
553 };
554 static const true_false_string tfs_fc_fctl_seq_recipient = {
555     "Seq Recipient",
556     "Seq Initiator"
557 };
558 static const true_false_string tfs_fc_fctl_exchange_first = {
559     "Exchg First",
560     "NOT exchg first"
561 };
562 static const true_false_string tfs_fc_fctl_exchange_last = {
563     "Exchg Last",
564     "NOT exchg last"
565 };
566 static const true_false_string tfs_fc_fctl_seq_last = {
567     "Seq Last",
568     "NOT seq last"
569 };
570 static const true_false_string tfs_fc_fctl_priority = {
571     "Priority",
572     "CS_CTL"
573 };
574 static const true_false_string tfs_fc_fctl_transfer_seq_initiative = {
575     "Transfer Seq Initiative",
576     "NOT transfer seq initiative"
577 };
578 static const true_false_string tfs_fc_fctl_rexmitted_seq = {
579     "Retransmitted Sequence",
580     "NOT retransmitted sequence"
581 };
582 static const true_false_string tfs_fc_fctl_rel_offset = {
583     "Rel Offset SET",
584     "rel offset NOT set"
585 };
586
587 /*
588  * Dissect the VFT header.
589  */
590 static void
591 dissect_fc_vft(proto_tree *parent_tree,
592                 tvbuff_t *tvb, int offset)
593 {
594     proto_item *item;
595     proto_tree *tree;
596     guint8 rctl;
597     guint8 ver;
598     guint8 type;
599     guint8 pri;
600     guint16 vf_id;
601     guint8 hop_ct;
602
603     rctl = tvb_get_guint8(tvb, offset);
604     type = tvb_get_guint8(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_guint8(tvb, offset + 4);
611
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);
622 }
623
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)
627 {
628     static const int * 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
642     };
643
644     proto_tree_add_bitmask_with_flags(parent_tree, tvb, offset, hf_fc_fctl,
645                                 ett_fctl, flags, ENC_BIG_ENDIAN, BMT_NO_INT);
646 }
647
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}
656 };
657
658 static const value_string fc_els_proto_val[] = {
659     {0x01    , "Solicited Data"},
660     {0x02    , "Request"},
661     {0x03    , "Reply"},
662     {0, NULL}
663 };
664
665 /* Code to actually dissect the packets */
666 static void
667 dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_ifcp, fc_data_t* fc_data)
668 {
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     gboolean is_lastframe_inseq, is_1frame_inseq, is_exchg_resp = 0;
676     fragment_head *fcfrag_head;
677     guint32 frag_id, frag_size;
678     guint8 df_ctl, seq_id;
679     guint32 f_ctl;
680     address addr;
681
682     guint32 param, exchange_key;
683     guint16 real_seqcnt;
684     guint8 ftype;
685
686     fc_hdr* fchdr = wmem_new(wmem_packet_scope(), fc_hdr); /* Needed by conversations, not just tap */
687     fc_exchange_t *fc_ex;
688     fc_conv_data_t *fc_conv_data=NULL;
689
690     conversation_t *conversation;
691     fcseq_conv_data_t *cdata;
692     fcseq_conv_key_t ckey, *req_key;
693
694     /* Make entries in Protocol column and Info column on summary display */
695     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
696
697     fchdr->r_ctl = tvb_get_guint8 (tvb, offset);
698     fchdr->fc_ex = NULL;
699
700     /*
701      * If the frame contains a VFT (virtual fabric tag), decode it
702      * as a separate header before the FC frame header.
703      *
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.
706      */
707     if (fchdr->r_ctl == FC_RCTL_VFT) {
708         vft_offset = offset;
709         offset += 8;
710         fchdr->r_ctl = tvb_get_guint8 (tvb, offset);
711     }
712
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.
720      */
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_create_endpoint(pinfo, &pinfo->src, &pinfo->dst, ENDPOINT_EXCHG, 0, 0, 0);
725     } else {
726         conversation_create_endpoint(pinfo, &pinfo->src, &pinfo->dst, ENDPOINT_EXCHG, pinfo->srcport, pinfo->destport, 0);
727     }
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);
730
731     fchdr->cs_ctl = tvb_get_guint8 (tvb, offset+4);
732     fchdr->type  = tvb_get_guint8 (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_guint8 (tvb, offset+12);
740
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);
750     }
751
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->flags.visited) {
756         fchdr->lun = (guint16)GPOINTER_TO_UINT(wmem_tree_lookup32(fc_conv_data->luns, fchdr->oxid));
757     }
758
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);
763
764     /*is_ack = ((fchdr->r_ctl == 0xC0) || (fchdr->r_ctl == 0xC1));*/
765
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.
770      */
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)));
774
775     is_lastframe_inseq = ((fc_data->sof_eof & FC_DATA_EOF_LAST_FRAME) == FC_DATA_EOF_LAST_FRAME);
776
777     is_lastframe_inseq |= fchdr->fctl & FC_FCTL_SEQ_LAST;
778     /*is_valid_frame = ((pinfo->sof_eof & 0x40) == 0x40);*/
779
780     ftype = fc_get_ftype (fchdr->r_ctl, fchdr->type);
781
782     col_add_str (pinfo->cinfo, COL_INFO, val_to_str (ftype, fc_ftype_vals,
783                                                         "Unknown Type (0x%x)"));
784
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"));
790
791     if (vft_offset >= 0) {
792         dissect_fc_vft(fc_tree, tvb, vft_offset);
793     }
794     switch (fchdr->r_ctl & 0xF0) {
795
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;
809
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;
821
822     case FC_RCTL_BLS:
823         switch (fchdr->type) {
824
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;
836
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;
846         }
847         break;
848
849     case FC_RCTL_ELS:
850         switch (fchdr->type) {
851
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;
863
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;
873         }
874         break;
875
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;
885     }
886
887     hidden_item = proto_tree_add_uint (fc_tree, hf_fc_ftype, tvb, offset, 1,
888                                        ftype);
889     PROTO_ITEM_SET_HIDDEN(hidden_item);
890
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);
896
897     proto_tree_add_uint (fc_tree, hf_fc_csctl, tvb, offset+4, 1, fchdr->cs_ctl);
898
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);
904
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.
910              */
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 ((guint8) (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);
918         }
919     } else {
920         proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
921     }
922
923
924     dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9);
925     f_ctl = tvb_get_ntoh24(tvb, offset+9);
926
927
928     proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, ENC_BIG_ENDIAN);
929
930     df_ctl = tvb_get_guint8(tvb, offset+13);
931
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);
936
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
943              */
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 ((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);
951         }
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);
962         }
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);
969         }
970     } else {
971         proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
972     }
973
974     /* Skip the Frame_Header */
975     next_offset = offset + FC_HEADER_SIZE;
976
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;
982     }
983
984     /* XXX - handle Association_Header and Device_Header here */
985
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
991          */
992         is_lastframe_inseq = TRUE;
993     } else {
994         is_exchg_resp = (f_ctl & FC_FCTL_EXCHANGE_RESPONDER) != 0;
995     }
996
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;
1001     }
1002
1003     frag_size = tvb_reported_length (tvb)-FC_HEADER_SIZE;
1004
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.
1009      */
1010     if ((fc_data->ethertype == ETHERTYPE_UNK) || (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;
1017         }
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;
1024         }
1025         frag_size -= 8;         /* 4 byte of FC CRC +
1026                                    4 bytes of error+EOF = 8 bytes  */
1027     }
1028
1029     if (!is_lastframe_inseq) {
1030         /* Show this only as a fragmented FC frame */
1031         col_append_str (pinfo->cinfo, COL_INFO, " (Fragmented)");
1032     }
1033
1034     /* If this is a fragment, attempt to check if fully reassembled frame is
1035      * present, if we're configured to reassemble.
1036      */
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 */
1042
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.
1048          */
1049         ckey.conv_idx = conversation->conv_index;
1050
1051         cdata = (fcseq_conv_data_t *)wmem_map_lookup (fcseq_req_hash,
1052                                                           &ckey);
1053
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.
1059                  */
1060                 cdata->seq_cnt = fchdr->seqcnt;
1061             }
1062             else {
1063                 req_key = wmem_new(wmem_file_scope(), fcseq_conv_key_t);
1064                 req_key->conv_idx = conversation->conv_index;
1065
1066                 cdata = wmem_new(wmem_file_scope(), fcseq_conv_data_t);
1067                 cdata->seq_cnt = fchdr->seqcnt;
1068
1069                 wmem_map_insert (fcseq_req_hash, req_key, cdata);
1070             }
1071             real_seqcnt = 0;
1072         }
1073         else if (cdata != NULL) {
1074             real_seqcnt = fchdr->seqcnt - cdata->seq_cnt ;
1075         }
1076         else {
1077             real_seqcnt = fchdr->seqcnt;
1078         }
1079
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.
1085               */
1086              next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1087              col_append_str (pinfo->cinfo, COL_INFO, " (Bogus Fragment)");
1088         } else {
1089
1090              frag_id = ((fchdr->oxid << 16) ^ seq_id) | is_exchg_resp ;
1091
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);
1099
1100              if (fcfrag_head) {
1101                   next_tvb = tvb_new_chain(tvb, fcfrag_head->tvb_data);
1102
1103                   /* Add the defragmented data to the data source list. */
1104                   add_new_data_source(pinfo, next_tvb, "Reassembled FC");
1105
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);
1109              }
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;
1117              }
1118         }
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);
1124     }
1125
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_new (fcftype_dissector_table, ftype,
1133                                 next_tvb, pinfo, tree, FALSE, fchdr)) {
1134                 call_data_dissector(next_tvb, pinfo, tree);
1135             }
1136         }
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");
1145         }
1146     }
1147
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 */
1151
1152     /* Set up LUN data */
1153     if (!pinfo->fd->flags.visited) {
1154         wmem_tree_insert32(fc_conv_data->luns, fchdr->oxid, GUINT_TO_POINTER((guint)fchdr->lun));
1155     }
1156
1157     exchange_key = ((fchdr->oxid & 0xFFFF) | ((fchdr->lun << 16) & 0xFFFF0000));
1158
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
1162      */
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;
1169
1170         wmem_tree_insert32(fc_conv_data->exchanges, exchange_key, fc_ex);
1171     }
1172
1173     fchdr->fc_ex = fc_ex;
1174
1175     /* populate the exchange struct */
1176     if(!pinfo->fd->flags.visited){
1177         if(fchdr->fctl&FC_FCTL_EXCHANGE_FIRST){
1178             fc_ex->first_exchange_frame=pinfo->num;
1179             fc_ex->fc_time = pinfo->abs_ts;
1180         }
1181         if(fchdr->fctl&FC_FCTL_EXCHANGE_LAST){
1182             fc_ex->last_exchange_frame=pinfo->num;
1183         }
1184     }
1185
1186     /* put some nice exchange data in the tree */
1187     if(!(fchdr->fctl&FC_FCTL_EXCHANGE_FIRST)){
1188         proto_item *it;
1189         it=proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
1190         PROTO_ITEM_SET_GENERATED(it);
1191         if(fchdr->fctl&FC_FCTL_EXCHANGE_LAST){
1192             nstime_t delta_ts;
1193             nstime_delta(&delta_ts, &pinfo->abs_ts, &fc_ex->fc_time);
1194             it=proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
1195             PROTO_ITEM_SET_GENERATED(it);
1196         }
1197     }
1198     if(!(fchdr->fctl&FC_FCTL_EXCHANGE_LAST)){
1199         proto_item *it;
1200         it=proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
1201         PROTO_ITEM_SET_GENERATED(it);
1202     }
1203
1204     tap_queue_packet(fc_tap, pinfo, fchdr);
1205 }
1206
1207 static int
1208 dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1209 {
1210     fc_data_t* fc_data = (fc_data_t*)data;
1211
1212     if (!fc_data)
1213        return 0;
1214
1215     dissect_fc_helper (tvb, pinfo, tree, FALSE, fc_data);
1216     return tvb_captured_length(tvb);
1217 }
1218
1219 static int
1220 dissect_fc_wtap (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1221 {
1222     fc_data_t fc_data;
1223
1224     fc_data.ethertype = ETHERTYPE_UNK;
1225     fc_data.sof_eof = 0;
1226
1227     dissect_fc_helper (tvb, pinfo, tree, FALSE, &fc_data);
1228     return tvb_captured_length(tvb);
1229 }
1230
1231 static int
1232 dissect_fc_ifcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1233 {
1234     fc_data_t* fc_data = (fc_data_t*)data;
1235
1236     if (!fc_data)
1237        return 0;
1238
1239     dissect_fc_helper (tvb, pinfo, tree, TRUE, fc_data);
1240     return tvb_captured_length(tvb);
1241 }
1242
1243 static int
1244 dissect_fcsof(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
1245
1246     proto_item *it;
1247     proto_tree *fcsof_tree;
1248     tvbuff_t *next_tvb;
1249     guint32 sof;
1250     guint32 crc_computed;
1251     guint32 eof;
1252     const gint FCSOF_TRAILER_LEN = 8;
1253     const gint FCSOF_HEADER_LEN = 4;
1254     gint crc_offset = tvb_reported_length(tvb) - FCSOF_TRAILER_LEN;
1255     gint eof_offset = crc_offset + 4;
1256     gint sof_offset = 0;
1257     gint frame_len_for_checksum;
1258     fc_data_t fc_data;
1259
1260     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
1261
1262     /* Get SOF */
1263     sof = tvb_get_ntohl(tvb, 0);
1264
1265     /* GET Computed CRC */
1266     frame_len_for_checksum = crc_offset - FCSOF_HEADER_LEN;
1267     crc_computed = crc32_802_tvb(tvb_new_subset_length(tvb, 4, frame_len_for_checksum), frame_len_for_checksum);
1268
1269     /* Get EOF */
1270     eof = tvb_get_ntohl(tvb, eof_offset);
1271
1272     it = proto_tree_add_protocol_format(tree, proto_fcsof, tvb, 0,
1273                                         4, "Fibre Channel Delimiter: SOF: %s EOF: %s",
1274                                         val_to_str(sof, fc_sof_vals, "0x%x"),
1275                                         val_to_str(eof, fc_eof_vals, "0x%x"));
1276
1277     fcsof_tree = proto_item_add_subtree(it, ett_fcsof);
1278
1279     proto_tree_add_uint(fcsof_tree, hf_fcsof, tvb, sof_offset, 4, sof);
1280
1281     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);
1282
1283     proto_tree_add_uint(fcsof_tree, hf_fceof, tvb, eof_offset, 4, eof);
1284
1285     next_tvb = tvb_new_subset_length(tvb, 4, crc_offset-4);
1286
1287     fc_data.ethertype = 0;
1288     fc_data.sof_eof = 0;
1289     if (sof == FC_SOFI2 || sof == FC_SOFI3) {
1290         fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME;
1291     } else if (sof == FC_SOFF) {
1292         fc_data.sof_eof = FC_DATA_SOF_SOFF;
1293     }
1294
1295     if (eof == EOFT_POS || eof == EOFT_NEG) {
1296         fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME;
1297     } else if (eof == EOFDTI_NEG || eof == EOFDTI_POS) {
1298         fc_data.sof_eof |= FC_DATA_EOF_INVALID;
1299     }
1300
1301     /* Call FC dissector */
1302     call_dissector_with_data(fc_handle, next_tvb, pinfo, tree, &fc_data);
1303     return tvb_captured_length(tvb);
1304 }
1305
1306 /* Register the protocol with Wireshark */
1307
1308 /* this format is require because a script is used to build the C function
1309    that calls all the protocol registration.
1310 */
1311
1312 void
1313 proto_register_fc(void)
1314 {
1315
1316 /* Setup list of header fields  See Section 1.6.1 for details*/
1317     static hf_register_info hf[] = {
1318         { &hf_fc_rctl,
1319           { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1320             NULL, HFILL }},
1321         { &hf_fc_ftype,
1322           {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
1323            0x0, "Derived Type", HFILL}},
1324         { &hf_fc_did,
1325           { "Dest Addr", "fc.d_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1326             "Destination Address", HFILL}},
1327         { &hf_fc_csctl,
1328           {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1329            NULL, HFILL}},
1330         { &hf_fc_sid,
1331           {"Src Addr", "fc.s_id", FT_BYTES, SEP_DOT, NULL, 0x0,
1332            "Source Address", HFILL}},
1333         { &hf_fc_id,
1334           {"Addr", "fc.id", FT_BYTES, SEP_DOT, NULL, 0x0,
1335            "Source or Destination Address", HFILL}},
1336         { &hf_fc_type,
1337           {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
1338            NULL, HFILL}},
1339         { &hf_fc_fctl,
1340           {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1341         { &hf_fc_seqid,
1342           {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
1343            "Sequence ID", HFILL}},
1344         { &hf_fc_dfctl,
1345           {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1346         { &hf_fc_seqcnt,
1347           {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
1348            "Sequence Count", HFILL}},
1349         { &hf_fc_oxid,
1350           {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
1351            HFILL}},
1352         { &hf_fc_rxid,
1353           {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
1354            HFILL}},
1355         { &hf_fc_param,
1356           {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL,
1357            HFILL}},
1358
1359         { &hf_fc_reassembled,
1360           {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_NONE, NULL,
1361            0x0, NULL, HFILL}},
1362         { &hf_fc_nh_da,
1363           {"Network DA", "fc.nethdr.da", FT_FCWWN, BASE_NONE, NULL,
1364            0x0, NULL, HFILL}},
1365         { &hf_fc_nh_sa,
1366           {"Network SA", "fc.nethdr.sa", FT_FCWWN, BASE_NONE, NULL,
1367            0x0, NULL, HFILL}},
1368
1369         /* Basic Link Svc field definitions */
1370         { &hf_fc_bls_seqid_vld,
1371           {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8, BASE_HEX,
1372            VALS (fc_bls_seqid_val), 0x0, NULL, HFILL}},
1373         { &hf_fc_bls_lastvld_seqid,
1374           {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8, BASE_HEX, NULL,
1375            0x0, NULL, HFILL}},
1376         { &hf_fc_bls_oxid,
1377           {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1378         { &hf_fc_bls_rxid,
1379           {"RXID", "fc.bls_rxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1380         { &hf_fc_bls_lowseqcnt,
1381           {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1382            HFILL}},
1383         { &hf_fc_bls_hiseqcnt,
1384           {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1385            HFILL}},
1386         { &hf_fc_bls_rjtcode,
1387           {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
1388            0x0, NULL, HFILL}},
1389         { &hf_fc_bls_rjtdetail,
1390           {"Reason Explanation", "fc.bls_rjtdetail", FT_UINT8, BASE_HEX,
1391            VALS (fc_bls_barjt_det_val), 0x0, NULL, HFILL}},
1392         { &hf_fc_bls_vendor,
1393           {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8, BASE_HEX, NULL,
1394            0x0, NULL, HFILL}},
1395         { &hf_fc_fctl_exchange_responder,
1396           {"ExgRpd", "fc.fctl.exchange_responder", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_responder),
1397            FC_FCTL_EXCHANGE_RESPONDER, "Exchange Responder?", HFILL}},
1398         { &hf_fc_fctl_seq_recipient,
1399           {"SeqRec", "fc.fctl.seq_recipient", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_recipient),
1400            FC_FCTL_SEQ_RECIPIENT, "Seq Recipient?", HFILL}},
1401         { &hf_fc_fctl_exchange_first,
1402           {"ExgFst", "fc.fctl.exchange_first", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_first),
1403            FC_FCTL_EXCHANGE_FIRST, "First Exchange?", HFILL}},
1404         { &hf_fc_fctl_exchange_last,
1405           {"ExgLst", "fc.fctl.exchange_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_last),
1406            FC_FCTL_EXCHANGE_LAST, "Last Exchange?", HFILL}},
1407         { &hf_fc_fctl_seq_last,
1408           {"SeqLst", "fc.fctl.seq_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_last),
1409            FC_FCTL_SEQ_LAST, "Last Sequence?", HFILL}},
1410         { &hf_fc_fctl_priority,
1411           {"Pri", "fc.fctl.priority", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_priority),
1412            FC_FCTL_PRIORITY, "Priority", HFILL}},
1413         { &hf_fc_fctl_transfer_seq_initiative,
1414           {"TSI", "fc.fctl.transfer_seq_initiative", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_transfer_seq_initiative),
1415            FC_FCTL_TRANSFER_SEQ_INITIATIVE, "Transfer Seq Initiative", HFILL}},
1416         { &hf_fc_fctl_rexmitted_seq,
1417           {"RetSeq", "fc.fctl.rexmitted_seq", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rexmitted_seq),
1418            FC_FCTL_REXMITTED_SEQ, "Retransmitted Sequence", HFILL}},
1419         { &hf_fc_fctl_rel_offset,
1420           {"RelOff", "fc.fctl.rel_offset", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rel_offset),
1421            FC_FCTL_REL_OFFSET, "rel offset", HFILL}},
1422         { &hf_fc_fctl_last_data_frame,
1423           {"LDF", "fc.fctl.last_data_frame", FT_UINT24, BASE_HEX, VALS(last_data_frame_vals),
1424            FC_FCTL_LAST_DATA_FRAME_MASK, "Last Data Frame?", HFILL}},
1425         { &hf_fc_fctl_ack_0_1,
1426           {"A01", "fc.fctl.ack_0_1", FT_UINT24, BASE_HEX, VALS(ack_0_1_vals),
1427            FC_FCTL_ACK_0_1_MASK, "Ack 0/1 value", HFILL}},
1428         { &hf_fc_fctl_abts_ack,
1429           {"AA", "fc.fctl.abts_ack", FT_UINT24, BASE_HEX, VALS(abts_ack_vals),
1430            FC_FCTL_ABTS_MASK, "ABTS ACK values", HFILL}},
1431 #if 0
1432         { &hf_fc_fctl_abts_not_ack,
1433           {"AnA", "fc.fctl.abts_not_ack", FT_UINT24, BASE_HEX, VALS(abts_not_ack_vals),
1434            FC_FCTL_ABTS_MASK, "ABTS not ACK vals", HFILL}},
1435 #endif
1436         { &hf_fc_exchange_first_frame,
1437           { "Exchange First In", "fc.exchange_first_frame", FT_FRAMENUM, BASE_NONE, NULL,
1438            0, "The first frame of this exchange is in this frame", HFILL }},
1439         { &hf_fc_exchange_last_frame,
1440           { "Exchange Last In", "fc.exchange_last_frame", FT_FRAMENUM, BASE_NONE, NULL,
1441            0, "The last frame of this exchange is in this frame", HFILL }},
1442         { &hf_fc_time,
1443           { "Time from Exchange First", "fc.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
1444            0, "Time since the first frame of the Exchange", HFILL }},
1445         { &hf_fc_relative_offset,
1446           {"Relative Offset", "fc.relative_offset", FT_UINT32, BASE_DEC, NULL,
1447            0, "Relative offset of data", HFILL}},
1448         { &hf_fc_vft,
1449           {"VFT Header", "fc.vft", FT_UINT16, BASE_DEC, NULL,
1450            0, NULL, HFILL}},
1451         { &hf_fc_vft_rctl,
1452           {"R_CTL", "fc.vft.rctl", FT_UINT8, BASE_HEX, NULL,
1453            0, NULL, HFILL}},
1454         { &hf_fc_vft_ver,
1455           {"Version", "fc.vft.ver", FT_UINT8, BASE_DEC, NULL,
1456            0, "Version of VFT header", HFILL}},
1457         { &hf_fc_vft_type,
1458           {"Type", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1459            0, "Type of tagged frame", HFILL}},
1460         { &hf_fc_vft_pri,
1461           {"Priority", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1462            0, "QoS Priority", HFILL}},
1463         { &hf_fc_vft_vf_id,
1464           {"VF_ID", "fc.vft.vf_id", FT_UINT16, BASE_DEC, NULL,
1465            0, "Virtual Fabric ID", HFILL}},
1466         { &hf_fc_vft_hop_ct,
1467           {"HopCT", "fc.vft.hop_ct", FT_UINT8, BASE_DEC, NULL,
1468            0, "Hop Count", HFILL}},
1469     };
1470
1471     /* Setup protocol subtree array */
1472     static gint *ett[] = {
1473         &ett_fc,
1474         &ett_fcbls,
1475         &ett_fc_vft,
1476         &ett_fctl
1477     };
1478
1479     static ei_register_info ei[] = {
1480         { &ei_fccrc,
1481             { "fc.crc.bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1482         { &ei_short_hdr,
1483             { "fc.short_hdr", PI_MALFORMED, PI_ERROR,
1484                 "Packet length is shorter than the required header", EXPFILL }},
1485 #if 0
1486         { &ei_frag_size,
1487             { "fc.frag_size", PI_MALFORMED, PI_ERROR,
1488                 "Invalid fragment size", EXPFILL }}
1489 #endif
1490     };
1491
1492     module_t *fc_module;
1493     expert_module_t* expert_fc;
1494
1495     /* FC SOF */
1496
1497     static hf_register_info sof_hf[] = {
1498         { &hf_fcsof,
1499           { "SOF", "fc.sof", FT_UINT32, BASE_HEX, VALS(fc_sof_vals), 0,
1500             NULL, HFILL }},
1501         { &hf_fceof,
1502           { "EOF", "fc.eof", FT_UINT32, BASE_HEX, VALS(fc_eof_vals), 0,
1503             NULL, HFILL }},
1504         { &hf_fccrc,
1505           { "CRC", "fc.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
1506         { &hf_fccrc_status,
1507           { "CRC Status", "fc.crc.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0, NULL, HFILL }},
1508     };
1509
1510     static gint *sof_ett[] = {
1511         &ett_fcsof,
1512         &ett_fceof,
1513         &ett_fccrc
1514     };
1515
1516
1517     /* Register the protocol name and description */
1518     proto_fc = proto_register_protocol ("Fibre Channel", "FC", "fc");
1519     fc_handle = register_dissector ("fc", dissect_fc, proto_fc);
1520     register_dissector ("fc_ifcp", dissect_fc_ifcp, proto_fc);
1521     fc_tap = register_tap("fc");
1522
1523     /* Required function calls to register the header fields and subtrees used */
1524     proto_register_field_array(proto_fc, hf, array_length(hf));
1525     proto_register_subtree_array(ett, array_length(ett));
1526     expert_fc = expert_register_protocol(proto_fc);
1527     expert_register_field_array(expert_fc, ei, array_length(ei));
1528
1529     /* subdissectors called through this table will find the fchdr structure
1530      * through data parameter of dissector
1531      */
1532     fcftype_dissector_table = register_dissector_table ("fc.ftype",
1533                                                         "FC Frame Type",
1534                                                         proto_fc, FT_UINT8, BASE_HEX);
1535
1536     /* Register preferences */
1537     fc_module = prefs_register_protocol (proto_fc, NULL);
1538     prefs_register_bool_preference (fc_module,
1539                                     "reassemble",
1540                                     "Reassemble multi-frame sequences",
1541                                     "If enabled, reassembly of multi-frame "
1542                                     "sequences is done",
1543                                     &fc_reassemble);
1544     prefs_register_uint_preference (fc_module,
1545                                     "max_frame_size", "Max FC Frame Size",
1546                                     "This is the size of non-last frames in a "
1547                                     "multi-frame sequence", 10,
1548                                     &fc_max_frame_size);
1549
1550     fcseq_req_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), fcseq_hash, fcseq_equal);
1551
1552     reassembly_table_register(&fc_reassembly_table,
1553                           &addresses_reassembly_table_functions);
1554
1555
1556     /* Register FC SOF/EOF */
1557     proto_fcsof = proto_register_protocol("Fibre Channel Delimiters", "FCSoF", "fcsof");
1558
1559     proto_register_field_array(proto_fcsof, sof_hf, array_length(sof_hf));
1560     proto_register_subtree_array(sof_ett, array_length(sof_ett));
1561
1562     fcsof_handle = register_dissector("fcsof", dissect_fcsof, proto_fcsof);
1563
1564     register_conversation_table(proto_fc, TRUE, fc_conversation_packet, fc_hostlist_packet);
1565     register_srt_table(proto_fc, NULL, 1, fcstat_packet, fcstat_init, NULL);
1566 }
1567
1568
1569 /* If this dissector uses sub-dissector registration add a registration routine.
1570    This format is required because a script is used to find these routines and
1571    create the code that calls these routines.
1572 */
1573 void
1574 proto_reg_handoff_fc (void)
1575 {
1576     dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2,
1577                        create_dissector_handle(dissect_fc_wtap, proto_fc));
1578
1579     dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS, fcsof_handle);
1580 }
1581
1582 /*
1583  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1584  *
1585  * Local variables:
1586  * c-basic-offset: 4
1587  * tab-width: 8
1588  * indent-tabs-mode: nil
1589  * End:
1590  *
1591  * vi: set shiftwidth=4 tabstop=8 expandtab:
1592  * :indentSize=4:tabSize=8:noTabs=true:
1593  */