epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-cisco-fp-mim.c
blob94e4d7a1f95ff072ae067e1237dc49577f594a40
1 /* packet-cisco-fp-mim.c
2 * Routines for analyzing Cisco FabricPath MiM (MAC-in-MAA) packets
3 * Copyright 2011, Leonard Tracy <letracy@cisco.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * https://clnv.s3.amazonaws.com/2016/usa/pdf/BRKDCT-3313.pdf
14 * https://clnv.s3.amazonaws.com/2014/eur/pdf/BRKDCT-2081.pdf
17 #include "config.h"
19 #include <epan/packet.h>
20 #include <epan/etypes.h>
21 #include <epan/addr_resolv.h>
22 #include <epan/prefs.h>
23 #include <epan/expert.h>
24 #include <epan/crc32-tvb.h>
25 #include <epan/tfs.h>
27 void proto_register_mim(void);
28 void proto_reg_handoff_fabricpath(void);
30 static bool fp_check_fcs;
32 static int proto_fp;
33 static int ett_mim;
34 static int ett_hmac;
36 /* Main protocol items */
37 static int hf_s_hmac;
38 static int hf_d_hmac;
39 static int hf_d_hmac_mc;
40 static int hf_ftag;
41 static int hf_ttl;
43 static int hf_fp_etype;
44 static int hf_fp_1ad_etype;
45 static int hf_fp_1ad_priority;
46 static int hf_fp_1ad_cfi;
47 static int hf_fp_1ad_svid;
48 static int hf_fp_fcs;
49 static int hf_fp_fcs_status;
51 /* HMAC subtrees */
52 static int hf_swid;
53 static int hf_sswid;
54 static int hf_eid;
55 static int hf_lid;
56 static int hf_ul;
57 static int hf_ig;
58 static int hf_ooodl;
60 static expert_field ei_fp_fcs_bad;
62 static const true_false_string ig_tfs = {
63 "Group address (multicast/broadcast)",
64 "Individual address (unicast)"
66 static const true_false_string ul_tfs = {
67 "Locally administered address (this is NOT the factory default)",
68 "Globally unique address (factory default)"
70 static const true_false_string ooodl_tfs = {
71 "Out of order delivery (If DA) or Do not learn (If SA)",
72 "Deliver in order (If DA) or Learn (If SA)"
75 static dissector_handle_t eth_withoutfcs_dissector;
77 #define FP_PROTO_COL_NAME "FabricPath"
78 #define FP_PROTO_COL_INFO "Cisco FabricPath MiM Encapsulated Frame"
80 #define FP_FIELD_LEN 3
82 #define FP_EID_MASK 0x00FCC0
83 #define FP_3B_EID_MASK 0xFCC000
85 #define FP_UL_MASK 0x020000
86 #define FP_IG_MASK 0x010000
87 #define FP_EID2_MASK 0x00C000
88 #define FP_RES_MASK 0x002000
89 #define FP_OOO_MASK 0x001000
90 #define FP_SWID_MASK 0x000FFF
92 #define FP_BF_LEN 3
93 #define FP_LID_LEN 2
94 #define FP_SSWID_LEN 1
95 #define FP_FTAG_LEN 2
97 #define FP_FTAG_MASK 0xFFC0
98 #define FP_TTL_MASK 0x003F
100 #define FP_HMAC_IG_MASK INT64_C(0x010000000000)
101 #define FP_HMAC_SWID_MASK INT64_C(0x000FFF000000)
102 #define FP_HMAC_SSWID_MASK INT64_C(0x000000FF0000)
103 #define FP_HMAC_LID_MASK INT64_C(0x00000000FFFF)
105 #define FP_HMAC_LEN 6
106 #define FP_HEADER_SIZE (16)
107 #define FP_HEADER_WITH_1AD_SIZE (20)
109 /* 0100.0000.0000 */
110 #define MAC_MC_BC INT64_C(0x010000000000)
112 /* proto */
113 static int dissect_fp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int header_size, int fcs_len );
116 * These packets are a bit strange.
118 * They run over Ethernet, but, instead of a normal 14-octet Ethernet
119 * header, they have a 16-octet or 20-octet header, which happens to
120 * have, in the position occupied by the Type/Length field in an
121 * Ethernet header, the Ethertype value reserved for FabricPath.
123 * The fields in the positions occupied by the destination and source
124 * MAC addresses in an Ethernet header are occupied by addresses that
125 * are parsed specially, so we want to dissect them differently from
126 * normal MAC addresses.
128 * The Ethertype field is part of a 4-octet FP tag, which includes
129 * the Ethertype and some additional information.
131 * So we register as a heuristic dissector, which gets called before
132 * the regular code that checks Ethertypes.
134 static bool
135 dissect_fp_heur (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
137 struct eth_phdr *eth = (struct eth_phdr *)data;
138 uint16_t etype = 0;
139 int header_size = 0;
140 int fcs_len = -1; // Unknown - we won't dissect it (see below)
142 /* Use the FCS length reported from Ethernet, which might be reported from
143 * wiretap if it was in the pcapng (if we're lucky), but likely has fallen
144 * back to the Ethernet "fcs" preference.
146 if (eth && eth->fcs_len != -1) {
147 fcs_len = eth->fcs_len;
150 if ( ! tvb_bytes_exist( tvb, 12, 2 ) )
151 return false;
153 etype = tvb_get_ntohs( tvb, 12 );
155 switch ( etype ) {
156 case ETHERTYPE_DCE:
157 header_size = FP_HEADER_SIZE;
158 break;
159 case ETHERTYPE_IEEE_802_1AD:
160 case ETHERTYPE_VLAN:
161 if ( tvb_bytes_exist( tvb, 16, 2 ) && tvb_get_ntohs( tvb, 16 ) == ETHERTYPE_DCE ) {
162 header_size = FP_HEADER_WITH_1AD_SIZE;
163 break;
165 /* fall through */
166 default:
167 return false;
170 if ( dissect_fp_common( tvb, pinfo, tree, header_size, fcs_len ) > 0 ) {
171 return true;
174 return false;
177 static void
178 fp_get_hmac_addr (uint64_t hmac, uint16_t *swid, uint16_t *sswid, uint16_t *lid) {
180 if (!swid || !sswid || !lid) {
181 return;
184 *swid = (uint16_t) ((hmac & FP_HMAC_SWID_MASK) >> 24);
185 *sswid = (uint16_t) ((hmac & FP_HMAC_SSWID_MASK) >> 16);
186 *lid = (uint16_t) (hmac & FP_HMAC_LID_MASK);
189 static void
190 fp_add_hmac (tvbuff_t *tvb, proto_tree *tree, int offset) {
192 uint16_t eid;
194 if (!tree) {
195 return;
198 eid = tvb_get_ntohs(tvb, offset);
200 eid &= FP_EID_MASK;
201 eid = ((eid & 0x00C0) >> 6) + ((eid & 0xFC00) >> 8);
202 proto_tree_add_uint(tree, hf_eid, tvb, offset, FP_BF_LEN, eid);
204 proto_tree_add_item (tree, hf_ul, tvb, offset, FP_BF_LEN, ENC_NA);
205 proto_tree_add_item (tree, hf_ig, tvb, offset, FP_BF_LEN, ENC_NA);
206 proto_tree_add_item (tree, hf_ooodl, tvb, offset, FP_BF_LEN, ENC_NA);
207 proto_tree_add_item (tree, hf_swid, tvb, offset, FP_BF_LEN, ENC_BIG_ENDIAN);
208 offset += FP_BF_LEN;
210 proto_tree_add_item (tree, hf_sswid, tvb, offset, FP_SSWID_LEN, ENC_BIG_ENDIAN);
211 offset += FP_SSWID_LEN;
213 proto_tree_add_item (tree, hf_lid, tvb, offset, FP_LID_LEN, ENC_BIG_ENDIAN);
214 /*offset += FP_LID_LEN;*/
217 /* FabricPath MiM Dissector */
218 static int
219 dissect_fp_common ( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int header_size, int fcs_len)
221 proto_item *ti;
222 proto_tree *fp_tree;
223 proto_tree *fp_addr_tree;
224 tvbuff_t *next_tvb;
225 int offset = 0;
226 int next_tvb_len = 0;
227 int fcs_offset = 0;
228 uint64_t hmac_src;
229 uint64_t hmac_dst;
230 uint16_t sswid = 0;
231 uint16_t ssswid = 0;
232 uint16_t slid = 0;
233 uint16_t dswid = 0;
234 uint16_t dsswid = 0;
235 uint16_t dlid = 0;
236 uint16_t etype = 0;
237 const uint8_t *dst_addr = NULL;
238 bool dest_as_mac = false;
241 col_set_str( pinfo->cinfo, COL_PROTOCOL, FP_PROTO_COL_NAME );
242 col_set_str( pinfo->cinfo, COL_INFO, FP_PROTO_COL_INFO );
245 * Outer SA:
246 * - SwitchID ingress FP switch system ID
247 * - SubswitchID is used in some cases of VPC+
248 * - LID (Local ID) is specific to the implementation
249 * + N7K the LID is generally the port index of the ingress interface
250 * + N5K/N6K LID most of the time will be 0
251 * + EndnodeID is not currently used
253 * Outer DA:
254 * - For known SA/DA is taken from MAC table for DMAC
255 * - For broadcast and multicast is the same as DMAC
256 * - For unknown unicast DA is 010f.ffc1.01c0 (flood to vlan)
257 * - For known unicast DA, but unknown SA is 010f.ffc1.02c0 (flood to fabric)
260 hmac_dst = tvb_get_ntoh48 (tvb, 0);
261 hmac_src = tvb_get_ntoh48 (tvb, 6);
263 if (hmac_dst & MAC_MC_BC) {
264 dest_as_mac = true;
266 if (!dest_as_mac) {
267 fp_get_hmac_addr (hmac_dst, &dswid, &dsswid, &dlid);
268 } else {
269 hmac_dst = GUINT64_TO_BE (hmac_dst);
270 /* Get pointer to most sig byte of destination address
271 in network order
273 dst_addr = ((const uint8_t *) &hmac_dst) + 2;
275 fp_get_hmac_addr (hmac_src, &sswid, &ssswid, &slid);
277 /* FIXME: Does this make sense??? */
278 if (tree && PTREE_DATA(tree)->visible) {
279 if (dest_as_mac) {
280 address ether_addr;
282 set_address(&ether_addr, AT_ETHER, 6, dst_addr);
284 ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, header_size,
285 "Cisco FabricPath, Src: %03x.%02x.%04x, Dst: %s",
286 sswid, ssswid, slid,
287 address_with_resolution_to_str(pinfo->pool, &ether_addr));
288 } else {
289 ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, header_size,
290 "Cisco FabricPath, Src: %03x.%02x.%04x, Dst: %03x.%02x.%04x",
291 sswid, ssswid, slid,
292 dswid, dsswid, dlid);
294 } else {
295 ti = proto_tree_add_item( tree, proto_fp, tvb, 0, header_size, ENC_NA );
297 fp_tree = proto_item_add_subtree( ti, ett_mim );
299 /* Add dest and source heir. mac */
300 if (dest_as_mac) {
301 /* MCAST address */
302 proto_tree_add_ether( fp_tree, hf_d_hmac_mc, tvb, offset, 6, dst_addr);
303 } else {
304 /* Unicast */
305 ti = proto_tree_add_none_format (fp_tree, hf_d_hmac, tvb, offset, 6, "Destination: %03x.%02x.%04x", dswid, dsswid, dlid);
306 fp_addr_tree = proto_item_add_subtree (ti, ett_hmac);
307 fp_add_hmac (tvb, fp_addr_tree, offset);
309 offset += FP_HMAC_LEN;
311 ti = proto_tree_add_none_format (fp_tree, hf_s_hmac, tvb, offset, 6,
312 "Source: %03x.%02x.%04x", sswid, ssswid, slid);
313 fp_addr_tree = proto_item_add_subtree (ti, ett_hmac);
314 fp_add_hmac (tvb, fp_addr_tree, offset);
315 offset += FP_HMAC_LEN;
317 etype = tvb_get_ntohs(tvb, offset);
318 switch (etype) {
319 case ETHERTYPE_DCE:
320 proto_tree_add_item(fp_tree, hf_fp_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
321 offset += 2;
322 break;
323 case ETHERTYPE_IEEE_802_1AD:
324 case ETHERTYPE_VLAN:
325 proto_tree_add_item(fp_tree, hf_fp_1ad_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
326 offset += 2;
327 proto_tree_add_item(fp_tree, hf_fp_1ad_priority, tvb, offset, 2, ENC_NA);
328 proto_tree_add_item(fp_tree, hf_fp_1ad_cfi, tvb, offset, 2, ENC_NA);
329 proto_tree_add_item(fp_tree, hf_fp_1ad_svid, tvb, offset, 2, ENC_BIG_ENDIAN);
330 offset += 2;
331 proto_tree_add_item(fp_tree, hf_fp_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
332 offset += 2;
333 break;
334 default:
335 /* The heuristics should prevent us from getting here */
336 DISSECTOR_ASSERT(0);
339 proto_tree_add_item (fp_tree, hf_ftag, tvb, offset, FP_FTAG_LEN, ENC_BIG_ENDIAN);
340 proto_tree_add_item (fp_tree, hf_ttl, tvb, offset, FP_FTAG_LEN, ENC_BIG_ENDIAN);
342 /* eval FCS */
344 * These packets don't have a length field, and the Ethernet dissector
345 * always returns the full captured length (because it will consume
346 * unused bytes as a trailer), so we don't have a good way to heuristically
347 * detect if there's an FCS. So if we don't know if there's an FCS,
348 * don't dissect it here and don't slice it off (so that if there isn't
349 * one, the Ethernet dissector and dissectors it calls don't have errors
350 * from slicing off too many bytes - #19989), but also tell the Ethernet
351 * dissector that there definitely isn't an FCS so that it treats it as a
352 * generic trailer, because if there _is_ an FCS the calculation includes
353 * this header, so any calculation in the Ethernet dissector will be
354 * wrong - #15769).
356 if (fcs_len > 0) {
357 fcs_offset = tvb_reported_length(tvb) - fcs_len;
359 if ( tvb_bytes_exist(tvb, fcs_offset, fcs_len ) ) {
360 if ( fp_check_fcs ) {
361 uint32_t fcs = crc32_802_tvb(tvb, fcs_offset);
362 proto_tree_add_checksum(fp_tree, tvb, fcs_offset, hf_fp_fcs, hf_fp_fcs_status, &ei_fp_fcs_bad, pinfo, fcs, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
363 } else {
364 proto_tree_add_checksum(fp_tree, tvb, fcs_offset, hf_fp_fcs, hf_fp_fcs_status, &ei_fp_fcs_bad, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
366 proto_tree_set_appendix(fp_tree, tvb, fcs_offset, fcs_len);
368 } else {
369 fcs_len = 0;
372 /* call the eth dissector w/o the FCS */
373 next_tvb_len = tvb_reported_length_remaining( tvb, header_size ) - fcs_len;
374 next_tvb = tvb_new_subset_length( tvb, header_size, next_tvb_len );
377 * We've already handled the replaced CFP checksum above.
378 * Therefore we call the Ethernet dissector without expecting a FCS.
380 call_dissector( eth_withoutfcs_dissector, next_tvb, pinfo, tree );
382 return tvb_captured_length( tvb );
385 /* Register the protocol with Wireshark */
386 void
387 proto_register_mim(void)
389 static hf_register_info hf[] = {
390 { &hf_s_hmac,
391 { "Source HMAC", "cfp.s_hmac",
392 FT_NONE, BASE_NONE, NULL,
393 0, "Source Hierarchical MAC", HFILL }},
395 { &hf_d_hmac,
396 { "Destination HMAC", "cfp.d_hmac",
397 FT_NONE, BASE_NONE, NULL,
398 0, "Destination Hierarchical MAC", HFILL }},
400 { &hf_d_hmac_mc,
401 { "MC Destination", "cfp.d_hmac_mc",
402 FT_ETHER, BASE_NONE, NULL,
403 0, "Multicast Destination Address", HFILL }},
405 { &hf_fp_etype,
406 { "FP Ethertype", "cfp.etype", FT_UINT16, BASE_HEX,
407 VALS(etype_vals), 0x0, NULL, HFILL }},
409 { &hf_fp_1ad_etype,
410 { "IEEE 802.1ad Ethertype", "cfp.1ad.etype", FT_UINT16, BASE_HEX,
411 VALS(etype_vals), 0x0, NULL, HFILL }},
413 { &hf_fp_1ad_priority,
414 { "Priority", "cfp.1ad.priority", FT_UINT16, BASE_DEC,
415 0, 0xE000, NULL, HFILL }},
417 { &hf_fp_1ad_cfi,
418 { "DEI", "cfp.1ad.dei", FT_UINT16, BASE_DEC,
419 0, 0x1000, "Drop Eligibility", HFILL }},
421 { &hf_fp_1ad_svid,
422 { "ID", "cfp.1ad.id", FT_UINT16, BASE_DEC,
423 0, 0x0FFF, "Vlan ID", HFILL }},
425 { &hf_fp_fcs,
426 { "Frame check sequence", "cfp.fcs", FT_UINT32, BASE_HEX,
427 NULL, 0x0, "FabricPath checksum", HFILL }},
429 { &hf_fp_fcs_status,
430 { "FCS status", "cfp.fcs.status", FT_UINT8, BASE_NONE,
431 VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
433 { &hf_ftag,
434 { "FTAG", "cfp.ftag",
435 FT_UINT16, BASE_DEC, NULL, FP_FTAG_MASK,
436 "FTAG field identifying forwarding distribution tree.", HFILL }},
438 { &hf_ttl,
439 { "TTL", "cfp.ttl",
440 FT_UINT16, BASE_DEC, NULL, FP_TTL_MASK,
441 "The remaining hop count for this frame", HFILL }},
443 &hf_swid,
444 { "switch-id", "cfp.swid",
445 FT_UINT24, BASE_DEC_HEX, NULL, FP_SWID_MASK,
446 "Switch-id/nickname of switch in FabricPath network", HFILL }},
448 &hf_sswid,
449 { "sub-switch-id", "cfp.sswid",
450 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
451 "Sub-switch-id of switch in FabricPath network", HFILL }},
453 &hf_eid,
454 { "End Node ID", "cfp.eid",
455 FT_UINT24, BASE_DEC_HEX, NULL, FP_3B_EID_MASK,
456 "Cisco FabricPath End node ID", HFILL }},
458 &hf_lid,
459 { "Source LID", "cfp.lid",
460 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
461 "Source or Destination Port index on switch in FabricPath network", HFILL }},
463 &hf_ul,
464 { "U/L bit", "cfp.ul",
465 FT_BOOLEAN, 24, TFS(&ul_tfs), FP_UL_MASK,
466 "Specifies if this is a locally administered or globally unique (IEEE assigned) address", HFILL }},
468 &hf_ig,
469 { "I/G bit", "cfp.ig",
470 FT_BOOLEAN, 24 /* FP_BF_LEN */, TFS(&ig_tfs), FP_IG_MASK,
471 "Specifies if this is an individual (unicast) or group (broadcast/multicast) address", HFILL }},
473 &hf_ooodl,
474 { "OOO/DL Bit", "cfp.ooodl",
475 FT_BOOLEAN, 24 /* FP_BF_LEN */, TFS(&ooodl_tfs), FP_OOO_MASK,
476 "Specifies Out of Order Delivery OK in destination address and Do Not Learn when set in source address", HFILL }}
480 static int *ett[] = {
481 &ett_mim,
482 &ett_hmac
485 static ei_register_info ei[] = {
486 { &ei_fp_fcs_bad, { "cfp.fcs_bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}
489 module_t *mim_module;
490 expert_module_t *expert_mim;
492 proto_fp = proto_register_protocol("Cisco FabricPath", "CFP", "cfp");
494 mim_module = prefs_register_protocol (proto_fp, NULL);
496 prefs_register_obsolete_preference (mim_module, "enable");
498 prefs_register_bool_preference(mim_module, "check_fcs",
499 "Validate the FabricPath checksum if possible",
500 "Whether to validate the Frame Check Sequence",
501 &fp_check_fcs);
503 proto_register_field_array(proto_fp, hf, array_length(hf));
504 proto_register_subtree_array(ett, array_length(ett));
506 expert_mim = expert_register_protocol(proto_fp);
507 expert_register_field_array(expert_mim, ei, array_length(ei));
510 void
511 proto_reg_handoff_fabricpath(void)
514 * Using Heuristic dissector (As opposed to
515 * registering the ethertype) in order to
516 * get outer source and destination MAC
517 * before the standard ethernet dissector
519 heur_dissector_add ("eth", dissect_fp_heur, "Cisco FabricPath over Ethernet", "fp_eth", proto_fp, HEURISTIC_ENABLE);
522 * The FCS in FabricPath frames covers the entire FabricPath frame,
523 * not the encapsulated Ethernet frame, so we don't want to treat
524 * the encapsulated frame as if it had an FCS.
526 eth_withoutfcs_dissector = find_dissector_add_dependency( "eth_withoutfcs", proto_fp );
530 * Editor modelines - https://www.wireshark.org/tools/modelines.html
532 * Local Variables:
533 * c-basic-offset: 2
534 * tab-width: 8
535 * indent-tabs-mode: nil
536 * End:
538 * ex: set shiftwidth=2 tabstop=8 expandtab:
539 * :indentSize=2:tabSize=8:noTabs=true: