Coverage Report

Created: 2026-05-14 06:28

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