Coverage Report

Created: 2025-12-27 06:52

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