1 /*
2  * packet-fip.c
3  * Routines for FIP dissection - FCoE Initialization Protocol
4  * Copyright (c) 2008 Cisco Systems, Inc. (jeykholt@cisco.com)
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Based on packet-fcoe.c, Copyright 2006, Nuova Systems, (jre@nuovasystems.com)
11  * Based on packet-fcp.c, Copyright 2001, Dinesh G Dutt (ddutt@cisco.com)
12  *
13  * SPDX-License-Identifier: GPL-2.0-or-later
14  */
15 
16 /*
17  * For FIP protocol details, see http://t11.org.
18  * This version uses preliminary details not yet standardized.
19  * Based on http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
20  * and      http://www.t11.org/ftp/t11/pub/fc/bb-5/08-545v1.pdf
21  */
22 
23 #include "config.h"
24 
25 #include <epan/packet.h>
26 #include <epan/to_str.h>
27 #include <epan/expert.h>
28 #include "packet-fc.h"
29 
30 void proto_register_fip(void);
31 void proto_reg_handoff_fip(void);
32 
33 /*
34  * FIP protocol information.
35  */
36 #define FIP_HEADER_LEN  10
37 #define FIP_BPW          4          /* bytes per descriptor length unit */
38 
39 /*
40  * FIP opcodes and subcodes.
41  */
42 enum fip_opcode {
43     FIP_OP_DISC  = 1,               /* discovery, advertisement, etc. */
44     FIP_OP_LS    = 2,               /* Link Service request or reply */
45     FIP_OP_CTRL  = 3,               /* control */
46     FIP_OP_VLAN  = 4,               /* VLAN request or reply */
47     FIP_OP_VN2VN = 5                /* VN_port to VN_port operation */
48 };
49 
50 /*
51  * Subcodes for FIP_OP_DISC.
52  */
53 enum fip_disc_subcode {
54     FIP_SC_SOL =    1,              /* solicitation */
55     FIP_SC_ADV =    2               /* advertisement */
56 };
57 
58 /*
59  * Subcodes for FIP_OP_LS.
60  */
61 enum fip_ls_subcode {
62     FIP_SC_REQ =    1,              /* request */
63     FIP_SC_REP =    2               /* reply */
64 };
65 
66 enum fip_ctrl_subcode {
67     FIP_SC_KA =     1,              /* keep-alive */
68     FIP_SC_CVL =    2               /* clear virtual link */
69 };
70 
71 enum fip_vlan_subcode {
72     FIP_VL_REQ =    1,              /* request */
73     FIP_VL_REP =    2               /* reply */
74 };
75 
76 /*
77  * Subcodes for FIP_OP_VN2VN.
78  * XXX proposal
79  */
80 enum fip_vn2vn_subcode {
81     FIP_SC_VN_PROBE_REQ    = 1,     /* probe request */
82     FIP_SC_VN_PROBE_REP    = 2,     /* probe reply */
83     FIP_SC_VN_CLAIM_NOTIFY = 3,     /* claim notification */
84     FIP_SC_VN_CLAIM_REP    = 4,     /* claim response */
85     FIP_SC_VN_BEACON       = 5      /* beacon */
86 };
87 
88 static const value_string fip_opcodes[] = {
89     { FIP_OP_DISC,      "Discovery" },
90     { FIP_OP_LS,        "Link Service" },
91     { FIP_OP_CTRL,      "Control" },
92     { FIP_OP_VLAN,      "VLAN" },
93     { FIP_OP_VN2VN,     "VN2VN" },
94     { 0,    NULL }
95 };
96 
97 static const value_string fip_disc_subcodes[] = {
98     { FIP_SC_SOL,       "Solicitation" },
99     { FIP_SC_ADV,       "Advertisement" },
100     { 0,    NULL }
101 };
102 
103 static const value_string fip_ls_subcodes[] = {
104     { FIP_SC_REQ,       "ELS Request" },
105     { FIP_SC_REP,       "ELS Response" },
106     { 0,    NULL }
107 };
108 
109 static const value_string fip_ctrl_subcodes[] = {
110     { FIP_SC_KA,        "Keep-Alive" },
111     { FIP_SC_CVL,       "Clear Virtual Link" },
112     { 0,    NULL }
113 };
114 
115 static const value_string fip_vlan_subcodes[] = {
116     { FIP_VL_REQ,       "VLAN Request" },
117     { FIP_VL_REP,       "VLAN Response" },
118     { 0,    NULL }
119 };
120 
121 static const value_string fip_vn2vn_subcodes[] = {
122     { FIP_SC_VN_PROBE_REQ,    "Probe Request" },
123     { FIP_SC_VN_PROBE_REP,    "Probe Reply" },
124     { FIP_SC_VN_CLAIM_NOTIFY, "Claim Notification" },
125     { FIP_SC_VN_CLAIM_REP,    "Claim Response" },
126     { FIP_SC_VN_BEACON,       "Beacon" },
127     { 0,    NULL }
128 };
129 
130 /*
131  * Descriptor types.
132  */
133 enum fip_desc_type {
134     FIP_DT_PRI       =  1, /* priority for forwarder selection */
135     FIP_DT_MAC       =  2, /* MAC address */
136     FIP_DT_MAP_OUI   =  3, /* FC-MAP OUI */
137     FIP_DT_NAME      =  4, /* switch name or node name */
138     FIP_DT_FAB       =  5, /* fabric descriptor */
139     FIP_DT_FCOE_SIZE =  6, /* max FCoE frame size */
140     FIP_DT_FLOGI     =  7, /* FLOGI request or response */
141     FIP_DT_FDISC     =  8, /* FDISC request or response */
142     FIP_DT_LOGO      =  9, /* LOGO request or response */
143     FIP_DT_ELP       = 10, /* ELP request or response */
144     FIP_DT_VN        = 11, /* VN_Port Info */
145     FIP_DT_FKA       = 12, /* FIP keep-alive / advert. period */
146     FIP_DT_VEND      = 13, /* Vendor-specific TLV */
147     FIP_DT_VLAN      = 14, /* VLAN number */
148     FIP_DT_FC4F      = 15  /* FC-4 features */
149 };
150 
151 static const value_string fip_desc_types[] = {
152     { FIP_DT_PRI,       "Priority" },
153     { FIP_DT_MAC,       "MAC Address" },
154     { FIP_DT_MAP_OUI,   "FPMA MAP OUI" },
155     { FIP_DT_NAME,      "Switch or Node Name" },
156     { FIP_DT_FAB,       "Fabric Descriptor" },
157     { FIP_DT_FCOE_SIZE, "Max FCoE frame size" },
158     { FIP_DT_FLOGI,     "FLOGI Encapsulation" },
159     { FIP_DT_FDISC,     "FDISC Encapsulation" },
160     { FIP_DT_LOGO,      "LOGO Encapsulation" },
161     { FIP_DT_ELP,       "ELP Encapsulation" },
162     { FIP_DT_VN,        "VN_Port Info" },
163     { FIP_DT_FKA,       "FKA_ADV_Period" },
164     { FIP_DT_VEND,      "Vendor_ID" },
165     { FIP_DT_VLAN,      "VLAN" },
166     { FIP_DT_FC4F,      "FC-4 features" },
167     { 0,    NULL }
168 };
169 static value_string_ext fip_desc_types_ext = VALUE_STRING_EXT_INIT(fip_desc_types);
170 
171 /*
172  * flags in header fip_flags.
173  */
174 enum fip_flag {
175     FIP_FL_FPMA    = 0x8000,         /* supports FPMA fabric-provided MACs */
176     FIP_FL_SPMA    = 0x4000,         /* supports SPMA server-provided MACs */
177     FIP_FL_REC_P2P = 0x0008,         /* recorded addr or point-to-point */
178     FIP_FL_AVAIL   = 0x0004,         /* available for FLOGI */
179     FIP_FL_SOL     = 0x0002,         /* this is a solicited message */
180     FIP_FL_FPORT   = 0x0001          /* sent from an F port */
181 };
182 
183 static int proto_fip            = -1;
184 static int hf_fip_ver           = -1;
185 static int hf_fip_reserved12    = -1;
186 static int hf_fip_op            = -1;
187 static int hf_fip_reserved8     = -1;
188 static int hf_fip_disc_subcode  = -1;
189 static int hf_fip_ls_subcode    = -1;
190 static int hf_fip_ctrl_subcode  = -1;
191 static int hf_fip_vlan_subcode  = -1;
192 static int hf_fip_vn2vn_subcode = -1;
193 static int hf_fip_hex_subcode   = -1;
194 static int hf_fip_dlen          = -1;
195 static int hf_fip_flags         = -1;
196 static int hf_fip_flag_fpma     = -1;
197 static int hf_fip_flag_spma     = -1;
198 static int hf_fip_flag_rec_p2p  = -1;
199 static int hf_fip_flag_avail    = -1;
200 static int hf_fip_flag_sol      = -1;
201 static int hf_fip_flag_fport    = -1;
202 static int hf_fip_descriptors   = -1;
203 
204 static int * const hf_fip_flags_fields[] = {
205     &hf_fip_flag_fpma,
206     &hf_fip_flag_spma,
207     &hf_fip_flag_rec_p2p,
208     &hf_fip_flag_avail,
209     &hf_fip_flag_sol,
210     &hf_fip_flag_fport,
211     NULL
212 };
213 
214 static int hf_fip_desc_type       = -1;
215 static int hf_fip_desc_len        = -1;
216 static int hf_fip_desc_pri        = -1;
217 static int hf_fip_desc_mac        = -1;
218 static int hf_fip_desc_map        = -1;
219 static int hf_fip_desc_name       = -1;
220 static int hf_fip_desc_fab_vfid   = -1;
221 static int hf_fip_desc_fab_map    = -1;
222 static int hf_fip_desc_fab_name   = -1;
223 static int hf_fip_desc_fcoe_size  = -1;
224 static int hf_fip_desc_vn_mac     = -1;
225 static int hf_fip_desc_vn_fid     = -1;
226 static int hf_fip_desc_vn_wwpn    = -1;
227 static int hf_fip_desc_fka        = -1;
228 static int hf_fip_desc_vend       = -1;
229 static int hf_fip_desc_vend_data  = -1;
230 static int hf_fip_desc_vlan       = -1;
231 static int hf_fip_desc_unk        = -1;
232 static int hf_fip_desc_fc4f_types = -1;
233 static int hf_fip_desc_fcp_feat   = -1;
234 static int hf_fip_type_ip         = -1;
235 static int hf_fip_type_fcp        = -1;
236 static int hf_fip_type_gs3        = -1;
237 static int hf_fip_fcp_feat_i      = -1;
238 static int hf_fip_fcp_feat_t      = -1;
239 
240 static int ett_fip                = -1;
241 static int ett_fip_flags          = -1;
242 static int ett_fip_dt_pri         = -1;
243 static int ett_fip_dt_mac         = -1;
244 static int ett_fip_dt_map         = -1;
245 static int ett_fip_dt_name        = -1;
246 static int ett_fip_dt_fab         = -1;
247 static int ett_fip_dt_mdl         = -1;
248 static int ett_fip_dt_caps        = -1;
249 static int ett_fip_dt_vn          = -1;
250 static int ett_fip_dt_fka         = -1;
251 static int ett_fip_dt_vend        = -1;
252 static int ett_fip_dt_vlan        = -1;
253 static int ett_fip_dt_unk         = -1;
254 static int ett_fip_dt_fc4f        = -1;
255 static int ett_fip_dt_fc4f_types  = -1;
256 static int ett_fip_dt_fcp_feat    = -1;
257 
258 static expert_field ei_fip_descriptors = EI_INIT;
259 
260 static dissector_handle_t fc_handle;
261 
262 /*
263  * Insert common descriptor type and length fields.
264  */
265 static proto_tree*
fip_desc_type_len(proto_tree * tree,tvbuff_t * tvb,guint8 dtype,int ett,proto_item ** item)266 fip_desc_type_len(proto_tree *tree, tvbuff_t *tvb, guint8 dtype, int ett, proto_item** item)
267 {
268     proto_tree* ret_tree;
269 
270     ret_tree = proto_tree_add_subtree_format(tree, tvb, 0, -1, ett, item,
271             "Descriptor: %s ", val_to_str_ext_const(dtype, &fip_desc_types_ext, "Unknown 0x%x"));
272     proto_tree_add_item(ret_tree, hf_fip_desc_type, tvb, 0, 1, ENC_BIG_ENDIAN);
273     proto_tree_add_item(ret_tree, hf_fip_desc_len, tvb, 1, 1, ENC_BIG_ENDIAN);
274 
275     return ret_tree;
276 }
277 
278 /*
279  * Dissect the FC-4 type features descriptor.
280  */
281 static void
fip_desc_fc4f(tvbuff_t * tvb,proto_tree * tree,proto_item * item)282 fip_desc_fc4f(tvbuff_t *tvb, proto_tree *tree, proto_item *item)
283 {
284     guint mask;
285     guint offset;
286 
287     static int * const types_word0[] = { /* types 0 - 31 */
288         &hf_fip_type_ip,
289         &hf_fip_type_fcp,
290         NULL
291     };
292     static int * const types_word1[] = { /* types 32 - 63 */
293         &hf_fip_type_gs3,
294         NULL
295     };
296     static int * const fcp_feat[] = {
297         &hf_fip_fcp_feat_t,
298         &hf_fip_fcp_feat_i,
299         NULL
300     };
301 
302     /*
303      * First the 256-bit bitmask of types supported.
304      */
305     offset = 4;
306     proto_tree_add_bitmask(tree, tvb, offset, hf_fip_desc_fc4f_types,
307             ett_fip_dt_fc4f_types, types_word0, ENC_BIG_ENDIAN);
308     offset += 4;
309     proto_tree_add_bitmask(tree, tvb, offset, hf_fip_desc_fc4f_types,
310             ett_fip_dt_fc4f_types, types_word1, ENC_BIG_ENDIAN);
311     offset += 256 / 8 - 4;   /* skip to end of bitmask (32 bytes) */
312 
313     /*
314      * Next the 4-bit capabilities per type.
315      * Only decode FCP (type 8) for now.
316      */
317     offset += 8 / 2;        /* skip first 8 types, 2 types per byte */
318     proto_tree_add_bitmask(tree, tvb, offset, hf_fip_desc_fcp_feat,
319             ett_fip_dt_fcp_feat, fcp_feat, ENC_BIG_ENDIAN);
320     mask = tvb_get_ntohl(tvb, offset);
321     if (mask & 1) {
322         proto_item_append_text(item, "FCP Target ");
323     }
324     if (mask & 2) {
325         proto_item_append_text(item, "FCP Initiator ");
326     }
327 }
328 
329 static int
dissect_fip(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)330 dissect_fip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
331 {
332     guint       op;
333     guint       sub;
334     guint       rlen;
335     proto_item *ti;
336     proto_item *item;
337     proto_tree *fip_tree;
338     proto_tree *subtree;
339     guint       dtype;
340     guint       dlen;
341     guint       desc_offset;
342     guint       val;
343     tvbuff_t   *desc_tvb;
344     const char *info;
345 
346     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIP");
347     col_clear(pinfo->cinfo, COL_INFO);
348 
349     if (!tvb_bytes_exist(tvb, 0, FIP_HEADER_LEN)) {
350         col_set_str(pinfo->cinfo, COL_INFO, "[packet too short]");
351         proto_tree_add_protocol_format(tree, proto_fip, tvb, 0,
352                                             -1, "FIP [packet too short]");
353         return tvb_captured_length(tvb);
354     }
355 
356     op  = tvb_get_ntohs(tvb, 2);
357     sub = tvb_get_guint8(tvb, 5);
358 
359     switch (op) {
360     case FIP_OP_DISC:
361         info = val_to_str(sub, fip_disc_subcodes, "Discovery 0x%x");
362         break;
363     case FIP_OP_LS:
364         info = val_to_str(sub, fip_ls_subcodes, "Link Service 0x%x");
365         break;
366     case FIP_OP_CTRL:
367         info = val_to_str(sub, fip_ctrl_subcodes, "Control 0x%x");
368         break;
369     case FIP_OP_VLAN:
370         info = val_to_str(sub, fip_vlan_subcodes, "VLAN 0x%x");
371         break;
372     case FIP_OP_VN2VN:
373         info = val_to_str(sub, fip_vn2vn_subcodes, "VN2VN 0x%x");
374         break;
375     default:
376         info = val_to_str(op, fip_opcodes, "Unknown op 0x%x");
377         break;
378     }
379 
380     col_add_str(pinfo->cinfo, COL_INFO, info);
381 
382     rlen = tvb_get_ntohs(tvb, 6);
383 
384     ti = proto_tree_add_protocol_format(tree, proto_fip, tvb, 0,
385                                         FIP_HEADER_LEN + rlen * FIP_BPW,
386                                         "FIP %s", info);
387     fip_tree = proto_item_add_subtree(ti, ett_fip);
388     proto_tree_add_item(fip_tree, hf_fip_ver, tvb, 0, 1, ENC_BIG_ENDIAN);
389     proto_tree_add_item(fip_tree, hf_fip_reserved12, tvb, 0, 2, ENC_BIG_ENDIAN);
390     proto_tree_add_item(fip_tree, hf_fip_op, tvb, 2, 2, ENC_BIG_ENDIAN);
391     proto_tree_add_item(fip_tree, hf_fip_reserved8, tvb, 4, 1, ENC_NA);
392     switch (op) {
393     case FIP_OP_DISC:
394         proto_tree_add_item(fip_tree, hf_fip_disc_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
395         break;
396     case FIP_OP_LS:
397         proto_tree_add_item(fip_tree, hf_fip_ls_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
398         break;
399     case FIP_OP_CTRL:
400         proto_tree_add_item(fip_tree, hf_fip_ctrl_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
401         break;
402     case FIP_OP_VLAN:
403         proto_tree_add_item(fip_tree, hf_fip_vlan_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
404         break;
405     case FIP_OP_VN2VN:
406         proto_tree_add_item(fip_tree, hf_fip_vn2vn_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
407         break;
408     default:
409         proto_tree_add_item(fip_tree, hf_fip_hex_subcode, tvb, 5, 1, ENC_BIG_ENDIAN);
410         break;
411     }
412     proto_tree_add_item(fip_tree, hf_fip_dlen, tvb, 6, 2, ENC_BIG_ENDIAN);
413 
414     proto_tree_add_bitmask(fip_tree, tvb, 8, hf_fip_flags,
415             ett_fip_flags, hf_fip_flags_fields, ENC_BIG_ENDIAN);
416 
417     desc_offset = FIP_HEADER_LEN;
418     rlen *= FIP_BPW;
419     proto_tree_add_bytes_format(fip_tree, hf_fip_descriptors, tvb, desc_offset, rlen, NULL, "Descriptors");
420 
421     while ((rlen > 0) && tvb_bytes_exist(tvb, desc_offset, 2)) {
422         dlen = tvb_get_guint8(tvb, desc_offset + 1) * FIP_BPW;
423         if (!dlen) {
424             proto_tree_add_expert(fip_tree, pinfo, &ei_fip_descriptors, tvb, desc_offset, -1);
425             break;
426         }
427         if (!tvb_bytes_exist(tvb, desc_offset, dlen) || dlen > rlen) {
428             break;
429         }
430         desc_tvb = tvb_new_subset_length_caplen(tvb, desc_offset, dlen, -1);
431         dtype = tvb_get_guint8(desc_tvb, 0);
432         desc_offset += dlen;
433         rlen -= dlen;
434 
435         switch (dtype) {
436         case FIP_DT_PRI:
437             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_pri, &item);
438             proto_tree_add_item(subtree, hf_fip_desc_pri, desc_tvb,
439                     3, 1, ENC_BIG_ENDIAN);
440             proto_item_append_text(item, "%u", tvb_get_guint8(desc_tvb, 3));
441             break;
442         case FIP_DT_MAC:
443             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_mac, &item);
444             proto_tree_add_item(subtree, hf_fip_desc_mac, desc_tvb,
445                     2, 6, ENC_NA);
446             proto_item_append_text(item, "%s",
447                     tvb_bytes_to_str_punct(pinfo->pool, desc_tvb, 2, 6, ':'));
448             break;
449         case FIP_DT_MAP_OUI:
450             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_map, &item);
451             proto_tree_add_item(subtree, hf_fip_desc_map, desc_tvb,
452                     5, 3, ENC_NA);
453             proto_item_append_text(item, "%s", tvb_fc_to_str(pinfo->pool, desc_tvb, 5));
454             break;
455         case FIP_DT_NAME:
456             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_name, &item);
457             proto_tree_add_item(subtree, hf_fip_desc_name, desc_tvb, 4, 8, ENC_NA);
458             proto_item_append_text(item, "%s", tvb_fcwwn_to_str(pinfo->pool, desc_tvb, 4));
459             break;
460         case FIP_DT_FAB:
461             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fab, &item);
462             proto_tree_add_item(subtree, hf_fip_desc_fab_vfid, desc_tvb,
463                     2, 2, ENC_BIG_ENDIAN);
464             proto_tree_add_item(subtree, hf_fip_desc_fab_map, desc_tvb,
465                     5, 3, ENC_NA);
466             proto_tree_add_item(subtree, hf_fip_desc_fab_name, desc_tvb, 8, 8, ENC_NA);
467             proto_item_append_text(item, "%s", tvb_fcwwn_to_str(pinfo->pool, desc_tvb, 8));
468             break;
469         case FIP_DT_FCOE_SIZE:
470             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_mdl, &item);
471             proto_tree_add_item(subtree, hf_fip_desc_fcoe_size, desc_tvb,
472                     2, 2, ENC_BIG_ENDIAN);
473             proto_item_append_text(item, "%u", tvb_get_ntohs(desc_tvb, 2));
474             break;
475         case FIP_DT_FLOGI:
476         case FIP_DT_FDISC:
477         case FIP_DT_LOGO:
478         case FIP_DT_ELP: {
479             tvbuff_t *ls_tvb;
480             fc_data_t fc_data = {ETHERTYPE_FIP, 0};
481 
482             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_caps, &item);
483             ls_tvb = tvb_new_subset_length_caplen(desc_tvb, 4, dlen - 4, -1);
484             call_dissector_with_data(fc_handle, ls_tvb, pinfo, subtree, &fc_data);
485             proto_item_append_text(item, "%u bytes", dlen - 4);
486         }
487             break;
488         case FIP_DT_VN:
489             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vn, &item);
490             proto_tree_add_item(subtree, hf_fip_desc_vn_mac, desc_tvb,
491                     2, 6, ENC_NA);
492             proto_tree_add_item(subtree, hf_fip_desc_vn_fid, desc_tvb,
493                     9, 3, ENC_BIG_ENDIAN);
494             proto_tree_add_item(subtree, hf_fip_desc_vn_wwpn,
495                     desc_tvb, 12, 8, ENC_NA);
496             proto_item_append_text(item, "MAC %s  FC_ID %6.6x",
497                     tvb_bytes_to_str_punct(pinfo->pool, desc_tvb, 2, 6, ':'),
498                     tvb_get_ntoh24(desc_tvb, 9));
499             break;
500         case FIP_DT_FKA:
501             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fka, &item);
502             val = tvb_get_ntohl(desc_tvb, 4);
503             proto_tree_add_uint_format_value(subtree, hf_fip_desc_fka,
504                     desc_tvb, 4, 4, val, "%u ms", val);
505             proto_item_append_text(item, "%u ms", val);
506             break;
507         case FIP_DT_VEND:
508             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vend, &item);
509             proto_tree_add_item(subtree, hf_fip_desc_vend, desc_tvb,
510                     4, 8, ENC_NA);
511             if (tvb_reported_length_remaining(desc_tvb, 9)) {
512                 proto_tree_add_item(subtree, hf_fip_desc_vend_data,
513                      desc_tvb, 9, -1, ENC_NA);
514             }
515             break;
516         case FIP_DT_VLAN:
517             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vlan, &item);
518             proto_tree_add_item(subtree, hf_fip_desc_vlan, desc_tvb,
519                     2, 2, ENC_BIG_ENDIAN);
520             proto_item_append_text(item, "%u", tvb_get_ntohs(desc_tvb, 2));
521             break;
522         case FIP_DT_FC4F:
523             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fc4f, &item);
524             fip_desc_fc4f(desc_tvb, subtree, item);
525             break;
526         default:
527             subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_unk, &item);
528             proto_tree_add_item(subtree, hf_fip_desc_unk, desc_tvb,
529                     2, -1, ENC_NA);
530             break;
531         }
532     }
533     return tvb_captured_length(tvb);
534 }
535 
536 void
proto_register_fip(void)537 proto_register_fip(void)
538 {
539     /* Setup list of header fields  See Section 1.6.1 for details*/
540     static hf_register_info hf[] = {
541         /*
542          * FIP header fields.
543          */
544         { &hf_fip_ver,
545           { "Version", "fip.ver",
546             FT_UINT8, BASE_DEC, NULL, 0xf0,
547             NULL, HFILL}},
548 
549         { &hf_fip_reserved12,
550           { "Reserved", "fip.reserved",
551             FT_UINT16, BASE_HEX, NULL, 0x0fff,
552             NULL, HFILL}},
553 
554         { &hf_fip_op,
555           { "Opcode", "fip.opcode",
556             FT_UINT16, BASE_HEX, VALS(fip_opcodes), 0,
557             NULL, HFILL}},
558 
559         { &hf_fip_reserved8,
560           { "Reserved", "fip.reserved",
561             FT_UINT8, BASE_HEX, NULL, 0x0,
562             NULL, HFILL}},
563 
564         { &hf_fip_disc_subcode,
565           { "Discovery Subcode", "fip.disc_subcode",
566             FT_UINT8, BASE_HEX, VALS(fip_disc_subcodes), 0,
567             NULL, HFILL}},
568 
569         { &hf_fip_ls_subcode,
570           { "Link Service Subcode", "fip.ls.subcode",
571             FT_UINT8, BASE_HEX, VALS(fip_ls_subcodes), 0,
572             NULL, HFILL}},
573 
574         { &hf_fip_ctrl_subcode,
575           { "Control Subcode", "fip.ctrl_subcode",
576             FT_UINT8, BASE_HEX, VALS(fip_ctrl_subcodes), 0,
577             NULL, HFILL}},
578 
579         { &hf_fip_vlan_subcode,
580           { "VLAN Subcode", "fip.vlan_subcode",
581             FT_UINT8, BASE_HEX, VALS(fip_vlan_subcodes), 0,
582             NULL, HFILL}},
583 
584         { &hf_fip_vn2vn_subcode,
585           { "VN2VN Subcode", "fip.vn2vn_subcode",
586             FT_UINT8, BASE_HEX, VALS(fip_vn2vn_subcodes), 0,
587             NULL, HFILL}},
588 
589         { &hf_fip_hex_subcode,
590           { "Unknown Subcode", "fip.subcode",
591             FT_UINT8, BASE_HEX, NULL, 0,
592             NULL, HFILL}},
593 
594         { &hf_fip_dlen,
595           { "Length of Descriptors (words)", "fip.dl_len",
596             FT_UINT16, BASE_DEC, NULL, 0,
597             NULL, HFILL}},
598 
599         { &hf_fip_flags,
600           { "Flags", "fip.flags",
601             FT_UINT16, BASE_HEX, NULL, 0,
602             NULL, HFILL}},
603 
604         { &hf_fip_flag_fpma,
605           { "Fabric Provided MAC addr", "fip.flags.fpma",
606             FT_BOOLEAN, 16, NULL, FIP_FL_FPMA,
607             NULL, HFILL}},
608 
609         { &hf_fip_flag_spma,
610           { "Server Provided MAC addr", "fip.flags.spma",
611             FT_BOOLEAN, 16, NULL, FIP_FL_SPMA,
612             NULL, HFILL}},
613 
614         { &hf_fip_flag_rec_p2p,
615           { "REC/P2P", "fip.flags.rec_p2p",
616             FT_BOOLEAN, 16, NULL, FIP_FL_REC_P2P,
617             NULL, HFILL}},
618 
619         { &hf_fip_flag_avail,
620           { "Available", "fip.flags.available",
621             FT_BOOLEAN, 16, NULL, FIP_FL_AVAIL,
622             NULL, HFILL}},
623 
624         { &hf_fip_flag_sol,
625           { "Solicited", "fip.flags.sol",
626             FT_BOOLEAN, 16, NULL, FIP_FL_SOL,
627             NULL, HFILL}},
628 
629         { &hf_fip_flag_fport,
630           { "F_Port", "fip.flags.fport",
631             FT_BOOLEAN, 16, NULL, FIP_FL_FPORT,
632             NULL, HFILL}},
633 
634         { &hf_fip_desc_type,
635           { "Descriptor Type", "fip.desc_type",
636             FT_UINT8, BASE_HEX | BASE_EXT_STRING, &fip_desc_types_ext, 0,
637             NULL, HFILL}},
638 
639         { &hf_fip_desc_len,
640           { "Descriptor Length (words)", "fip.desc_len",
641             FT_UINT8, BASE_DEC, NULL, 0,
642             NULL, HFILL}},
643 
644         /*
645          * Various descriptor fields.
646          */
647         { &hf_fip_desc_pri,
648           { "Priority", "fip.pri",
649             FT_UINT8, BASE_DEC, NULL, 0,
650             NULL, HFILL}},
651 
652         { &hf_fip_desc_mac,
653           { "MAC Address", "fip.mac",
654             FT_ETHER, BASE_NONE, NULL, 0,
655             NULL, HFILL}},
656 
657         { &hf_fip_desc_map,
658           { "FC-MAP-OUI", "fip.map",
659             FT_BYTES, SEP_DOT, NULL, 0,
660             NULL, HFILL}},
661 
662         { &hf_fip_desc_name,
663           { "Switch or Node Name", "fip.name",
664             FT_FCWWN, BASE_NONE, NULL, 0,
665             NULL, HFILL}},
666 
667         { &hf_fip_desc_fab_vfid,
668           { "VFID", "fip.fab.vfid",
669             FT_UINT16, BASE_DEC, NULL, 0,
670             NULL, HFILL}},
671 
672         { &hf_fip_desc_fab_map,
673           { "FC-MAP", "fip.fab.map",
674             FT_BYTES, SEP_DOT, NULL, 0,
675             NULL, HFILL}},
676 
677         { &hf_fip_desc_fab_name,
678           { "Fabric Name", "fip.fab.name",
679             FT_FCWWN, BASE_NONE, NULL, 0,
680             NULL, HFILL}},
681 
682         { &hf_fip_desc_fcoe_size,
683           { "Max FCoE frame size", "fip.fcoe_size",
684             FT_UINT16, BASE_DEC, NULL, 0,
685             NULL, HFILL}},
686 
687         { &hf_fip_desc_vn_mac,
688           { "VN_Port MAC Address", "fip.vn.mac",
689             FT_ETHER, BASE_NONE, NULL, 0,
690             NULL, HFILL}},
691 
692         { &hf_fip_desc_vn_fid,
693           { "VN_Port FC_ID", "fip.vn.fc_id",
694             FT_UINT32, BASE_HEX, NULL, 0,
695             NULL, HFILL}},
696 
697         { &hf_fip_desc_vn_wwpn,
698           { "Port Name", "fip.vn.pwwn",
699             FT_FCWWN, BASE_NONE, NULL, 0,
700             NULL, HFILL}},
701 
702         { &hf_fip_desc_fka,
703           { "FKA_ADV_Period", "fip.fka",
704             FT_UINT32, BASE_DEC, NULL, 0,
705             NULL, HFILL}},
706 
707         { &hf_fip_desc_vend,
708           { "Vendor-ID", "fip.vendor",
709             FT_BYTES, BASE_NONE, NULL, 0,
710             NULL, HFILL}},
711 
712         { &hf_fip_desc_vend_data,
713           { "Vendor-specific data", "fip.vendor.data",
714             FT_BYTES, BASE_NONE, NULL, 0,
715             NULL, HFILL}},
716 
717         { &hf_fip_desc_vlan,
718           { "VLAN", "fip.vlan",
719             FT_UINT16, BASE_DEC, NULL, 0,
720             NULL, HFILL}},
721 
722         { &hf_fip_desc_fc4f_types,
723           { "FC4 Types", "fip.fc4f.types",
724             FT_UINT32, BASE_HEX, NULL, 0,
725             NULL, HFILL}},
726 
727         { &hf_fip_desc_fcp_feat,
728           { "FCP Features", "fip.fc4f.feat.fcp",
729             FT_UINT32, BASE_HEX, NULL, 0xf,
730             NULL, HFILL}},
731 
732         { &hf_fip_type_ip,
733           { "IP", "fip.fc4f.ip",
734             FT_BOOLEAN, 32, NULL, 1 << 5,
735             NULL, HFILL}},
736 
737         { &hf_fip_type_fcp,
738           { "FCP", "fip.fc4f.fcp",
739             FT_BOOLEAN, 32, NULL, 1 << 8,
740             NULL, HFILL}},
741 
742         { &hf_fip_type_gs3,
743           { "GS3", "fip.fc4f.gs3",
744             FT_BOOLEAN, 32, NULL, 1 << 0,
745             NULL, HFILL}},
746 
747         { &hf_fip_fcp_feat_t,
748           { "FCP Target", "fip.fc4f.feat.fcp.target",
749             FT_BOOLEAN, 32, NULL, 1,
750             NULL, HFILL}},
751 
752         { &hf_fip_fcp_feat_i,
753           { "FCP Initiator", "fip.fc4f.feat.fcp.initiator",
754             FT_BOOLEAN, 32, NULL, 2,
755             NULL, HFILL}},
756 
757         { &hf_fip_desc_unk,
758           { "Unknown Descriptor", "fip.desc_unk",
759             FT_BYTES, BASE_NONE, NULL, 0,
760             NULL, HFILL}},
761 
762         { &hf_fip_descriptors,
763           { "Descriptors", "fip.descriptors",
764             FT_BYTES, BASE_NONE, NULL, 0,
765             NULL, HFILL}},
766 
767     };
768     static gint *ett[] = {
769         &ett_fip,
770         &ett_fip_flags,
771         &ett_fip_dt_pri,
772         &ett_fip_dt_mac,
773         &ett_fip_dt_map,
774         &ett_fip_dt_name,
775         &ett_fip_dt_fab,
776         &ett_fip_dt_mdl,
777         &ett_fip_dt_caps,
778         &ett_fip_dt_vn,
779         &ett_fip_dt_fka,
780         &ett_fip_dt_vend,
781         &ett_fip_dt_vlan,
782         &ett_fip_dt_fc4f,
783         &ett_fip_dt_fc4f_types,
784         &ett_fip_dt_fcp_feat,
785         &ett_fip_dt_unk
786     };
787 
788     static ei_register_info ei[] = {
789         { &ei_fip_descriptors, { "fip.descriptors.length_error", PI_MALFORMED, PI_ERROR, "Descriptor [length error]", EXPFILL }},
790     };
791 
792     expert_module_t* expert_fip;
793 
794     /* Register the protocol name and description */
795     proto_fip = proto_register_protocol("FCoE Initialization Protocol",
796         "FIP", "fip");
797 
798     /* Required function calls to register the header fields and
799      * subtrees used */
800     proto_register_field_array(proto_fip, hf, array_length(hf));
801     proto_register_subtree_array(ett, array_length(ett));
802     expert_fip = expert_register_protocol(proto_fip);
803     expert_register_field_array(expert_fip, ei, array_length(ei));
804 }
805 
806 /*
807  * This function name is required because a script is used to find these
808  * routines and create the code that calls these routines.
809  */
810 void
proto_reg_handoff_fip(void)811 proto_reg_handoff_fip(void)
812 {
813     dissector_handle_t fip_handle;
814 
815     fip_handle = create_dissector_handle(dissect_fip, proto_fip);
816     dissector_add_uint("ethertype", ETHERTYPE_FIP, fip_handle);
817     fc_handle = find_dissector_add_dependency("fc", proto_fip);
818 }
819 
820 /*
821  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
822  *
823  * Local variables:
824  * c-basic-offset: 4
825  * tab-width: 8
826  * indent-tabs-mode: nil
827  * End:
828  *
829  * vi: set shiftwidth=4 tabstop=8 expandtab:
830  * :indentSize=4:tabSize=8:noTabs=true:
831  */
832