Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ieee8021ah.c
blob4387724121fe53d22f893bb7605d1157fce11aa1
1 /* packet-ieee8021ah.c
2 * Routines for 802.1ah ethernet header disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <epan/packet.h>
14 #include <epan/capture_dissectors.h>
15 #include <wsutil/pint.h>
16 #include <epan/addr_resolv.h>
18 #include "packet-ipx.h"
19 #include "packet-llc.h"
20 #include <epan/etypes.h>
21 #include <epan/prefs.h>
23 void proto_register_ieee8021ah(void);
24 void proto_reg_handoff_ieee8021ah(void);
26 static dissector_handle_t ieee8021ah_handle;
27 static dissector_handle_t ieee8021ad_handle;
28 static dissector_handle_t ethertype_handle;
30 static capture_dissector_handle_t ipx_cap_handle;
31 static capture_dissector_handle_t llc_cap_handle;
33 static void dissect_ieee8021ah_common(tvbuff_t *tvb, packet_info *pinfo,
34 proto_tree *tree, proto_tree *parent, int tree_index);
36 /* GLOBALS ************************************************************/
38 /* ethertype for 802.1ah tag - encapsulating an Ethernet packet */
39 static unsigned int ieee8021ah_ethertype = ETHERTYPE_IEEE_802_1AH;
41 static int proto_ieee8021ah;
42 static int proto_ieee8021ad;
44 /* dot1ad B-tag fields */
45 static int hf_ieee8021ad_priority;
46 static int hf_ieee8021ad_cfi;
47 static int hf_ieee8021ad_id;
48 static int hf_ieee8021ad_svid;
49 static int hf_ieee8021ad_cvid;
51 /* dot1ah C-tag fields */
52 static int hf_ieee8021ah_priority;
53 static int hf_ieee8021ah_drop; /* drop eligibility */
54 static int hf_ieee8021ah_nca; /* no customer addresses (c_daddr & c_saddr are 0) */
55 static int hf_ieee8021ah_res1; /* 2 bits reserved; ignored on receive */
56 static int hf_ieee8021ah_res2; /* 2 bits reserved; delete frame if non-zero */
57 static int hf_ieee8021ah_isid; /* I-SID */
58 static int hf_ieee8021ah_c_daddr; /* encapsulated customer dest addr */
59 static int hf_ieee8021ah_c_saddr; /* encapsulated customer src addr */
61 static int hf_ieee8021ah_etype;
62 /* static int hf_ieee8021ah_len; */
63 static int hf_ieee8021ah_trailer;
65 static int ett_ieee8021ah;
66 static int ett_ieee8021ad;
68 #define IEEE8021AD_LEN 4
69 #define IEEE8021AH_LEN 18
70 #define IEEE8021AH_ISIDMASK 0x00FFFFFF
72 /* FUNCTIONS ************************************************************/
75 static bool
76 capture_ieee8021ah(const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_)
78 uint16_t encap_proto;
80 if (!BYTES_ARE_IN_FRAME(offset, len, IEEE8021AH_LEN + 1))
81 return false;
83 encap_proto = pntoh16( &pd[offset + IEEE8021AH_LEN - 2] );
84 if (encap_proto <= IEEE_802_3_MAX_LEN) {
85 if ( pd[offset + IEEE8021AH_LEN] == 0xff
86 && pd[offset + IEEE8021AH_LEN + 1] == 0xff ) {
87 return call_capture_dissector(ipx_cap_handle, pd, offset + IEEE8021AH_LEN, len, cpinfo, pseudo_header);
89 else {
90 return call_capture_dissector(llc_cap_handle, pd, offset + IEEE8021AH_LEN, len, cpinfo, pseudo_header);
94 return try_capture_dissector("ethertype", encap_proto, pd, offset + IEEE8021AH_LEN, len, cpinfo, pseudo_header);
97 /* Dissector *************************************************************/
98 static
99 int dissect_ieee8021ad(tvbuff_t *tvb, packet_info *pinfo,
100 proto_tree *tree, void* data _U_)
102 proto_tree *ptree = NULL;
103 proto_tree *tagtree = NULL;
104 uint32_t tci, ctci;
105 uint16_t encap_proto;
106 int proto_tree_index;
107 ethertype_data_t ethertype_data;
109 tvbuff_t *next_tvb = NULL;
110 proto_tree *ieee8021ad_tree;
111 proto_tree *ieee8021ad_tag_tree;
113 /* set tree index */
114 proto_tree_index = proto_ieee8021ad;
116 /* add info to column display */
117 col_set_str(pinfo->cinfo, COL_PROTOCOL, "802.1ad");
118 col_clear(pinfo->cinfo, COL_INFO);
120 tci = tvb_get_ntohs( tvb, 0 );
122 col_add_fstr(pinfo->cinfo, COL_INFO,
123 "PRI: %d DROP: %d ID: %d",
124 (tci >> 13), ((tci >> 12) & 1), (tci & 0xFFF));
126 /* create the protocol tree */
127 ptree = proto_tree_add_item(tree, proto_tree_index, tvb, 0, IEEE8021AD_LEN, ENC_NA);
128 ieee8021ad_tree = proto_item_add_subtree(ptree, ett_ieee8021ad);
130 encap_proto = tvb_get_ntohs(tvb, IEEE8021AD_LEN - 2);
131 ethertype_data.fh_tree = ieee8021ad_tree;
132 ethertype_data.trailer_id = hf_ieee8021ah_trailer;
133 ethertype_data.fcs_len = 0;
135 /* If it's a 1ah frame, create subtree for B-Tag, rename overall
136 tree to 802.1ah, pass to 1ah dissector */
137 if (encap_proto == ETHERTYPE_IEEE_802_1AH) {
138 if (tree) {
139 tagtree = proto_tree_add_item(ptree, proto_tree_index, tvb, 0, 2, ENC_NA);
140 ieee8021ad_tag_tree = proto_item_add_subtree(tagtree, ett_ieee8021ad);
142 /* add fields */
143 proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_priority, tvb,
144 0, 1, tci);
145 proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
146 proto_tree_add_uint(ieee8021ad_tag_tree, hf_ieee8021ad_id, tvb, 0, 2, tci);
148 /* set label of B-tag subtree */
149 proto_item_set_text(ieee8021ad_tag_tree, "B-Tag, B-VID: %d", tci & 0x0FFF);
152 next_tvb = tvb_new_subset_remaining(tvb, IEEE8021AD_LEN);
154 if (ptree) {
155 /* add bvid to label */
156 proto_item_set_text(ptree, "IEEE 802.1ah, B-VID: %d", tci & 0x0FFF);
158 dissect_ieee8021ah_common(next_tvb, pinfo, ptree, tree, proto_tree_index);
160 else {
161 dissect_ieee8021ah_common(next_tvb, pinfo, tree, NULL, proto_tree_index);
164 } else if (encap_proto == ETHERTYPE_IEEE_802_1AD) {
165 /* two VLAN tags (i.e. Q-in-Q) */
166 ctci = tvb_get_ntohs(tvb, IEEE8021AD_LEN);
168 if (tree) {
169 /* add fields */
170 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb,
171 0, 1, tci);
172 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
173 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_svid, tvb, 0, 2, tci);
174 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb,
175 IEEE8021AD_LEN, 1, ctci);
176 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb,
177 IEEE8021AD_LEN, 1, ctci);
178 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cvid, tvb, IEEE8021AD_LEN,
179 2, ctci);
182 proto_item_set_text(ptree, "IEEE 802.1ad, S-VID: %d, C-VID: %d", tci & 0x0FFF,
183 ctci & 0x0FFF);
185 ethertype_data.etype = tvb_get_ntohs(tvb, IEEE8021AD_LEN * 2 - 2);
186 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ah_etype, tvb,
187 IEEE8021AD_LEN * 2 - 2, 2, ethertype_data.etype);
189 ethertype_data.payload_offset = IEEE8021AD_LEN * 2;
191 /* 802.1ad tags are always followed by an ethertype; call next
192 dissector based on ethertype */
193 call_dissector_with_data(ethertype_handle, tvb, pinfo, tree, &ethertype_data);
194 } else {
195 /* Something else (shouldn't really happen, but we'll support it anyways) */
196 if (tree) {
197 /* add fields */
198 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_priority, tvb,
199 0, 1, tci);
200 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_cfi, tvb, 0, 1, tci);
201 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ad_id, tvb, 0, 2, tci);
204 /* label should be 802.1ad not .1ah */
205 proto_item_set_text(ptree, "IEEE 802.1ad, ID: %d", tci & 0x0FFF);
207 /* Add the Ethernet type to the protocol tree */
208 proto_tree_add_uint(ieee8021ad_tree, hf_ieee8021ah_etype, tvb,
209 IEEE8021AD_LEN - 2, 2, encap_proto);
211 ethertype_data.etype = encap_proto;
212 ethertype_data.payload_offset = IEEE8021AD_LEN;
214 /* 802.1ad tags are always followed by an ethertype; call next
215 dissector based on ethertype */
216 call_dissector_with_data(ethertype_handle, tvb, pinfo, tree, &ethertype_data);
218 return tvb_captured_length(tvb);
221 static void
222 dissect_ieee8021ah_common(tvbuff_t *tvb, packet_info *pinfo,
223 proto_tree *tree, proto_tree *parent, int tree_index) {
224 uint32_t tci;
225 uint16_t encap_proto;
226 proto_tree *ptree;
227 ethertype_data_t ethertype_data;
229 proto_tree *ieee8021ah_tag_tree;
231 tci = tvb_get_ntohl( tvb, 0 );
233 col_add_fstr(pinfo->cinfo, COL_INFO,
234 "PRI: %d Drop: %d NCA: %d Res1: %d Res2: %d I-SID: %d",
235 (tci >> 29), ((tci >> 28) & 1), ((tci >> 27) & 1),
236 ((tci >> 26) & 1), ((tci >> 24) & 3), tci & IEEE8021AH_ISIDMASK);
238 /* create the protocol tree */
239 ptree = NULL;
240 ieee8021ah_tag_tree = NULL;
242 if (tree) {
243 /* 802.1ah I-Tag */
244 ptree = proto_tree_add_item(tree, tree_index, tvb, 0, 4, ENC_NA);
245 ieee8021ah_tag_tree = proto_item_add_subtree(ptree, ett_ieee8021ah);
247 /* add fields */
248 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_priority, tvb,
249 0, 1, tci);
250 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_drop, tvb, 0, 1, tci);
251 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_nca, tvb, 0, 1, tci);
252 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_res1, tvb, 0, 1, tci);
253 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_res2, tvb, 0, 1, tci);
254 proto_tree_add_uint(ieee8021ah_tag_tree, hf_ieee8021ah_isid, tvb, 1, 3, tci);
256 proto_item_set_text(ieee8021ah_tag_tree, "I-Tag, I-SID: %d",
257 tci & IEEE8021AH_ISIDMASK);
259 proto_tree_add_item(tree, hf_ieee8021ah_c_daddr, tvb, 4, 6, ENC_NA);
260 proto_tree_add_item(tree, hf_ieee8021ah_c_saddr, tvb, 10, 6, ENC_NA);
262 /* add text to 802.1ad label */
263 if (parent) {
264 proto_item_append_text(tree, ", I-SID: %d, C-Src: %s, C-Dst: %s",
265 tci & IEEE8021AH_ISIDMASK,
266 tvb_address_with_resolution_to_str(pinfo->pool, tvb, AT_ETHER, 10),
267 tvb_address_with_resolution_to_str(pinfo->pool, tvb, AT_ETHER, 4));
271 encap_proto = tvb_get_ntohs(tvb, IEEE8021AH_LEN - 2);
272 proto_tree_add_uint(tree, hf_ieee8021ah_etype, tvb,
273 IEEE8021AD_LEN - 2, 2, encap_proto);
275 /* 802.1ah I-tags are always followed by an ethertype; call next
276 dissector based on ethertype */
278 /* If this was preceded by a 802.1ad tag, must pass original tree
279 to next dissector, not 802.1ad tree */
280 ethertype_data.etype = encap_proto;
281 ethertype_data.fh_tree = tree;
282 ethertype_data.payload_offset = IEEE8021AH_LEN;
283 ethertype_data.trailer_id = hf_ieee8021ah_trailer;
284 ethertype_data.fcs_len = 0;
286 if (parent) {
287 call_dissector_with_data(ethertype_handle, tvb, pinfo, parent, &ethertype_data);
289 else {
290 call_dissector_with_data(ethertype_handle, tvb, pinfo, tree, &ethertype_data);
294 static
295 int dissect_ieee8021ah(tvbuff_t *tvb, packet_info *pinfo,
296 proto_tree *tree, void* data _U_)
298 proto_item *pi;
299 uint32_t tci;
300 int proto_tree_index;
301 proto_tree *ieee8021ah_tree;
303 /* set tree index */
304 proto_tree_index = proto_ieee8021ah;
306 /* add info to column display */
307 col_set_str(pinfo->cinfo, COL_PROTOCOL, "802.1ah");
308 col_clear(pinfo->cinfo, COL_INFO);
310 tci = tvb_get_ntohl( tvb, 0 );
312 col_add_fstr(pinfo->cinfo, COL_INFO,
313 "PRI: %d Drop: %d NCA: %d Res1: %d Res2: %d I-SID: %d",
314 (tci >> 29), ((tci >> 28) & 1), ((tci >> 27) & 1),
315 ((tci >> 26) & 1), ((tci >> 24) & 3), (tci & 0x00FFFFFF));
317 pi = proto_tree_add_item(tree, proto_tree_index, tvb, 0, IEEE8021AH_LEN, ENC_NA);
318 ieee8021ah_tree = proto_item_add_subtree(pi, ett_ieee8021ah);
320 if (ieee8021ah_tree) {
321 dissect_ieee8021ah_common(tvb, pinfo, ieee8021ah_tree, tree, proto_tree_index);
322 } else {
323 dissect_ieee8021ah_common(tvb, pinfo, tree, NULL, proto_tree_index);
325 return tvb_captured_length(tvb);
328 /* Protocol Registration **************************************************/
330 void
331 proto_register_ieee8021ah(void)
333 static hf_register_info hf[] = {
334 { &hf_ieee8021ah_priority, {
335 "Priority", "ieee8021ah.priority", FT_UINT32, BASE_DEC,
336 0, 0xE0000000, NULL, HFILL }},
337 { &hf_ieee8021ah_drop, {
338 "DROP", "ieee8021ah.drop", FT_UINT32, BASE_DEC,
339 0, 0x10000000, NULL, HFILL }},
340 { &hf_ieee8021ah_nca, {
341 "NCA", "ieee8021ah.nca", FT_UINT32, BASE_DEC,
342 0, 0x08000000, "No Customer Addresses", HFILL }},
343 { &hf_ieee8021ah_res1, {
344 "RES1", "ieee8021ah.res1", FT_UINT32, BASE_DEC,
345 0, 0x04000000, "Reserved1", HFILL }},
346 { &hf_ieee8021ah_res2, {
347 "RES2", "ieee8021ah.res2", FT_UINT32, BASE_DEC,
348 0, 0x03000000, "Reserved2", HFILL }},
349 { &hf_ieee8021ah_isid, {
350 "I-SID", "ieee8021ah.isid", FT_UINT32, BASE_DEC,
351 0, 0x00FFFFFF, NULL, HFILL }},
352 { &hf_ieee8021ah_c_daddr, {
353 "C-Destination", "ieee8021ah.cdst", FT_ETHER, BASE_NONE,
354 NULL, 0x0, "Customer Destination Address", HFILL }},
355 { &hf_ieee8021ah_c_saddr, {
356 "C-Source", "ieee8021ah.csrc", FT_ETHER, BASE_NONE,
357 NULL, 0x0, "Customer Source Address", HFILL }},
358 { &hf_ieee8021ah_etype, {
359 "Type", "ieee8021ah.etype", FT_UINT16, BASE_HEX,
360 VALS(etype_vals), 0x0, NULL, HFILL }},
361 #if 0
362 { &hf_ieee8021ah_len, {
363 "Length", "ieee8021ah.len", FT_UINT16, BASE_DEC,
364 NULL, 0x0, NULL, HFILL }},
365 #endif
366 { &hf_ieee8021ah_trailer, {
367 "Trailer", "ieee8021ah.trailer", FT_BYTES, BASE_NONE,
368 NULL, 0x0, "802.1ah Trailer", HFILL }}
371 static hf_register_info hf_1ad[] = {
372 { &hf_ieee8021ad_priority, {
373 "Priority", "ieee8021ad.priority", FT_UINT16, BASE_DEC,
374 0, 0xE000, NULL, HFILL }},
375 { &hf_ieee8021ad_cfi, {
376 "DEI", "ieee8021ad.dei", FT_UINT16, BASE_DEC,
377 0, 0x1000, "Drop Eligibility", HFILL }},
378 { &hf_ieee8021ad_id, {
379 "ID", "ieee8021ad.id", FT_UINT16, BASE_DEC,
380 0, 0x0FFF, "Vlan ID", HFILL }},
381 { &hf_ieee8021ad_svid, {
382 "ID", "ieee8021ad.svid", FT_UINT16, BASE_DEC,
383 0, 0x0FFF, "S-Vlan ID", HFILL }},
384 { &hf_ieee8021ad_cvid, {
385 "ID", "ieee8021ad.cvid", FT_UINT16, BASE_DEC,
386 0, 0x0FFF, "C-Vlan ID", HFILL }},
389 static int *ett[] = {
390 &ett_ieee8021ah,
391 &ett_ieee8021ad
395 module_t *ieee8021ah_module;
397 /* registration */
398 /* dot1ah */
399 proto_ieee8021ah = proto_register_protocol("IEEE 802.1ah", "IEEE 802.1AH",
400 "ieee8021ah");
401 ieee8021ah_handle = register_dissector("ieee8021ah", dissect_ieee8021ah,
402 proto_ieee8021ah);
403 proto_register_field_array(proto_ieee8021ah, hf, array_length(hf));
405 proto_ieee8021ad = proto_register_protocol("IEEE 802.1ad", "IEEE 802.1AD",
406 "ieee8021ad");
407 ieee8021ad_handle = register_dissector("ieee8021ad", dissect_ieee8021ad,
408 proto_ieee8021ad);
409 proto_register_field_array(proto_ieee8021ad, hf_1ad, array_length(hf_1ad));
411 /* register subtree array for both */
412 proto_register_subtree_array(ett, array_length(ett));
414 /* add a user preference to set the 802.1ah ethertype */
415 ieee8021ah_module = prefs_register_protocol(proto_ieee8021ah,
416 proto_reg_handoff_ieee8021ah);
417 prefs_register_uint_preference(ieee8021ah_module, "8021ah_ethertype",
418 "802.1ah Ethertype (in hex)",
419 "(Hexadecimal) Ethertype used to indicate IEEE 802.1ah tag.",
420 16, &ieee8021ah_ethertype);
423 void
424 proto_reg_handoff_ieee8021ah(void)
426 static bool prefs_initialized = false;
427 static unsigned int old_ieee8021ah_ethertype;
428 static capture_dissector_handle_t ieee8021ah_cap_handle;
430 if (!prefs_initialized){
431 dissector_add_uint("ethertype", ETHERTYPE_IEEE_802_1AD, ieee8021ad_handle);
432 ethertype_handle = find_dissector_add_dependency("ethertype", proto_ieee8021ah);
433 find_dissector_add_dependency("ethertype", proto_ieee8021ad);
434 ieee8021ah_cap_handle = create_capture_dissector_handle(capture_ieee8021ah, proto_ieee8021ah);
435 capture_dissector_add_uint("ethertype", ETHERTYPE_IEEE_802_1AD, ieee8021ah_cap_handle);
436 capture_dissector_add_uint("ethertype", ETHERTYPE_IEEE_802_1AH, ieee8021ah_cap_handle);
438 ipx_cap_handle = find_capture_dissector("ipx");
439 llc_cap_handle = find_capture_dissector("llc");
441 prefs_initialized = true;
443 else {
444 dissector_delete_uint("ethertype", old_ieee8021ah_ethertype, ieee8021ah_handle);
447 old_ieee8021ah_ethertype = ieee8021ah_ethertype;
448 dissector_add_uint("ethertype", ieee8021ah_ethertype, ieee8021ah_handle);
452 * Editor modelines - https://www.wireshark.org/tools/modelines.html
454 * Local variables:
455 * c-basic-offset: 4
456 * tab-width: 8
457 * indent-tabs-mode: nil
458 * End:
460 * vi: set shiftwidth=4 tabstop=8 expandtab:
461 * :indentSize=4:tabSize=8:noTabs=true: