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