Remove all $Id$ from top of file
[metze/wireshark/wip.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  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <glib.h>
29
30 #include <epan/packet.h>
31 #include <epan/exceptions.h>
32 #include <epan/prefs.h>
33 #include <epan/to_str.h>
34 #include <wiretap/wtap.h>
35 #include <epan/reassemble.h>
36 #include <epan/conversation.h>
37 #include <epan/etypes.h>
38 #include "packet-fc.h"
39 #include "packet-fclctl.h"
40 #include "packet-fcbls.h"
41 #include <epan/tap.h>
42 #include <epan/wmem/wmem.h>
43 #include <epan/crc32-tvb.h>
44 #include <epan/expert.h>
45
46 void proto_register_fc(void);
47 void proto_reg_handoff_fc(void);
48
49 #define FC_HEADER_SIZE         24
50 #define FC_RCTL_VFT            0x50
51 #define MDSHDR_TRAILER_SIZE    6
52
53 /* Size of various fields in FC header in bytes */
54 #define FC_RCTL_SIZE           1
55 #define FC_DID_SIZE            3
56 #define FC_CSCTL_SIZE          1
57 #define FC_SID_SIZE            3
58 #define FC_TYPE_SIZE           1
59 #define FC_FCTL_SIZE           3
60 #define FC_SEQID_SIZE          1
61 #define FC_DFCTL_SIZE          1
62 #define FC_SEQCNT_SIZE         2
63 #define FC_OXID_SIZE           2
64 #define FC_RXID_SIZE           2
65 #define FC_PARAM_SIZE          4
66
67 /* Initialize the protocol and registered fields */
68 static int proto_fc = -1;
69 static int hf_fc_time = -1;
70 static int hf_fc_exchange_first_frame = -1;
71 static int hf_fc_exchange_last_frame = -1;
72 static int hf_fc_rctl = -1;
73 static int hf_fc_did = -1;
74 static int hf_fc_csctl = -1;
75 static int hf_fc_sid = -1;
76 static int hf_fc_id = -1;
77 static int hf_fc_type = -1;
78 static int hf_fc_fctl = -1;
79 static int hf_fc_fctl_exchange_responder = -1;
80 static int hf_fc_fctl_seq_recipient = -1;
81 static int hf_fc_fctl_exchange_first = -1;
82 static int hf_fc_fctl_exchange_last = -1;
83 static int hf_fc_fctl_seq_last = -1;
84 static int hf_fc_fctl_priority = -1;
85 static int hf_fc_fctl_transfer_seq_initiative = -1;
86 static int hf_fc_fctl_rexmitted_seq = -1;
87 static int hf_fc_fctl_rel_offset = -1;
88 static int hf_fc_fctl_abts_ack = -1;
89 /* static int hf_fc_fctl_abts_not_ack = -1; */
90 static int hf_fc_fctl_last_data_frame = -1;
91 static int hf_fc_fctl_ack_0_1 = -1;
92 static int hf_fc_seqid = -1;
93 static int hf_fc_dfctl = -1;
94 static int hf_fc_seqcnt = -1;
95 static int hf_fc_oxid = -1;
96 static int hf_fc_rxid = -1;
97 static int hf_fc_param = -1;
98 static int hf_fc_ftype = -1;    /* Derived field, non-existent in FC hdr */
99 static int hf_fc_reassembled = -1;
100 static int hf_fc_relative_offset = -1;
101
102 /* VFT fields */
103 static int hf_fc_vft = -1;
104 static int hf_fc_vft_rctl = -1;
105 static int hf_fc_vft_ver = -1;
106 static int hf_fc_vft_type = -1;
107 static int hf_fc_vft_pri = -1;
108 static int hf_fc_vft_vf_id = -1;
109 static int hf_fc_vft_hop_ct = -1;
110
111 /* Network_Header fields */
112 static int hf_fc_nh_da = -1;
113 static int hf_fc_nh_sa = -1;
114
115 /* For Basic Link Svc */
116 static int hf_fc_bls_seqid_vld = -1;
117 static int hf_fc_bls_lastvld_seqid = -1;
118 static int hf_fc_bls_oxid = -1;
119 static int hf_fc_bls_rxid = -1;
120 static int hf_fc_bls_lowseqcnt = -1;
121 static int hf_fc_bls_hiseqcnt = -1;
122 static int hf_fc_bls_rjtcode = -1;
123 static int hf_fc_bls_rjtdetail = -1;
124 static int hf_fc_bls_vendor = -1;
125
126 /* For FC SOF */
127 static int proto_fcsof = -1;
128
129 static int hf_fcsof = -1;
130 static int hf_fceof = -1;
131 static int hf_fccrc = -1;
132
133 static int ett_fcsof = -1;
134 static int ett_fceof = -1;
135 static int ett_fccrc = -1;
136
137
138 /* Initialize the subtree pointers */
139 static gint ett_fc = -1;
140 static gint ett_fctl = -1;
141 static gint ett_fcbls = -1;
142 static gint ett_fc_vft = -1;
143
144 static expert_field ei_fccrc = EI_INIT;
145
146 static dissector_handle_t fc_handle, fcsof_handle;
147 static dissector_table_t fcftype_dissector_table;
148
149 static dissector_handle_t data_handle;
150
151 static int fc_tap = -1;
152
153 typedef struct _fc_conv_data_t {
154     wmem_tree_t *exchanges;
155     wmem_tree_t *luns;
156 } fc_conv_data_t;
157
158 /* Reassembly stuff */
159 static gboolean fc_reassemble = TRUE;
160 static guint32  fc_max_frame_size = 1024;
161 static reassembly_table fc_reassembly_table;
162
163 typedef struct _fcseq_conv_key {
164     guint32 conv_idx;
165 } fcseq_conv_key_t;
166
167 typedef struct _fcseq_conv_data {
168     guint32 seq_cnt;
169 } fcseq_conv_data_t;
170
171 static GHashTable *fcseq_req_hash = NULL;
172
173 /*
174  * Hash Functions
175  */
176 static gint
177 fcseq_equal(gconstpointer v, gconstpointer w)
178 {
179     const fcseq_conv_key_t *v1 = (const fcseq_conv_key_t *)v;
180     const fcseq_conv_key_t *v2 = (const fcseq_conv_key_t *)w;
181
182     return (v1->conv_idx == v2->conv_idx);
183 }
184
185 static guint
186 fcseq_hash (gconstpointer v)
187 {
188     const fcseq_conv_key_t *key = (const fcseq_conv_key_t *)v;
189     guint val;
190
191     val = key->conv_idx;
192
193     return val;
194 }
195
196 static void
197 fc_exchange_init_protocol(void)
198 {
199     reassembly_table_init(&fc_reassembly_table,
200                           &addresses_reassembly_table_functions);
201
202     if (fcseq_req_hash)
203         g_hash_table_destroy(fcseq_req_hash);
204
205     fcseq_req_hash = g_hash_table_new(fcseq_hash, fcseq_equal);
206 }
207
208
209 const value_string fc_fc4_val[] = {
210     {FC_TYPE_BLS,        "Basic Link Svc"},
211     {FC_TYPE_ELS,        "Ext Link Svc"},
212     {FC_TYPE_LLCSNAP,    "LLC_SNAP"},
213     {FC_TYPE_IP,         "IP/FC"},
214     {FC_TYPE_SCSI,       "FCP"},
215     {FC_TYPE_FCCT,       "FC_CT"},
216     {FC_TYPE_SWILS,      "SW_ILS"},
217     {FC_TYPE_AL,         "AL"},
218     {FC_TYPE_SNMP,       "SNMP"},
219     {FC_TYPE_SB_FROM_CU, "SB-3(CU->Channel)"},
220     {FC_TYPE_SB_TO_CU,   "SB-3(Channel->CU)"},
221     {0, NULL}
222 };
223
224 static const value_string fc_ftype_vals [] = {
225     {FC_FTYPE_UNDEF ,    "Unknown frame"},
226     {FC_FTYPE_SWILS,     "SW_ILS"},
227     {FC_FTYPE_IP ,       "IP/FC"},
228     {FC_FTYPE_SCSI ,     "FCP"},
229     {FC_FTYPE_BLS ,      "Basic Link Svc"},
230     {FC_FTYPE_ELS ,      "ELS"},
231     {FC_FTYPE_FCCT ,     "FC_CT"},
232     {FC_FTYPE_LINKDATA,  "Link Data"},
233     {FC_FTYPE_VDO,       "Video Data"},
234     {FC_FTYPE_LINKCTL,   "Link Ctl"},
235     {FC_FTYPE_SBCCS,     "SBCCS"},
236     {FC_FTYPE_OHMS,      "OHMS(Cisco MDS)"},
237     {0, NULL}
238 };
239
240 static const value_string fc_wka_vals[] _U_ = {
241     {FC_WKA_MULTICAST,    "Multicast Server"},
242     {FC_WKA_CLKSYNC,      "Clock Sync Server"},
243     {FC_WKA_KEYDIST,      "Key Distribution Server"},
244     {FC_WKA_ALIAS,        "Alias Server"},
245     {FC_WKA_QOSF,         "QoS Facilitator"},
246     {FC_WKA_MGMT,         "Management Server"},
247     {FC_WKA_TIME,         "Time Server"},
248     {FC_WKA_DNS,          "Directory Server"},
249     {FC_WKA_FABRIC_CTRLR, "Fabric Ctlr"},
250     {FC_WKA_FPORT,        "F_Port Server"},
251     {FC_WKA_BCAST,        "Broadcast ID"},
252     {0, NULL}
253 };
254
255 static const value_string fc_routing_val[] = {
256     {FC_RCTL_DEV_DATA,  "Device_Data"},
257     {FC_RCTL_ELS,       "Extended Link Services"},
258     {FC_RCTL_LINK_DATA, "FC-4 Link_Data"},
259     {FC_RCTL_VIDEO,     "Video_Data"},
260     {FC_RCTL_BLS,       "Basic Link Services"},
261     {FC_RCTL_LINK_CTL,  "Link_Control Frame"},
262     {0, NULL}
263 };
264
265 static const value_string fc_iu_val[] = {
266     {FC_IU_UNCATEGORIZED   , "Uncategorized Data"},
267     {FC_IU_SOLICITED_DATA  , "Solicited Data"},
268     {FC_IU_UNSOLICITED_CTL , "Unsolicited Control"},
269     {FC_IU_SOLICITED_CTL   , "Solicited Control"},
270     {FC_IU_UNSOLICITED_DATA, "Solicited Data"},
271     {FC_IU_DATA_DESCRIPTOR , "Data Descriptor"},
272     {FC_IU_UNSOLICITED_CMD , "Unsolicited Command"},
273     {FC_IU_CMD_STATUS      , "Command Status"},
274     {0, NULL}
275 };
276
277
278 /* For FC SOF */
279 #define    FC_SOFC1  0xBCB51717
280 #define    FC_SOFI1  0xBCB55757
281 #define    FC_SOFN1  0xBCB53737
282 #define    FC_SOFI2  0xBCB55555
283 #define    FC_SOFN2  0xBCB53535
284 #define    FC_SOFI3  0xBCB55656
285 #define    FC_SOFN3  0xBCB53636
286 #define    FC_SOFC4  0xBCB51919
287 #define    FC_SOFI4  0xBCB55959
288 #define    FC_SOFN4  0xBCB53939
289 #define    FC_SOFF   0xBCB55858
290
291 #define    EOFT_NEG    0xBC957575
292 #define    EOFT_POS    0xBCB57575
293 #define    EOFDT_NEG   0xBC959595
294 #define    EOFDT_POS   0xBCB59595
295 #define    EOFA_NEG    0xBC95F5F5
296 #define    EOFA_POS    0xBCB5F5F5
297 #define    EOFN_NEG    0xBC95D5D5
298 #define    EOFN_POS    0xBCB5D5D5
299 #define    EOFNI_NEG   0xBC8AD5D5
300 #define    EOFNI_POS   0xBCAAD5D5
301 #define    EOFDTI_NEG  0xBC8A9595
302 #define    EOFDTI_POS  0xBCAA9595
303 #define    EOFRT_NEG   0xBC959999
304 #define    EOFRT_POS   0xBCB59999
305 #define    EOFRTI_NEG  0xBC8A9999
306 #define    EOFRTI_POS  0xBCAA9999
307
308 static const value_string fc_sof_vals[] = {
309     {FC_SOFC1, "SOFc1 - SOF Connect Class 1 (Obsolete)" },
310     {FC_SOFI1, "SOFi1 - SOF Initiate Class 1 (Obsolete)" },
311     {FC_SOFN1, "SOFn1 - SOF Normal Class 1 (Obsolete)" },
312     {FC_SOFI2, "SOFi2 - SOF Initiate Class 2" },
313     {FC_SOFN2, "SOFn2 - SOF Normal Class 2" },
314     {FC_SOFI3, "SOFi3 - SOF Initiate Class 3" },
315     {FC_SOFN3, "SOFn3 - SOF Normal Class 3" },
316     {FC_SOFC4, "SOFc4 - SOF Activate Class 4 (Obsolete)" },
317     {FC_SOFI4, "SOFi4 - SOF Initiate Class 4 (Obsolete)" },
318     {FC_SOFN4, "SOFn4 - SOF Normal Class 4 (Obsolete)" },
319     {FC_SOFF,  "SOFf - SOF Fabric" },
320     {0, NULL}
321 };
322
323 static const value_string fc_eof_vals[] = {
324     {EOFT_NEG,   "EOFt- - EOF Terminate" },
325     {EOFT_POS,   "EOFt+ - EOF Terminate" },
326     {EOFDT_NEG,  "EOFdt- - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
327     {EOFDT_POS,  "EOFdt+ - EOF Disconnect-Terminate-Class 1 (Obsolete)" },
328     {EOFA_NEG,   "EOFa- - EOF Abort" },
329     {EOFA_POS,   "EOFa+ - EOF Abort" },
330     {EOFN_NEG,   "EOFn- - EOF Normal" },
331     {EOFN_POS,   "EOFn+ - EOF Normal" },
332     {EOFNI_NEG,  "EOFni- - EOF Normal Invalid" },
333     {EOFNI_POS,  "EOFni+ - EOF Normal Invalid" },
334     {EOFDTI_NEG, "EOFdti- - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
335     {EOFDTI_POS, "EOFdti+ - EOF Disconnect-Terminate-Invalid Class 1 (Obsolete)" },
336     {EOFRT_NEG,  "EOFrt- - EOF Remove-Terminate Class 4 (Obsolete)" },
337     {EOFRT_POS,  "EOFrt+ - EOF Remove-Terminate Class 4 (Obsolete)" },
338     {EOFRTI_NEG, "EOFrti- - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
339     {EOFRTI_POS, "EOFrti+ - EOF Remove-Terminate Invalid Class 4 (Obsolete)" },
340     {0, NULL}
341 };
342
343 /* BA_ACC & BA_RJT are decoded in this file itself instead of a traditional
344  * dedicated file and dissector format because the dissector would require some
345  * fields of the FC_HDR such as param in some cases, type in some others, the
346  * lower 4 bits of r_ctl in some other cases etc. So, we decode BLS & Link Ctl
347  * in this file itself.
348  */
349 static void
350 dissect_fc_ba_acc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
351 {
352     /* Set up structures needed to add the protocol subtree and manage it */
353     proto_item *ti;
354     proto_tree *acc_tree;
355     int offset = 0;
356
357     /* Make entries in Protocol column and Info column on summary display */
358     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
359
360     col_set_str(pinfo->cinfo, COL_INFO, "BA_ACC");
361
362     if (tree) {
363         ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
364         acc_tree = proto_item_add_subtree (ti, ett_fcbls);
365
366         proto_tree_add_item (acc_tree, hf_fc_bls_seqid_vld, tvb, offset++, 1, ENC_BIG_ENDIAN);
367         proto_tree_add_item (acc_tree, hf_fc_bls_lastvld_seqid, tvb, offset++, 1, ENC_BIG_ENDIAN);
368         offset += 2; /* Skip reserved field */
369         proto_tree_add_item (acc_tree, hf_fc_bls_oxid, tvb, offset, 2, ENC_BIG_ENDIAN);
370         offset += 2;
371         proto_tree_add_item (acc_tree, hf_fc_bls_rxid, tvb, offset, 2, ENC_BIG_ENDIAN);
372         offset += 2;
373         proto_tree_add_item (acc_tree, hf_fc_bls_lowseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
374         offset += 2;
375         proto_tree_add_item (acc_tree, hf_fc_bls_hiseqcnt, tvb, offset, 2, ENC_BIG_ENDIAN);
376     }
377 }
378
379 static void
380 dissect_fc_ba_rjt (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
381 {
382     /* Set up structures needed to add the protocol subtree and manage it */
383     proto_item *ti;
384     proto_tree *rjt_tree;
385     int offset = 0;
386
387     /* Make entries in Protocol column and Info column on summary display */
388     col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
389
390     col_set_str(pinfo->cinfo, COL_INFO, "BA_RJT");
391
392     if (tree) {
393         ti = proto_tree_add_text (tree, tvb, 0, tvb_length (tvb), "Basic Link Svc");
394         rjt_tree = proto_item_add_subtree (ti, ett_fcbls);
395
396         proto_tree_add_item (rjt_tree, hf_fc_bls_rjtcode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
397         proto_tree_add_item (rjt_tree, hf_fc_bls_rjtdetail, tvb, offset+2, 1, ENC_BIG_ENDIAN);
398         proto_tree_add_item (rjt_tree, hf_fc_bls_vendor, tvb, offset+3, 1, ENC_BIG_ENDIAN);
399     }
400 }
401
402 static guint8
403 fc_get_ftype (guint8 r_ctl, guint8 type)
404 {
405     /* A simple attempt to determine the upper level protocol based on the
406      * r_ctl & type fields.
407      */
408     switch (r_ctl & 0xF0) {
409     case FC_RCTL_DEV_DATA:
410         switch (type) {
411         case FC_TYPE_SWILS:
412             if ((r_ctl == 0x2) || (r_ctl == 0x3))
413                 return FC_FTYPE_SWILS;
414             else
415                 return FC_FTYPE_UNDEF;
416         case FC_TYPE_IP:
417             return FC_FTYPE_IP;
418         case FC_TYPE_SCSI:
419             return FC_FTYPE_SCSI;
420         case FC_TYPE_FCCT:
421             return FC_FTYPE_FCCT;
422         case FC_TYPE_SB_FROM_CU:
423         case FC_TYPE_SB_TO_CU:
424             return FC_FTYPE_SBCCS;
425         case FC_TYPE_VENDOR:
426              return FC_FTYPE_OHMS;
427         default:
428             return FC_FTYPE_UNDEF;
429         }
430     case FC_RCTL_ELS:
431         if (((r_ctl & 0x0F) == 0x2) || ((r_ctl & 0x0F) == 0x3))
432             return FC_FTYPE_ELS;
433         else if (type == FC_TYPE_ELS)
434             return FC_FTYPE_OHMS;
435         else
436              return FC_FTYPE_UNDEF;
437     case FC_RCTL_LINK_DATA:
438         switch (type) {
439         case FC_TYPE_SCSI:
440             return FC_FTYPE_SCSI;
441         default:
442             return FC_FTYPE_LINKDATA;
443         }
444     case FC_RCTL_VIDEO:
445         return FC_FTYPE_VDO;
446     case FC_RCTL_BLS:
447         if (type == 0)
448             return FC_FTYPE_BLS;
449         else
450             return FC_FTYPE_UNDEF;
451     case FC_RCTL_LINK_CTL:
452         return FC_FTYPE_LINKCTL;
453     default:
454         return FC_FTYPE_UNDEF;
455     }
456 }
457
458 static const value_string abts_ack_vals[] = {
459     {0x000000,  "ABTS - Cont"},
460     {0x000010,  "ABTS - Abort"},
461     {0x000020,  "ABTS - Stop"},
462     {0x000030,  "ABTS - Imm Seq Retx"},
463     {0,NULL}
464 };
465 #if 0
466 static const value_string abts_not_ack_vals[] = {
467     {0x000000,  "ABTS - Abort/MS"},
468     {0x000010,  "ABTS - Abort/SS"},
469     {0x000020,  "ABTS - Process/IB"},
470     {0x000030,  "ABTS - Discard/MS/Imm Retx"},
471     {0,NULL}
472 };
473 #endif
474 static const value_string last_data_frame_vals[] = {
475     {0x000000,  "Last Data Frame - No Info"},
476     {0x004000,  "Last Data Frame - Seq Imm"},
477     {0x008000,  "Last Data Frame - Seq Soon"},
478     {0x00c000,  "Last Data Frame - Seq Delyd"},
479     {0,NULL}
480 };
481 static const value_string ack_0_1_vals[] = {
482     {0x003000,  "ACK_0 Required"},
483     {0x002000,  "ACK_0 Required"},
484     {0x001000,  "ACK_1 Required"},
485     {0x000000,  "no ack required"},
486     {0,NULL}
487 };
488 static const true_false_string tfs_fc_fctl_exchange_responder = {
489     "Exchange Responder",
490     "Exchange Originator"
491 };
492 static const true_false_string tfs_fc_fctl_seq_recipient = {
493     "Seq Recipient",
494     "Seq Initiator"
495 };
496 static const true_false_string tfs_fc_fctl_exchange_first = {
497     "Exchg First",
498     "NOT exchg first"
499 };
500 static const true_false_string tfs_fc_fctl_exchange_last = {
501     "Exchg Last",
502     "NOT exchg last"
503 };
504 static const true_false_string tfs_fc_fctl_seq_last = {
505     "Seq Last",
506     "NOT seq last"
507 };
508 static const true_false_string tfs_fc_fctl_priority = {
509     "Priority",
510     "CS_CTL"
511 };
512 static const true_false_string tfs_fc_fctl_transfer_seq_initiative = {
513     "Transfer Seq Initiative",
514     "NOT transfer seq initiative"
515 };
516 static const true_false_string tfs_fc_fctl_rexmitted_seq = {
517     "Retransmitted Sequence",
518     "NOT retransmitted sequence"
519 };
520 static const true_false_string tfs_fc_fctl_rel_offset = {
521     "Rel Offset SET",
522     "rel offset NOT set"
523 };
524
525 /*
526  * Dissect the VFT header.
527  */
528 static void
529 dissect_fc_vft(proto_tree *parent_tree,
530                 tvbuff_t *tvb, int offset)
531 {
532     proto_item *item = NULL;
533     proto_tree *tree = NULL;
534     guint8 rctl;
535     guint8 ver;
536     guint8 type;
537     guint8 pri;
538     guint16 vf_id;
539     guint8 hop_ct;
540
541     rctl = tvb_get_guint8(tvb, offset);
542     type = tvb_get_guint8(tvb, offset + 1);
543     ver = (type >> 6) & 3;
544     type = (type >> 2) & 0xf;
545     vf_id = tvb_get_ntohs(tvb, offset + 2);
546     pri = (vf_id >> 13) & 7;
547     vf_id = (vf_id >> 1) & 0xfff;
548     hop_ct = tvb_get_guint8(tvb, offset + 4);
549
550     if (parent_tree) {
551         item = proto_tree_add_uint_format_value(parent_tree, hf_fc_vft, tvb, offset,
552                                     8, vf_id, "VF_ID %d Pri %d Hop Count %d",
553                                     vf_id, pri, hop_ct);
554         tree = proto_item_add_subtree(item, ett_fc_vft);
555     }
556     proto_tree_add_uint(tree, hf_fc_vft_rctl, tvb, offset, 1, rctl);
557     proto_tree_add_uint(tree, hf_fc_vft_ver, tvb, offset + 1, 1, ver);
558     proto_tree_add_uint(tree, hf_fc_vft_type, tvb, offset + 1, 1, type);
559     proto_tree_add_uint(tree, hf_fc_vft_pri, tvb, offset + 2, 1, pri);
560     proto_tree_add_uint(tree, hf_fc_vft_vf_id, tvb, offset + 2, 2, vf_id);
561     proto_tree_add_uint(tree, hf_fc_vft_hop_ct, tvb, offset + 4, 1, hop_ct);
562 }
563
564 /* code to dissect the  F_CTL bitmask */
565 static void
566 dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset)
567 {
568     proto_item *item=NULL;
569     proto_tree *tree=NULL;
570     guint32 flags;
571
572     flags = tvb_get_guint8 (tvb, offset);
573     flags = (flags<<8) | tvb_get_guint8 (tvb, offset+1);
574     flags = (flags<<8) | tvb_get_guint8 (tvb, offset+2);
575
576     if(parent_tree){
577         item=proto_tree_add_uint(parent_tree, hf_fc_fctl, tvb, offset, 3, flags);
578         tree=proto_item_add_subtree(item, ett_fctl);
579     }
580
581     proto_tree_add_boolean(tree, hf_fc_fctl_exchange_responder, tvb, offset, 3, flags);
582     if (flags&FC_FCTL_EXCHANGE_RESPONDER){
583         proto_item_append_text(item, " Exchange Responder");
584         if (flags & (~( FC_FCTL_EXCHANGE_RESPONDER )))
585             proto_item_append_text(item, ",");
586     } else {
587         proto_item_append_text(item, " Exchange Originator");
588         if (flags & (~( FC_FCTL_EXCHANGE_RESPONDER )))
589             proto_item_append_text(item, ",");
590     }
591     flags&=(~( FC_FCTL_EXCHANGE_RESPONDER ));
592
593     proto_tree_add_boolean(tree, hf_fc_fctl_seq_recipient, tvb, offset, 3, flags);
594     if (flags&FC_FCTL_SEQ_RECIPIENT){
595         proto_item_append_text(item, " Seq Recipient");
596         if (flags & (~( FC_FCTL_SEQ_RECIPIENT )))
597             proto_item_append_text(item, ",");
598     } else {
599         proto_item_append_text(item, " Seq Initiator");
600         if (flags & (~( FC_FCTL_SEQ_RECIPIENT )))
601             proto_item_append_text(item, ",");
602     }
603     flags&=(~( FC_FCTL_SEQ_RECIPIENT ));
604
605     proto_tree_add_boolean(tree, hf_fc_fctl_exchange_first, tvb, offset, 3, flags);
606     if (flags&FC_FCTL_EXCHANGE_FIRST){
607         proto_item_append_text(item, " Exchg First");
608         if (flags & (~( FC_FCTL_EXCHANGE_FIRST )))
609             proto_item_append_text(item, ",");
610     }
611     flags&=(~( FC_FCTL_EXCHANGE_FIRST ));
612
613     proto_tree_add_boolean(tree, hf_fc_fctl_exchange_last, tvb, offset, 3, flags);
614     if (flags&FC_FCTL_EXCHANGE_LAST){
615         proto_item_append_text(item, " Exchg Last");
616         if (flags & (~( FC_FCTL_EXCHANGE_LAST )))
617             proto_item_append_text(item, ",");
618     }
619     flags&=(~( FC_FCTL_EXCHANGE_LAST ));
620
621     proto_tree_add_boolean(tree, hf_fc_fctl_seq_last, tvb, offset, 3, flags);
622     if (flags&FC_FCTL_SEQ_LAST){
623         proto_item_append_text(item, " Seq Last");
624         if (flags & (~( FC_FCTL_SEQ_LAST )))
625             proto_item_append_text(item, ",");
626     }
627     flags&=(~( FC_FCTL_SEQ_LAST ));
628
629     proto_tree_add_boolean(tree, hf_fc_fctl_priority, tvb, offset, 3, flags);
630     if (flags&FC_FCTL_PRIORITY){
631         proto_item_append_text(item, " Priority");
632         if (flags & (~( FC_FCTL_PRIORITY )))
633             proto_item_append_text(item, ",");
634     } else {
635         proto_item_append_text(item, " CS_CTL");
636         if (flags & (~( FC_FCTL_PRIORITY )))
637             proto_item_append_text(item, ",");
638     }
639     flags&=(~( FC_FCTL_PRIORITY ));
640
641     proto_tree_add_boolean(tree, hf_fc_fctl_transfer_seq_initiative, tvb, offset, 3, flags);
642     if (flags&FC_FCTL_TRANSFER_SEQ_INITIATIVE){
643         proto_item_append_text(item, " Transfer Seq Initiative");
644         if (flags & (~( FC_FCTL_TRANSFER_SEQ_INITIATIVE )))
645             proto_item_append_text(item, ",");
646     }
647     flags&=(~( FC_FCTL_TRANSFER_SEQ_INITIATIVE ));
648
649     proto_tree_add_uint(tree, hf_fc_fctl_last_data_frame, tvb, offset, 3, flags);
650
651     proto_tree_add_uint(tree, hf_fc_fctl_ack_0_1, tvb, offset, 3, flags);
652
653     proto_tree_add_boolean(tree, hf_fc_fctl_rexmitted_seq, tvb, offset, 3, flags);
654     if (flags&FC_FCTL_REXMITTED_SEQ){
655         proto_item_append_text(item, " Rexmitted Seq");
656         if (flags & (~( FC_FCTL_REXMITTED_SEQ )))
657             proto_item_append_text(item, ",");
658     }
659     flags&=(~( FC_FCTL_REXMITTED_SEQ ));
660
661     proto_tree_add_uint(tree, hf_fc_fctl_abts_ack, tvb, offset, 3, flags);
662
663     proto_tree_add_boolean(tree, hf_fc_fctl_rel_offset, tvb, offset, 3, flags);
664     if (flags&FC_FCTL_REL_OFFSET){
665         proto_item_append_text(item, " Rel Offset");
666         if (flags & (~( FC_FCTL_REL_OFFSET )))
667             proto_item_append_text(item, ",");
668     }
669
670 }
671
672 static const value_string fc_bls_proto_val[] = {
673     {FC_BLS_NOP    , "NOP"},
674     {FC_BLS_ABTS   , "ABTS"},
675     {FC_BLS_RMC    , "RMC"},
676     {FC_BLS_BAACC  , "BA_ACC"},
677     {FC_BLS_BARJT  , "BA_RJT"},
678     {FC_BLS_PRMT   , "PRMT"},
679     {0, NULL}
680 };
681
682 static const value_string fc_els_proto_val[] = {
683     {0x01    , "Solicited Data"},
684     {0x02    , "Request"},
685     {0x03    , "Reply"},
686     {0, NULL}
687 };
688
689 /* Code to actually dissect the packets */
690 static void
691 dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_ifcp, fc_data_t* fc_data)
692 {
693    /* Set up structures needed to add the protocol subtree and manage it */
694     proto_item *ti, *hidden_item;
695     proto_tree *fc_tree;
696     tvbuff_t *next_tvb;
697     int offset = 0, next_offset;
698     int vft_offset = -1;
699     gboolean is_lastframe_inseq, is_1frame_inseq, is_exchg_resp = 0;
700     fragment_head *fcfrag_head;
701     guint32 frag_id, frag_size;
702     guint8 df_ctl, seq_id;
703     guint32 f_ctl;
704
705     guint32 param, exchange_key;
706     guint16 real_seqcnt;
707     guint8 ftype;
708
709     fc_hdr fchdr;
710     fc_exchange_t *fc_ex;
711     fc_conv_data_t *fc_conv_data=NULL;
712
713     conversation_t *conversation;
714     fcseq_conv_data_t *cdata;
715     fcseq_conv_key_t ckey, *req_key;
716
717     /* Make entries in Protocol column and Info column on summary display */
718     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
719
720     fchdr.r_ctl = tvb_get_guint8 (tvb, offset);
721     fchdr.fc_ex = NULL;
722
723     /*
724      * If the frame contains a VFT (virtual fabric tag), decode it
725      * as a separate header before the FC frame header.
726      *
727      * This used to be called the Cisco-proprietary EISL field, but is now
728      * standardized in FC-FS-2.  See section 10.2.4.
729      */
730     if (fchdr.r_ctl == FC_RCTL_VFT) {
731         vft_offset = offset;
732         offset += 8;
733         fchdr.r_ctl = tvb_get_guint8 (tvb, offset);
734     }
735
736     /* Each fc endpoint pair gets its own TCP session in iFCP but
737      * the src/dst ids are undefined(==semi-random) in the FC header.
738      * This means we can no track conversations for FC over iFCP by using
739      * the FC src/dst addresses.
740      * For iFCP: Do not update the pinfo src/dst struct and let it remain
741      * being tcpip src/dst so that request/response matching in the FCP layer
742      * will use ip addresses instead and still work.
743      */
744     if(!is_ifcp){
745         TVB_SET_ADDRESS (&pinfo->dst, AT_FC, tvb, offset+1, 3);
746         TVB_SET_ADDRESS (&pinfo->src, AT_FC, tvb, offset+5, 3);
747         pinfo->srcport=0;
748         pinfo->destport=0;
749     }
750     SET_ADDRESS(&fchdr.d_id, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
751     SET_ADDRESS(&fchdr.s_id, pinfo->src.type, pinfo->src.len, pinfo->src.data);
752
753     fchdr.cs_ctl = tvb_get_guint8 (tvb, offset+4);
754     fchdr.type  = tvb_get_guint8 (tvb, offset+8);
755     fchdr.fctl=tvb_get_ntoh24(tvb,offset+9);
756     fchdr.seqcnt = tvb_get_ntohs (tvb, offset+14);
757     fchdr.oxid=tvb_get_ntohs(tvb,offset+16);
758     fchdr.rxid=tvb_get_ntohs(tvb,offset+18);
759     fchdr.relative_offset=0;
760     param = tvb_get_ntohl (tvb, offset+20);
761     seq_id = tvb_get_guint8 (tvb, offset+12);
762
763     pinfo->ptype = PT_EXCHG;
764
765     /* set up a conversation and conversation data */
766     /* TODO treat the fc address  s_id==00.00.00 as a wildcard matching anything */
767     conversation=find_or_create_conversation(pinfo);
768     fc_conv_data=(fc_conv_data_t *)conversation_get_proto_data(conversation, proto_fc);
769     if(!fc_conv_data){
770         fc_conv_data=wmem_new(wmem_file_scope(), fc_conv_data_t);
771         fc_conv_data->exchanges=wmem_tree_new(wmem_file_scope());
772         fc_conv_data->luns=wmem_tree_new(wmem_file_scope());
773         conversation_add_proto_data(conversation, proto_fc, fc_conv_data);
774     }
775
776     /* Set up LUN data. OXID + LUN make up unique exchanges, but LUN is populated in subdissectors
777        and not necessarily in every frame. Stub it here for now */
778     fchdr.lun = 0xFFFF;
779     if (!pinfo->fd->flags.visited) {
780         fchdr.lun = (guint16)GPOINTER_TO_UINT(wmem_tree_lookup32(fc_conv_data->luns, fchdr.oxid));
781     }
782
783     /* In the interest of speed, if "tree" is NULL, don't do any work not
784        necessary to generate protocol tree items. */
785     ti = proto_tree_add_protocol_format (tree, proto_fc, tvb, offset, FC_HEADER_SIZE, "Fibre Channel");
786     fc_tree = proto_item_add_subtree (ti, ett_fc);
787
788     /*is_ack = ((fchdr.r_ctl == 0xC0) || (fchdr.r_ctl == 0xC1));*/
789
790     /* There are two ways to determine if this is the first frame of a
791      * sequence. Either:
792      * (i) The SOF bits indicate that this is the first frame OR
793      * (ii) This is an SOFf frame and seqcnt is 0.
794      */
795     is_1frame_inseq = (((fc_data->sof_eof & FC_DATA_SOF_FIRST_FRAME) == FC_DATA_SOF_FIRST_FRAME) ||
796                        (((fc_data->sof_eof & FC_DATA_SOF_SOFF) == FC_DATA_SOF_SOFF) &&
797                         (fchdr.seqcnt == 0)));
798
799     is_lastframe_inseq = ((fc_data->sof_eof & FC_DATA_EOF_LAST_FRAME) == FC_DATA_EOF_LAST_FRAME);
800
801     is_lastframe_inseq |= fchdr.fctl & FC_FCTL_SEQ_LAST;
802     /*is_valid_frame = ((pinfo->sof_eof & 0x40) == 0x40);*/
803
804     ftype = fc_get_ftype (fchdr.r_ctl, fchdr.type);
805
806     col_add_str (pinfo->cinfo, COL_INFO, val_to_str (ftype, fc_ftype_vals,
807                                                         "Unknown Type (0x%x)"));
808
809     if (ftype == FC_FTYPE_LINKCTL)
810         col_append_fstr (pinfo->cinfo, COL_INFO, ", %s",
811                             val_to_str ((fchdr.r_ctl & 0x0F),
812                                         fc_lctl_proto_val,
813                                         "LCTL 0x%x"));
814
815     if (vft_offset >= 0) {
816         dissect_fc_vft(fc_tree, tvb, vft_offset);
817     }
818     switch (fchdr.r_ctl & 0xF0) {
819
820     case FC_RCTL_DEV_DATA:
821     case FC_RCTL_LINK_DATA:
822     case FC_RCTL_VIDEO:
823         /* the lower 4 bits of R_CTL are the information category */
824         proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
825                                     FC_RCTL_SIZE, fchdr.r_ctl,
826                                     "0x%x(%s/%s)",
827                                     fchdr.r_ctl,
828                                     val_to_str ((fchdr.r_ctl & 0xF0),
829                                                 fc_routing_val, "0x%x"),
830                                     val_to_str ((fchdr.r_ctl & 0x0F),
831                                                 fc_iu_val, "0x%x"));
832         break;
833
834     case FC_RCTL_LINK_CTL:
835         /* the lower 4 bits of R_CTL indicate the type of link ctl frame */
836         proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
837                                     FC_RCTL_SIZE, fchdr.r_ctl,
838                                     "0x%x(%s/%s)",
839                                     fchdr.r_ctl,
840                                     val_to_str ((fchdr.r_ctl & 0xF0),
841                                                 fc_routing_val, "0x%x"),
842                                     val_to_str ((fchdr.r_ctl & 0x0F),
843                                                 fc_lctl_proto_val, "0x%x"));
844         break;
845
846     case FC_RCTL_BLS:
847         switch (fchdr.type) {
848
849         case 0x00:
850             /* the lower 4 bits of R_CTL indicate the type of BLS frame */
851             proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
852                                         FC_RCTL_SIZE, fchdr.r_ctl,
853                                         "0x%x(%s/%s)",
854                                         fchdr.r_ctl,
855                                         val_to_str ((fchdr.r_ctl & 0xF0),
856                                                     fc_routing_val, "0x%x"),
857                                         val_to_str ((fchdr.r_ctl & 0x0F),
858                                                     fc_bls_proto_val, "0x%x"));
859             break;
860
861         default:
862             proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
863                                         FC_RCTL_SIZE, fchdr.r_ctl,
864                                         "0x%x(%s/0x%x)",
865                                         fchdr.r_ctl,
866                                         val_to_str ((fchdr.r_ctl & 0xF0),
867                                                     fc_routing_val, "0x%x"),
868                                         fchdr.r_ctl & 0x0F);
869             break;
870         }
871         break;
872
873     case FC_RCTL_ELS:
874         switch (fchdr.type) {
875
876         case 0x01:
877             /* the lower 4 bits of R_CTL indicate the type of ELS frame */
878             proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
879                                         FC_RCTL_SIZE, fchdr.r_ctl,
880                                         "0x%x(%s/%s)",
881                                         fchdr.r_ctl,
882                                         val_to_str ((fchdr.r_ctl & 0xF0),
883                                                     fc_routing_val, "0x%x"),
884                                         val_to_str ((fchdr.r_ctl & 0x0F),
885                                                     fc_els_proto_val, "0x%x"));
886             break;
887
888         default:
889             proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
890                                         FC_RCTL_SIZE, fchdr.r_ctl,
891                                         "0x%x(%s/0x%x)",
892                                         fchdr.r_ctl,
893                                         val_to_str ((fchdr.r_ctl & 0xF0),
894                                                     fc_routing_val, "0x%x"),
895                                         fchdr.r_ctl & 0x0F);
896             break;
897         }
898         break;
899
900     default:
901         proto_tree_add_uint_format_value(fc_tree, hf_fc_rctl, tvb, offset,
902                                     FC_RCTL_SIZE, fchdr.r_ctl,
903                                     "0x%x(%s/0x%x)",
904                                     fchdr.r_ctl,
905                                     val_to_str ((fchdr.r_ctl & 0xF0),
906                                                 fc_routing_val, "0x%x"),
907                                     fchdr.r_ctl & 0x0F);
908         break;
909     }
910
911     hidden_item = proto_tree_add_uint (fc_tree, hf_fc_ftype, tvb, offset, 1,
912                                        ftype);
913     PROTO_ITEM_SET_HIDDEN(hidden_item);
914
915     /* XXX - use "fc_wka_vals[]" on this? */
916     proto_tree_add_string (fc_tree, hf_fc_did, tvb, offset+1, 3,
917                            fc_to_str ((const guint8 *)fchdr.d_id.data));
918     hidden_item = proto_tree_add_string (fc_tree, hf_fc_id, tvb, offset+1, 3,
919                                          fc_to_str ((const guint8 *)fchdr.d_id.data));
920     PROTO_ITEM_SET_HIDDEN(hidden_item);
921
922     proto_tree_add_uint (fc_tree, hf_fc_csctl, tvb, offset+4, 1, fchdr.cs_ctl);
923
924     /* XXX - use "fc_wka_vals[]" on this? */
925     proto_tree_add_string (fc_tree, hf_fc_sid, tvb, offset+5, 3,
926                            fc_to_str ((const guint8 *)fchdr.s_id.data));
927     hidden_item = proto_tree_add_string (fc_tree, hf_fc_id, tvb, offset+5, 3,
928                                          fc_to_str ((const guint8 *)fchdr.s_id.data));
929     PROTO_ITEM_SET_HIDDEN(hidden_item);
930
931     if (ftype == FC_FTYPE_LINKCTL) {
932         if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYB) ||
933             ((fchdr.r_ctl & 0x0F) == FC_LCTL_FBSYL)) {
934             /* for F_BSY frames, the upper 4 bits of the type field specify the
935              * reason for the BSY.
936              */
937             proto_tree_add_uint_format_value(fc_tree, hf_fc_type, tvb,
938                                         offset+8, FC_TYPE_SIZE,
939                                         fchdr.type,"0x%x(%s)", fchdr.type,
940                                         fclctl_get_typestr ((guint8) (fchdr.r_ctl & 0x0F),
941                                                             fchdr.type));
942         } else {
943             proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
944         }
945     } else {
946         proto_tree_add_item (fc_tree, hf_fc_type, tvb, offset+8, 1, ENC_BIG_ENDIAN);
947     }
948
949
950     dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9);
951     f_ctl = tvb_get_ntoh24(tvb, offset+9);
952
953
954     proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, ENC_BIG_ENDIAN);
955
956     df_ctl = tvb_get_guint8(tvb, offset+13);
957
958     proto_tree_add_uint (fc_tree, hf_fc_dfctl, tvb, offset+13, 1, df_ctl);
959     proto_tree_add_uint (fc_tree, hf_fc_seqcnt, tvb, offset+14, 2, fchdr.seqcnt);
960     proto_tree_add_uint (fc_tree, hf_fc_oxid, tvb, offset+16, 2, fchdr.oxid);
961     proto_tree_add_uint (fc_tree, hf_fc_rxid, tvb, offset+18, 2, fchdr.rxid);
962
963     if (ftype == FC_FTYPE_LINKCTL) {
964         if (((fchdr.r_ctl & 0x0F) == FC_LCTL_FRJT) ||
965             ((fchdr.r_ctl & 0x0F) == FC_LCTL_PRJT) ||
966             ((fchdr.r_ctl & 0x0F) == FC_LCTL_PBSY)) {
967             /* In all these cases of Link Ctl frame, the parameter field
968              * encodes the detailed error message
969              */
970             proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
971                                         offset+20, 4, param,
972                                         "0x%x(%s)", param,
973                                         fclctl_get_paramstr ((fchdr.r_ctl & 0x0F),
974                                                              param));
975         } else {
976             proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
977         }
978     } else if (ftype == FC_FTYPE_BLS) {
979         if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
980             proto_tree_add_uint_format_value(fc_tree, hf_fc_param, tvb,
981                                         offset+20, 4, param,
982                                         "0x%x(%s)", param,
983                                         ((param & 0x0F) == 1 ? "Abort Sequence" :
984                                          "Abort Exchange"));
985         } else {
986             proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20,
987                                  4, ENC_BIG_ENDIAN);
988         }
989     } else if (ftype == FC_FTYPE_SCSI ) {
990         if (f_ctl&FC_FCTL_REL_OFFSET){
991             proto_tree_add_item (fc_tree, hf_fc_relative_offset, tvb, offset+20, 4, ENC_BIG_ENDIAN);
992             fchdr.relative_offset=tvb_get_ntohl(tvb, offset+20);
993         } else {
994             proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
995         }
996     } else {
997         proto_tree_add_item (fc_tree, hf_fc_param, tvb, offset+20, 4, ENC_BIG_ENDIAN);
998     }
999
1000     /* Skip the Frame_Header */
1001     next_offset = offset + FC_HEADER_SIZE;
1002
1003     /* Network_Header present? */
1004     if (df_ctl & FC_DFCTL_NH) {
1005         /* Yes - dissect it. */
1006         if (tree) {
1007             proto_tree_add_string (fc_tree, hf_fc_nh_da, tvb, next_offset, 8,
1008                                    fcwwn_to_str (tvb_get_string (wmem_packet_scope(), tvb, offset, 8)));
1009             proto_tree_add_string (fc_tree, hf_fc_nh_sa, tvb, offset+8, 8,
1010                                    fcwwn_to_str (tvb_get_string (wmem_packet_scope(), tvb, offset+8, 8)));
1011         }
1012         next_offset += 16;
1013     }
1014
1015     /* XXX - handle Association_Header and Device_Header here */
1016
1017     if (ftype == FC_FTYPE_LINKCTL) {
1018         /* ACK_1 frames and other LINK_CTL frames echo the last seq bit if the
1019          * packet they're ack'ing did not have it set. So, we'll incorrectly
1020          * flag them as being fragmented when they're not. This fixes the
1021          * problem
1022          */
1023         is_lastframe_inseq = TRUE;
1024     } else {
1025         is_exchg_resp = (f_ctl & FC_FCTL_EXCHANGE_RESPONDER) != 0;
1026     }
1027
1028     if (tvb_reported_length (tvb) < FC_HEADER_SIZE)
1029         THROW(ReportedBoundsError);
1030
1031     frag_size = tvb_reported_length (tvb)-FC_HEADER_SIZE;
1032
1033     /* If there is an MDS header, we need to subtract the MDS trailer size
1034      * Link Ctl, BLS & OHMS are all (encap header + FC Header + encap trailer)
1035      * and are never fragmented and so we ignore the frag_size assertion for
1036      *  these frames.
1037      */
1038     if ((fc_data->ethertype == ETHERTYPE_UNK) || (fc_data->ethertype == ETHERTYPE_FCFT)) {
1039         if ((frag_size < MDSHDR_TRAILER_SIZE) ||
1040             ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1041              (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1042             THROW(ReportedBoundsError);
1043         frag_size -= MDSHDR_TRAILER_SIZE;
1044     } else if (fc_data->ethertype == ETHERTYPE_BRDWALK) {
1045         if ((frag_size <= 8) ||
1046             ((frag_size == MDSHDR_TRAILER_SIZE) && (ftype != FC_FTYPE_LINKCTL) &&
1047              (ftype != FC_FTYPE_BLS) && (ftype != FC_FTYPE_OHMS)))
1048             THROW(ReportedBoundsError);
1049         frag_size -= 8;         /* 4 byte of FC CRC +
1050                                    4 bytes of error+EOF = 8 bytes  */
1051     }
1052
1053     if (!is_lastframe_inseq) {
1054         /* Show this only as a fragmented FC frame */
1055         col_append_str (pinfo->cinfo, COL_INFO, " (Fragmented)");
1056     }
1057
1058     /* If this is a fragment, attempt to check if fully reassembled frame is
1059      * present, if we're configured to reassemble.
1060      */
1061     if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS) &&
1062         (ftype != FC_FTYPE_OHMS) &&
1063         (!is_lastframe_inseq || !is_1frame_inseq) && fc_reassemble &&
1064         tvb_bytes_exist(tvb, FC_HEADER_SIZE, frag_size) && tree) {
1065         /* Add this to the list of fragments */
1066
1067         /* In certain cases such as FICON, the SEQ_CNT is streaming
1068          * i.e. continuously increasing. So, zero does not signify the
1069          * first frame of the sequence. To fix this, we need to save the
1070          * SEQ_CNT of the first frame in sequence and use this value to
1071          * determine the actual offset into a frame.
1072          */
1073         ckey.conv_idx = conversation->index;
1074
1075         cdata = (fcseq_conv_data_t *)g_hash_table_lookup (fcseq_req_hash,
1076                                                           &ckey);
1077
1078         if (is_1frame_inseq) {
1079             if (cdata) {
1080                 /* Since we never free the memory used by an exchange, this maybe a
1081                  * case of another request using the same exchange as a previous
1082                  * req.
1083                  */
1084                 cdata->seq_cnt = fchdr.seqcnt;
1085             }
1086             else {
1087                 req_key = wmem_new(wmem_file_scope(), fcseq_conv_key_t);
1088                 req_key->conv_idx = conversation->index;
1089
1090                 cdata = wmem_new(wmem_file_scope(), fcseq_conv_data_t);
1091                 cdata->seq_cnt = fchdr.seqcnt;
1092
1093                 g_hash_table_insert (fcseq_req_hash, req_key, cdata);
1094             }
1095             real_seqcnt = 0;
1096         }
1097         else if (cdata != NULL) {
1098             real_seqcnt = fchdr.seqcnt - cdata->seq_cnt ;
1099         }
1100         else {
1101             real_seqcnt = fchdr.seqcnt;
1102         }
1103
1104         /* Verify that this is a valid fragment */
1105         if (is_lastframe_inseq && !is_1frame_inseq && !real_seqcnt) {
1106              /* This is a frame that purports to be the last frame in a
1107               * sequence, is not the first frame, but has a seqcnt that is
1108               * 0. This is a bogus frame, don't attempt to reassemble it.
1109               */
1110              next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1111              col_append_str (pinfo->cinfo, COL_INFO, " (Bogus Fragment)");
1112         } else {
1113
1114              frag_id = ((fchdr.oxid << 16) ^ seq_id) | is_exchg_resp ;
1115
1116              /* We assume that all frames are of the same max size */
1117              fcfrag_head = fragment_add (&fc_reassembly_table,
1118                                          tvb, FC_HEADER_SIZE,
1119                                          pinfo, frag_id, NULL,
1120                                          real_seqcnt * fc_max_frame_size,
1121                                          frag_size,
1122                                          !is_lastframe_inseq);
1123
1124              if (fcfrag_head) {
1125                   next_tvb = tvb_new_chain(tvb, fcfrag_head->tvb_data);
1126
1127                   /* Add the defragmented data to the data source list. */
1128                   add_new_data_source(pinfo, next_tvb, "Reassembled FC");
1129
1130                   if (tree) {
1131                       hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1132                                                             tvb, offset+9, 1, 1);
1133                       PROTO_ITEM_SET_HIDDEN(hidden_item);
1134                   }
1135              }
1136              else {
1137                   if (tree) {
1138                        hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1139                                                              tvb, offset+9, 1, 0);
1140                        PROTO_ITEM_SET_HIDDEN(hidden_item);
1141             }
1142                   next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1143                   call_dissector (data_handle, next_tvb, pinfo, tree);
1144                   return;
1145              }
1146         }
1147     } else {
1148         if (tree) {
1149             hidden_item = proto_tree_add_boolean (fc_tree, hf_fc_reassembled,
1150                                                   tvb, offset+9, 1, 0);
1151             PROTO_ITEM_SET_HIDDEN(hidden_item);
1152         }
1153         next_tvb = tvb_new_subset_remaining (tvb, next_offset);
1154     }
1155
1156     if ((ftype != FC_FTYPE_LINKCTL) && (ftype != FC_FTYPE_BLS)) {
1157         /* If relative offset is used, only dissect the pdu with
1158          * offset 0 (param) */
1159         if( (fchdr.fctl&FC_FCTL_REL_OFFSET) && param ){
1160             call_dissector (data_handle, next_tvb, pinfo, tree);
1161         } else {
1162             if (!dissector_try_uint_new (fcftype_dissector_table, ftype,
1163                                 next_tvb, pinfo, tree, FALSE, &fchdr)) {
1164                 call_dissector (data_handle, next_tvb, pinfo, tree);
1165             }
1166         }
1167     } else if (ftype == FC_FTYPE_BLS) {
1168         if ((fchdr.r_ctl & 0x0F) == FC_BLS_BAACC) {
1169             dissect_fc_ba_acc (next_tvb, pinfo, tree);
1170         } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_BARJT) {
1171             dissect_fc_ba_rjt (next_tvb, pinfo, tree);
1172         } else if ((fchdr.r_ctl & 0x0F) == FC_BLS_ABTS) {
1173             col_set_str(pinfo->cinfo, COL_PROTOCOL, "BLS");
1174             col_set_str(pinfo->cinfo, COL_INFO, "ABTS");
1175         }
1176     }
1177
1178     /* Lun is only populated by subdissectors, and subsequent packets assume the same lun.
1179        The only way that consistently works is to save the lun on the first pass (with OXID as
1180        key) when packets are guaranteed to be parsed consecutively */
1181
1182     /* Set up LUN data */
1183     if (!pinfo->fd->flags.visited) {
1184         wmem_tree_insert32(fc_conv_data->luns, fchdr.oxid, GUINT_TO_POINTER((guint)fchdr.lun));
1185     }
1186
1187     exchange_key = ((fchdr.oxid & 0xFFFF) | ((fchdr.lun << 16) & 0xFFFF0000));
1188
1189     /* set up the exchange data */
1190     /* XXX we should come up with a way to handle when the 16bit oxid wraps
1191      * so that large traces will work
1192      */
1193     fc_ex=(fc_exchange_t*)wmem_tree_lookup32(fc_conv_data->exchanges, exchange_key);
1194     if(!fc_ex){
1195         fc_ex=wmem_new(wmem_file_scope(), fc_exchange_t);
1196         fc_ex->first_exchange_frame=0;
1197         fc_ex->last_exchange_frame=0;
1198         fc_ex->fc_time=pinfo->fd->abs_ts;
1199
1200         wmem_tree_insert32(fc_conv_data->exchanges, exchange_key, fc_ex);
1201     }
1202
1203     fchdr.fc_ex = fc_ex;
1204
1205     /* populate the exchange struct */
1206     if(!pinfo->fd->flags.visited){
1207         if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
1208             fc_ex->first_exchange_frame=pinfo->fd->num;
1209             fc_ex->fc_time = pinfo->fd->abs_ts;
1210         }
1211         if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1212             fc_ex->last_exchange_frame=pinfo->fd->num;
1213         }
1214     }
1215
1216     /* put some nice exchange data in the tree */
1217     if(!(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST)){
1218         proto_item *it;
1219         it=proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
1220         PROTO_ITEM_SET_GENERATED(it);
1221         if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
1222             nstime_t delta_ts;
1223             nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fc_ex->fc_time);
1224             it=proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
1225             PROTO_ITEM_SET_GENERATED(it);
1226         }
1227     }
1228     if(!(fchdr.fctl&FC_FCTL_EXCHANGE_LAST)){
1229         proto_item *it;
1230         it=proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
1231         PROTO_ITEM_SET_GENERATED(it);
1232     }
1233
1234     tap_queue_packet(fc_tap, pinfo, &fchdr);
1235 }
1236
1237 static int
1238 dissect_fc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1239 {
1240     fc_data_t* fc_data = (fc_data_t*)data;
1241
1242     if (!fc_data)
1243        return 0;
1244
1245     dissect_fc_helper (tvb, pinfo, tree, FALSE, fc_data);
1246     return tvb_length(tvb);
1247 }
1248
1249 static int
1250 dissect_fc_ifcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1251 {
1252     fc_data_t* fc_data = (fc_data_t*)data;
1253
1254     if (!fc_data)
1255        return 0;
1256
1257     dissect_fc_helper (tvb, pinfo, tree, TRUE, fc_data);
1258     return tvb_length(tvb);
1259 }
1260
1261 static void
1262 dissect_fcsof(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1263
1264     proto_item *it = NULL;
1265     proto_tree *fcsof_tree = NULL;
1266     gint bytes_remaining;
1267     tvbuff_t *next_tvb, *checksum_tvb;
1268     guint32 sof = 0;
1269     guint32 crc = 0;
1270     guint32 crc_computed = 0;
1271     guint32 eof = 0;
1272     gint crc_offset = 0;
1273     gint eof_offset = 0;
1274     gint sof_offset = 0;
1275     const gint FCSOF_TRAILER_LEN = 8;
1276     const gint FCSOF_HEADER_LEN = 4;
1277     gint frame_len_for_checksum = 0;
1278     fc_data_t fc_data;
1279
1280     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC");
1281
1282     crc_offset = tvb_reported_length(tvb) - FCSOF_TRAILER_LEN;
1283     eof_offset = crc_offset + 4;
1284     sof_offset = 0;
1285
1286     /* Get SOF */
1287     sof = tvb_get_ntohl(tvb, 0);
1288
1289     /* GET CRC */
1290     crc = tvb_get_ntohl(tvb, crc_offset);
1291
1292     /* GET Computed CRC */
1293     frame_len_for_checksum = crc_offset - FCSOF_HEADER_LEN;
1294     checksum_tvb = tvb_new_subset(tvb, 4, frame_len_for_checksum, frame_len_for_checksum);
1295     crc_computed = crc32_802_tvb(checksum_tvb, frame_len_for_checksum);
1296
1297     /* Get EOF */
1298     eof = tvb_get_ntohl(tvb, eof_offset);
1299
1300     it = proto_tree_add_protocol_format(tree, proto_fcsof, tvb, 0,
1301                                         4, "Fibre Channel Delimiter: SOF: %s EOF: %s",
1302                                         val_to_str(sof, fc_sof_vals, "0x%x"),
1303                                         val_to_str(eof, fc_eof_vals, "0x%x"));
1304
1305     fcsof_tree = proto_item_add_subtree(it, ett_fcsof);
1306
1307     proto_tree_add_uint(fcsof_tree, hf_fcsof, tvb, sof_offset, 4, sof);
1308
1309     if (crc == crc_computed) {
1310         proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1311                                        crc_offset, 4, crc,
1312                                        "%8.8x [valid]", crc);
1313     } else {
1314         it = proto_tree_add_uint_format_value(fcsof_tree, hf_fccrc, tvb,
1315                                        crc_offset, 4, crc,
1316                                        "%8.8x [error: should be %8.8x]",
1317                                        crc, crc_computed);
1318
1319         expert_add_info_format(pinfo, it, &ei_fccrc,
1320                                    "Bad FC CRC %8.8x %8.x",
1321                                    crc, crc_computed);
1322     }
1323
1324     proto_tree_add_uint(fcsof_tree, hf_fceof, tvb, eof_offset, 4, eof);
1325
1326     bytes_remaining = tvb_length_remaining(tvb, 4);
1327     next_tvb = tvb_new_subset(tvb, 4, bytes_remaining, -1);
1328
1329     fc_data.ethertype = 0;
1330     fc_data.sof_eof = 0;
1331     if (sof == FC_SOFI2 || sof == FC_SOFI3) {
1332         fc_data.sof_eof = FC_DATA_SOF_FIRST_FRAME;
1333     } else if (sof == FC_SOFF) {
1334         fc_data.sof_eof = FC_DATA_SOF_SOFF;
1335     }
1336
1337     if (eof == EOFT_POS || eof == EOFT_NEG) {
1338         fc_data.sof_eof |= FC_DATA_EOF_LAST_FRAME;
1339     } else if (eof == EOFDTI_NEG || eof == EOFDTI_POS) {
1340         fc_data.sof_eof |= FC_DATA_EOF_INVALID;
1341     }
1342
1343     /* Call FC dissector */
1344     call_dissector_with_data(fc_handle, next_tvb, pinfo, tree, &fc_data);
1345 }
1346
1347 /* Register the protocol with Wireshark */
1348
1349 /* this format is require because a script is used to build the C function
1350    that calls all the protocol registration.
1351 */
1352
1353 void
1354 proto_register_fc(void)
1355 {
1356
1357 /* Setup list of header fields  See Section 1.6.1 for details*/
1358     static hf_register_info hf[] = {
1359         { &hf_fc_rctl,
1360           { "R_CTL", "fc.r_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1361             NULL, HFILL }},
1362         { &hf_fc_ftype,
1363           {"Frame type", "fc.ftype", FT_UINT8, BASE_HEX, VALS(fc_ftype_vals),
1364            0x0, "Derived Type", HFILL}},
1365         { &hf_fc_did,
1366           { "Dest Addr", "fc.d_id", FT_STRING, BASE_NONE, NULL, 0x0,
1367             "Destination Address", HFILL}},
1368         { &hf_fc_csctl,
1369           {"CS_CTL", "fc.cs_ctl", FT_UINT8, BASE_HEX, NULL, 0x0,
1370            NULL, HFILL}},
1371         { &hf_fc_sid,
1372           {"Src Addr", "fc.s_id", FT_STRING, BASE_NONE, NULL, 0x0,
1373            "Source Address", HFILL}},
1374         { &hf_fc_id,
1375           {"Addr", "fc.id", FT_STRING, BASE_NONE, NULL, 0x0,
1376            "Source or Destination Address", HFILL}},
1377         { &hf_fc_type,
1378           {"Type", "fc.type", FT_UINT8, BASE_HEX, VALS (fc_fc4_val), 0x0,
1379            NULL, HFILL}},
1380         { &hf_fc_fctl,
1381           {"F_CTL", "fc.f_ctl", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1382         { &hf_fc_seqid,
1383           {"SEQ_ID", "fc.seq_id", FT_UINT8, BASE_HEX, NULL, 0x0,
1384            "Sequence ID", HFILL}},
1385         { &hf_fc_dfctl,
1386           {"DF_CTL", "fc.df_ctl", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1387         { &hf_fc_seqcnt,
1388           {"SEQ_CNT", "fc.seq_cnt", FT_UINT16, BASE_DEC, NULL, 0x0,
1389            "Sequence Count", HFILL}},
1390         { &hf_fc_oxid,
1391           {"OX_ID", "fc.ox_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Originator ID",
1392            HFILL}},
1393         { &hf_fc_rxid,
1394           {"RX_ID", "fc.rx_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Receiver ID",
1395            HFILL}},
1396         { &hf_fc_param,
1397           {"Parameter", "fc.parameter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL,
1398            HFILL}},
1399
1400         { &hf_fc_reassembled,
1401           {"Reassembled Frame", "fc.reassembled", FT_BOOLEAN, BASE_NONE, NULL,
1402            0x0, NULL, HFILL}},
1403         { &hf_fc_nh_da,
1404           {"Network DA", "fc.nethdr.da", FT_STRING, BASE_NONE, NULL,
1405            0x0, NULL, HFILL}},
1406         { &hf_fc_nh_sa,
1407           {"Network SA", "fc.nethdr.sa", FT_STRING, BASE_NONE, NULL,
1408            0x0, NULL, HFILL}},
1409
1410         /* Basic Link Svc field definitions */
1411         { &hf_fc_bls_seqid_vld,
1412           {"SEQID Valid", "fc.bls_seqidvld", FT_UINT8, BASE_HEX,
1413            VALS (fc_bls_seqid_val), 0x0, NULL, HFILL}},
1414         { &hf_fc_bls_lastvld_seqid,
1415           {"Last Valid SEQID", "fc.bls_lastseqid", FT_UINT8, BASE_HEX, NULL,
1416            0x0, NULL, HFILL}},
1417         { &hf_fc_bls_oxid,
1418           {"OXID", "fc.bls_oxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1419         { &hf_fc_bls_rxid,
1420           {"RXID", "fc.bls_rxid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1421         { &hf_fc_bls_lowseqcnt,
1422           {"Low SEQCNT", "fc.bls_lseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1423            HFILL}},
1424         { &hf_fc_bls_hiseqcnt,
1425           {"High SEQCNT", "fc.bls_hseqcnt", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1426            HFILL}},
1427         { &hf_fc_bls_rjtcode,
1428           {"Reason", "fc.bls_reason", FT_UINT8, BASE_HEX, VALS(fc_bls_barjt_val),
1429            0x0, NULL, HFILL}},
1430         { &hf_fc_bls_rjtdetail,
1431           {"Reason Explanation", "fc.bls_rjtdetail", FT_UINT8, BASE_HEX,
1432            VALS (fc_bls_barjt_det_val), 0x0, NULL, HFILL}},
1433         { &hf_fc_bls_vendor,
1434           {"Vendor Unique Reason", "fc.bls_vnduniq", FT_UINT8, BASE_HEX, NULL,
1435            0x0, NULL, HFILL}},
1436         { &hf_fc_fctl_exchange_responder,
1437           {"ExgRpd", "fc.fctl.exchange_responder", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_responder),
1438            FC_FCTL_EXCHANGE_RESPONDER, "Exchange Responder?", HFILL}},
1439         { &hf_fc_fctl_seq_recipient,
1440           {"SeqRec", "fc.fctl.seq_recipient", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_recipient),
1441            FC_FCTL_SEQ_RECIPIENT, "Seq Recipient?", HFILL}},
1442         { &hf_fc_fctl_exchange_first,
1443           {"ExgFst", "fc.fctl.exchange_first", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_first),
1444            FC_FCTL_EXCHANGE_FIRST, "First Exchange?", HFILL}},
1445         { &hf_fc_fctl_exchange_last,
1446           {"ExgLst", "fc.fctl.exchange_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_exchange_last),
1447            FC_FCTL_EXCHANGE_LAST, "Last Exchange?", HFILL}},
1448         { &hf_fc_fctl_seq_last,
1449           {"SeqLst", "fc.fctl.seq_last", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_seq_last),
1450            FC_FCTL_SEQ_LAST, "Last Sequence?", HFILL}},
1451         { &hf_fc_fctl_priority,
1452           {"Pri", "fc.fctl.priority", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_priority),
1453            FC_FCTL_PRIORITY, "Priority", HFILL}},
1454         { &hf_fc_fctl_transfer_seq_initiative,
1455           {"TSI", "fc.fctl.transfer_seq_initiative", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_transfer_seq_initiative),
1456            FC_FCTL_TRANSFER_SEQ_INITIATIVE, "Transfer Seq Initiative", HFILL}},
1457         { &hf_fc_fctl_rexmitted_seq,
1458           {"RetSeq", "fc.fctl.rexmitted_seq", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rexmitted_seq),
1459            FC_FCTL_REXMITTED_SEQ, "Retransmitted Sequence", HFILL}},
1460         { &hf_fc_fctl_rel_offset,
1461           {"RelOff", "fc.fctl.rel_offset", FT_BOOLEAN, 24, TFS(&tfs_fc_fctl_rel_offset),
1462            FC_FCTL_REL_OFFSET, "rel offset", HFILL}},
1463         { &hf_fc_fctl_last_data_frame,
1464           {"LDF", "fc.fctl.last_data_frame", FT_UINT24, BASE_HEX, VALS(last_data_frame_vals),
1465            FC_FCTL_LAST_DATA_FRAME_MASK, "Last Data Frame?", HFILL}},
1466         { &hf_fc_fctl_ack_0_1,
1467           {"A01", "fc.fctl.ack_0_1", FT_UINT24, BASE_HEX, VALS(ack_0_1_vals),
1468            FC_FCTL_ACK_0_1_MASK, "Ack 0/1 value", HFILL}},
1469         { &hf_fc_fctl_abts_ack,
1470           {"AA", "fc.fctl.abts_ack", FT_UINT24, BASE_HEX, VALS(abts_ack_vals),
1471            FC_FCTL_ABTS_MASK, "ABTS ACK values", HFILL}},
1472 #if 0
1473         { &hf_fc_fctl_abts_not_ack,
1474           {"AnA", "fc.fctl.abts_not_ack", FT_UINT24, BASE_HEX, VALS(abts_not_ack_vals),
1475            FC_FCTL_ABTS_MASK, "ABTS not ACK vals", HFILL}},
1476 #endif
1477         { &hf_fc_exchange_first_frame,
1478           { "Exchange First In", "fc.exchange_first_frame", FT_FRAMENUM, BASE_NONE, NULL,
1479            0, "The first frame of this exchange is in this frame", HFILL }},
1480         { &hf_fc_exchange_last_frame,
1481           { "Exchange Last In", "fc.exchange_last_frame", FT_FRAMENUM, BASE_NONE, NULL,
1482            0, "The last frame of this exchange is in this frame", HFILL }},
1483         { &hf_fc_time,
1484           { "Time from Exchange First", "fc.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
1485            0, "Time since the first frame of the Exchange", HFILL }},
1486         { &hf_fc_relative_offset,
1487           {"Relative Offset", "fc.relative_offset", FT_UINT32, BASE_DEC, NULL,
1488            0, "Relative offset of data", HFILL}},
1489         { &hf_fc_vft,
1490           {"VFT Header", "fc.vft", FT_UINT16, BASE_DEC, NULL,
1491            0, NULL, HFILL}},
1492         { &hf_fc_vft_rctl,
1493           {"R_CTL", "fc.vft.rctl", FT_UINT8, BASE_HEX, NULL,
1494            0, NULL, HFILL}},
1495         { &hf_fc_vft_ver,
1496           {"Version", "fc.vft.ver", FT_UINT8, BASE_DEC, NULL,
1497            0, "Version of VFT header", HFILL}},
1498         { &hf_fc_vft_type,
1499           {"Type", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1500            0, "Type of tagged frame", HFILL}},
1501         { &hf_fc_vft_pri,
1502           {"Priority", "fc.vft.type", FT_UINT8, BASE_DEC, NULL,
1503            0, "QoS Priority", HFILL}},
1504         { &hf_fc_vft_vf_id,
1505           {"VF_ID", "fc.vft.vf_id", FT_UINT16, BASE_DEC, NULL,
1506            0, "Virtual Fabric ID", HFILL}},
1507         { &hf_fc_vft_hop_ct,
1508           {"HopCT", "fc.vft.hop_ct", FT_UINT8, BASE_DEC, NULL,
1509            0, "Hop Count", HFILL}},
1510     };
1511
1512     /* Setup protocol subtree array */
1513     static gint *ett[] = {
1514         &ett_fc,
1515         &ett_fcbls,
1516         &ett_fc_vft,
1517         &ett_fctl
1518     };
1519
1520     static ei_register_info ei[] = {
1521         { &ei_fccrc, { "fc.crc.bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1522     };
1523
1524     module_t *fc_module;
1525     expert_module_t* expert_fc;
1526
1527     /* FC SOF */
1528
1529     static hf_register_info sof_hf[] = {
1530         { &hf_fcsof,
1531           { "SOF", "fc.sof", FT_UINT32, BASE_HEX, VALS(fc_sof_vals), 0,
1532             NULL, HFILL }},
1533         { &hf_fceof,
1534           { "EOF", "fc.eof", FT_UINT32, BASE_HEX, VALS(fc_eof_vals), 0,
1535             NULL, HFILL }},
1536         { &hf_fccrc,
1537           { "CRC", "fc.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
1538     };
1539
1540     static gint *sof_ett[] = {
1541         &ett_fcsof,
1542         &ett_fceof,
1543         &ett_fccrc
1544     };
1545
1546
1547     /* Register the protocol name and description */
1548     proto_fc = proto_register_protocol ("Fibre Channel", "FC", "fc");
1549     fc_handle = new_register_dissector ("fc", dissect_fc, proto_fc);
1550     new_register_dissector ("fc_ifcp", dissect_fc_ifcp, proto_fc);
1551     fc_tap = register_tap("fc");
1552
1553     /* Required function calls to register the header fields and subtrees used */
1554     proto_register_field_array(proto_fc, hf, array_length(hf));
1555     proto_register_subtree_array(ett, array_length(ett));
1556     expert_fc = expert_register_protocol(proto_fc);
1557     expert_register_field_array(expert_fc, ei, array_length(ei));
1558
1559     /* subdissectors called through this table will find the fchdr structure
1560      * through data parameter of dissector
1561      */
1562     fcftype_dissector_table = register_dissector_table ("fc.ftype",
1563                                                         "FC Frame Type",
1564                                                         FT_UINT8, BASE_HEX);
1565
1566     /* Register preferences */
1567     fc_module = prefs_register_protocol (proto_fc, NULL);
1568     prefs_register_bool_preference (fc_module,
1569                                     "reassemble",
1570                                     "Reassemble multi-frame sequences",
1571                                     "If enabled, reassembly of multi-frame "
1572                                     "sequences is done",
1573                                     &fc_reassemble);
1574     prefs_register_uint_preference (fc_module,
1575                                     "max_frame_size", "Max FC Frame Size",
1576                                     "This is the size of non-last frames in a "
1577                                     "multi-frame sequence", 10,
1578                                     &fc_max_frame_size);
1579
1580     register_init_routine (fc_exchange_init_protocol);
1581
1582
1583     /* Register FC SOF/EOF */
1584     proto_fcsof = proto_register_protocol("Fibre Channel Delimiters", "FCSoF", "fcsof");
1585
1586     proto_register_field_array(proto_fcsof, sof_hf, array_length(sof_hf));
1587     proto_register_subtree_array(sof_ett, array_length(sof_ett));
1588
1589     fcsof_handle = register_dissector("fcsof", dissect_fcsof, proto_fcsof);
1590 }
1591
1592
1593 /* If this dissector uses sub-dissector registration add a registration routine.
1594    This format is required because a script is used to find these routines and
1595    create the code that calls these routines.
1596 */
1597 void
1598 proto_reg_handoff_fc (void)
1599 {
1600     dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2, fc_handle);
1601
1602     dissector_add_uint("wtap_encap", WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS, fcsof_handle);
1603
1604     data_handle = find_dissector("data");
1605 }