2 * Routines for VLAN 802.1Q 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
12 #include <epan/packet.h>
13 #include <epan/capture_dissectors.h>
14 #include <wsutil/pint.h>
15 #include <epan/expert.h>
16 #include "packet-ieee8023.h"
17 #include <epan/etypes.h>
18 #include <epan/prefs.h>
19 #include <epan/to_str.h>
20 #include <epan/addr_resolv.h>
21 #include <epan/proto_data.h>
22 #include <epan/conversation_table.h>
24 #include <wsutil/array.h>
26 void proto_register_vlan(void);
27 void proto_reg_handoff_vlan(void);
29 static unsigned int q_in_q_ethertype
= ETHERTYPE_QINQ_OLD
;
31 static bool vlan_summary_in_tree
= true;
39 static int vlan_version
= (int)IEEE_8021Q_2011
;
41 enum priority_drop_value
{
48 static int vlan_priority_drop
= (int)Priority_Drop_8P0D
;
50 static dissector_handle_t vlan_handle
;
51 static dissector_handle_t ethertype_handle
;
53 static capture_dissector_handle_t llc_cap_handle
;
54 static capture_dissector_handle_t ipx_cap_handle
;
56 static int proto_vlan
;
58 static int hf_vlan_cfi
;
59 static int hf_vlan_dei
;
60 static int hf_vlan_etype
;
61 static int hf_vlan_id
;
62 static int hf_vlan_id_name
;
63 static int hf_vlan_len
;
64 static int hf_vlan_priority
;
65 static int hf_vlan_priority_5
;
66 static int hf_vlan_priority_6
;
67 static int hf_vlan_priority_7
;
68 static int hf_vlan_priority_old
;
69 static int hf_vlan_trailer
;
73 static expert_field ei_vlan_len
;
74 static expert_field ei_vlan_too_many_tags
;
76 /* From Table G-2 of IEEE standard 802.1D-2004 */
77 /* Note that 0 is the default priority, but is above 1 and 2.
78 * Priority order from lowest to highest is 1,2,0,3,4,5,6,7 */
79 static const value_string pri_vals_old
[] = {
80 { 0, "Best Effort (default)" },
83 { 3, "Excellent Effort" },
84 { 4, "Controlled Load" },
85 { 5, "Video, < 100ms latency and jitter" },
86 { 6, "Voice, < 10ms latency and jitter" },
87 { 7, "Network Control" },
91 /* From Table G-2 of IEEE standard 802.1Q-2005 (and I-2 of 2011 and 2014 revisions) */
92 /* Note that 0 is still the default, but priority 2 was moved from below 0 to
93 * above it. The new order from lowest to highest is 1,0,2,3,4,5,6,7 */
94 static const value_string pri_vals
[] = {
95 { 0, "Best Effort (default)" },
97 { 2, "Excellent Effort" },
98 { 3, "Critical Applications" },
99 { 4, "Video, < 100ms latency and jitter" },
100 { 5, "Voice, < 10ms latency and jitter" },
101 { 6, "Internetwork Control" },
102 { 7, "Network Control" },
106 /* From Tables G-2,3 of IEEE standard 802.1Q-2005 (and I-2,3,7 of 2011 and 2014 revisions) */
107 static const value_string pri_vals_7
[] = {
108 { 0, "Best Effort (default)" },
110 { 2, "Excellent Effort" },
111 { 3, "Critical Applications" },
112 { 4, "Voice, < 10ms latency and jitter, Drop Eligible" },
113 { 5, "Voice, < 10ms latency and jitter" },
114 { 6, "Internetwork Control" },
115 { 7, "Network Control" },
119 /* From Tables G-2,3 of IEEE standard 802.1Q-2005 (and I-2,3,7 of 2011 and 2015 revisions) */
120 static const value_string pri_vals_6
[] = {
121 { 0, "Best Effort (default)" },
123 { 2, "Critical Applications, Drop Eligible" },
124 { 3, "Critical Applications" },
125 { 4, "Voice, < 10ms latency and jitter, Drop Eligible" },
126 { 5, "Voice, < 10ms latency and jitter" },
127 { 6, "Internetwork Control" },
128 { 7, "Network Control" },
132 /* From Tables G-2,3 of IEEE standard 802.1Q-2005 (and I-2,3,7 of 2011 and 2015 revisions) */
133 static const value_string pri_vals_5
[] = {
134 { 0, "Best Effort (default), Drop Eligible" },
135 { 1, "Best Effort (default)" },
136 { 2, "Critical Applications, Drop Eligible" },
137 { 3, "Critical Applications" },
138 { 4, "Voice, < 10ms latency and jitter, Drop Eligible" },
139 { 5, "Voice, < 10ms latency and jitter" },
140 { 6, "Internetwork Control" },
141 { 7, "Network Control" },
145 /* True is non-canonical (i.e., bit-reversed MACs like Token Ring) since usually 0 and canonical. */
146 static const true_false_string tfs_noncanonical_canonical
= { "Non-canonical", "Canonical" };
148 static const true_false_string tfs_eligible_ineligible
= { "Eligible", "Ineligible" };
150 #define VLAN_MAX_NESTED_TAGS 20
153 capture_vlan(const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header _U_
) {
154 uint16_t encap_proto
;
155 if ( !BYTES_ARE_IN_FRAME(offset
,len
,5) )
158 encap_proto
= pntoh16( &pd
[offset
+2] );
159 if ( encap_proto
<= IEEE_802_3_MAX_LEN
) {
160 if ( pd
[offset
+4] == 0xff && pd
[offset
+5] == 0xff ) {
161 return call_capture_dissector(ipx_cap_handle
, pd
,offset
+4,len
, cpinfo
, pseudo_header
);
163 return call_capture_dissector(llc_cap_handle
, pd
,offset
+4,len
, cpinfo
, pseudo_header
);
167 return try_capture_dissector("ethertype", encap_proto
, pd
, offset
+4, len
, cpinfo
, pseudo_header
);
171 columns_set_vlan(column_info
*cinfo
, uint16_t tci
)
175 uint32_to_str_buf(tci
& 0xFFF, id_str
, sizeof(id_str
));
177 if (vlan_version
< IEEE_8021Q_2011
) {
178 col_add_fstr(cinfo
, COL_INFO
,
179 "PRI: %d CFI: %d ID: %s",
180 (tci
>> 13), ((tci
>> 12) & 1), id_str
);
182 col_add_fstr(cinfo
, COL_INFO
,
183 "PRI: %d DEI: %d ID: %s",
184 (tci
>> 13), ((tci
>> 12) & 1), id_str
);
189 dissect_vlan(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
192 uint16_t tci
, vlan_id
;
193 uint16_t encap_proto
;
195 proto_tree
*vlan_tree
;
197 unsigned vlan_nested_count
;
200 int * const flags
[] = {
207 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "VLAN");
208 col_clear(pinfo
->cinfo
, COL_INFO
);
210 tci
= tvb_get_ntohs( tvb
, 0 );
211 vlan_id
= tci
& 0xFFF;
212 /* Add the VLAN Id if it's the first one*/
213 if (pinfo
->vlan_id
== 0) {
214 pinfo
->vlan_id
= vlan_id
;
217 columns_set_vlan(pinfo
->cinfo
, tci
);
221 ti
= proto_tree_add_item(tree
, proto_vlan
, tvb
, 0, 4, ENC_NA
);
222 vlan_nested_count
= p_get_proto_depth(pinfo
, proto_vlan
);
223 if (++vlan_nested_count
> VLAN_MAX_NESTED_TAGS
) {
224 expert_add_info(pinfo
, ti
, &ei_vlan_too_many_tags
);
225 return tvb_captured_length(tvb
);
227 p_set_proto_depth(pinfo
, proto_vlan
, vlan_nested_count
);
231 if (vlan_summary_in_tree
) {
232 if (vlan_version
< IEEE_8021Q_2011
) {
233 proto_item_append_text(ti
, ", PRI: %u, CFI: %u, ID: %u",
234 (tci
>> 13), ((tci
>> 12) & 1), vlan_id
);
236 proto_item_append_text(ti
, ", PRI: %u, DEI: %u, ID: %u",
237 (tci
>> 13), ((tci
>> 12) & 1), vlan_id
);
241 vlan_tree
= proto_item_add_subtree(ti
, ett_vlan
);
243 if (vlan_version
== IEEE_8021Q_1998
) {
244 hf1
= hf_vlan_priority_old
;
247 switch (vlan_priority_drop
) {
249 case Priority_Drop_8P0D
:
250 hf1
= hf_vlan_priority
;
253 case Priority_Drop_7P1D
:
254 hf1
= hf_vlan_priority_7
;
257 case Priority_Drop_6P2D
:
258 hf1
= hf_vlan_priority_6
;
261 case Priority_Drop_5P3D
:
262 hf1
= hf_vlan_priority_5
;
265 if (vlan_version
== IEEE_8021Q_2005
) {
272 proto_tree_add_bitmask_list(vlan_tree
, tvb
, 0, 2, flags
, ENC_BIG_ENDIAN
);
274 if (gbl_resolv_flags
.vlan_name
) {
275 item
= proto_tree_add_string(vlan_tree
, hf_vlan_id_name
, tvb
, 0, 2,
276 get_vlan_name(pinfo
->pool
, vlan_id
));
277 proto_item_set_generated(item
);
281 /* TODO: If the CFI is set on Ethernet (or FDDI MAC and not source routed,
282 * i.e. the RII bit in the source MAC address is 0, then a E-RIF follows.
283 * Only true before version 2011 since the CFI was replaced with DEI
284 * (Since who needs VLANs that bridge Token Ring and FDDI these days?) */
287 encap_proto
= tvb_get_ntohs(tvb
, 2);
288 if (encap_proto
<= IEEE_802_3_MAX_LEN
) {
289 /* Is there an 802.2 layer? I can tell by looking at the first 2
290 bytes after the VLAN header. If they are 0xffff, then what
291 follows the VLAN header is an IPX payload, meaning no 802.2.
292 (IPX/SPX is they only thing that can be contained inside a
293 straight 802.3 packet, so presumably the same applies for
294 Ethernet VLAN packets). A non-0xffff value means that there's an
295 802.2 layer inside the VLAN layer */
298 /* Don't throw an exception for this check (even a BoundsError) */
299 if (tvb_captured_length_remaining(tvb
, 4) >= 2) {
300 if (tvb_get_ntohs(tvb
, 4) == 0xffff) {
305 dissect_802_3(encap_proto
, is_802_2
, tvb
, 4, pinfo
, tree
, vlan_tree
,
306 hf_vlan_len
, hf_vlan_trailer
, &ei_vlan_len
, 0);
308 ethertype_data_t ethertype_data
;
310 proto_tree_add_uint(vlan_tree
, hf_vlan_etype
, tvb
, 2, 2, encap_proto
);
312 ethertype_data
.etype
= encap_proto
;
313 ethertype_data
.payload_offset
= 4;
314 ethertype_data
.fh_tree
= vlan_tree
;
315 ethertype_data
.trailer_id
= hf_vlan_trailer
;
316 ethertype_data
.fcs_len
= 0;
318 /* deinterlacing requested */
319 if(prefs
.conversation_deinterlacing_key
>0) {
320 conversation_t
*conv
;
322 uint32_t dtlc_iface
= 0;
323 uint32_t dtlc_vlan
= 0;
325 if(prefs
.conversation_deinterlacing_key
&CONV_DEINT_KEY_INTERFACE
&&
326 pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
) {
328 if(prefs
.conversation_deinterlacing_key
&CONV_DEINT_KEY_VLAN
&&
331 conv_type
= CONVERSATION_ETH_IV
;
332 dtlc_iface
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
333 dtlc_vlan
= pinfo
->vlan_id
;
335 /* look for existing conv, create one if none found */
336 conv
= find_conversation_deinterlacer(pinfo
->num
, &pinfo
->src
, &pinfo
->dst
, conv_type
,
337 dtlc_iface
, dtlc_vlan
, 0);
340 /* ETH _IN moulting into _IV */
341 conversation_new_deinterlacer(pinfo
->num
, &pinfo
->src
, &pinfo
->dst
,
342 conv_type
, dtlc_iface
, pinfo
->vlan_id
, 0);
345 // else : vlan id == 0, such thing is not expected
348 if(prefs
.conversation_deinterlacing_key
&CONV_DEINT_KEY_VLAN
&&
351 conv_type
= CONVERSATION_ETH_NV
;
353 /* look for existing conv, create one if none found */
354 conv
= find_conversation_deinterlacer(pinfo
->num
, &pinfo
->src
, &pinfo
->dst
, conv_type
,
355 dtlc_iface
, pinfo
->vlan_id
, 0);
358 /* ETH _NN moulting into _NV */
359 conversation_new_deinterlacer(pinfo
->num
, &pinfo
->src
, &pinfo
->dst
,
360 conv_type
, dtlc_iface
, pinfo
->vlan_id
, 0);
363 // else : vlan id == 0, such thing is not expected
368 call_dissector_with_data(ethertype_handle
, tvb
, pinfo
, tree
, ðertype_data
);
370 return tvb_captured_length(tvb
);
374 proto_register_vlan(void)
376 static hf_register_info hf
[] = {
377 { &hf_vlan_priority_old
,
378 { "Priority", "vlan.priority",
379 FT_UINT16
, BASE_DEC
, VALS(pri_vals_old
), 0xE000,
380 "Descriptions are recommendations from IEEE standard 802.1D-2004", HFILL
}
383 { "Priority", "vlan.priority",
384 FT_UINT16
, BASE_DEC
, VALS(pri_vals
), 0xE000,
385 "Descriptions are recommendations from IEEE standard 802.1Q-2014", HFILL
}
387 { &hf_vlan_priority_7
,
388 { "Priority", "vlan.priority",
389 FT_UINT16
, BASE_DEC
, VALS(pri_vals_7
), 0xE000,
390 "Descriptions are recommendations from IEEE standard 802.1Q-2014", HFILL
}
392 { &hf_vlan_priority_6
,
393 { "Priority", "vlan.priority",
394 FT_UINT16
, BASE_DEC
, VALS(pri_vals_6
), 0xE000,
395 "Descriptions are recommendations from IEEE standard 802.1Q-2014", HFILL
}
397 { &hf_vlan_priority_5
,
398 { "Priority", "vlan.priority",
399 FT_UINT16
, BASE_DEC
, VALS(pri_vals_5
), 0xE000,
400 "Descriptions are recommendations from IEEE standard 802.1Q-2014", HFILL
}
404 FT_BOOLEAN
, 16, TFS(&tfs_noncanonical_canonical
), 0x1000,
405 "Canonical Format Identifier", HFILL
}
409 FT_BOOLEAN
, 16, TFS(&tfs_eligible_ineligible
), 0x1000,
410 "Drop Eligible Indicator", HFILL
}
414 FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF,
418 { "Name", "vlan.id_name",
419 FT_STRING
, BASE_NONE
, NULL
, 0x0,
420 "VLAN ID Name", HFILL
}
423 { "Type", "vlan.etype",
424 FT_UINT16
, BASE_HEX
, VALS(etype_vals
), 0x0,
428 { "Length", "vlan.len",
429 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
433 { "Trailer", "vlan.trailer",
434 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
435 "VLAN Trailer", HFILL
}
439 static int *ett
[] = {
443 static ei_register_info ei
[] = {
444 { &ei_vlan_len
, { "vlan.len.past_end", PI_MALFORMED
, PI_ERROR
, "Length field value goes past the end of the payload", EXPFILL
}},
445 { &ei_vlan_too_many_tags
, { "vlan.too_many_tags", PI_UNDECODED
, PI_WARN
, "Too many nested VLAN tags", EXPFILL
}},
448 static const enum_val_t version_vals
[] = {
449 {"1998", "IEEE 802.1Q-1998", IEEE_8021Q_1998
},
450 {"2005", "IEEE 802.1Q-2005", IEEE_8021Q_2005
},
451 {"2011", "IEEE 802.1Q-2011", IEEE_8021Q_2011
},
455 static const enum_val_t priority_drop_vals
[] = {
456 {"8p0d", "8 Priorities, 0 Drop Eligible", Priority_Drop_8P0D
},
457 {"7p1d", "7 Priorities, 1 Drop Eligible", Priority_Drop_7P1D
},
458 {"6p2d", "6 Priorities, 2 Drop Eligible", Priority_Drop_6P2D
},
459 {"5p3d", "5 Priorities, 3 Drop Eligible", Priority_Drop_5P3D
},
463 module_t
*vlan_module
;
464 expert_module_t
* expert_vlan
;
466 proto_vlan
= proto_register_protocol("802.1Q Virtual LAN", "VLAN", "vlan");
467 proto_register_field_array(proto_vlan
, hf
, array_length(hf
));
468 proto_register_subtree_array(ett
, array_length(ett
));
469 expert_vlan
= expert_register_protocol(proto_vlan
);
470 expert_register_field_array(expert_vlan
, ei
, array_length(ei
));
472 vlan_module
= prefs_register_protocol(proto_vlan
, proto_reg_handoff_vlan
);
473 prefs_register_bool_preference(vlan_module
, "summary_in_tree",
474 "Show vlan summary in protocol tree",
475 "Whether the vlan summary line should be shown in the protocol tree",
476 &vlan_summary_in_tree
);
477 prefs_register_uint_preference(vlan_module
, "qinq_ethertype",
478 "802.1QinQ Ethertype (in hex)",
479 "The (hexadecimal) Ethertype used to indicate 802.1QinQ VLAN in VLAN tunneling.",
480 16, &q_in_q_ethertype
);
481 prefs_register_enum_preference(vlan_module
, "version",
482 "IEEE 802.1Q version",
483 "IEEE 802.1Q specification version used (802.1Q-1998 uses 802.1D-2004 for PRI values)",
484 &vlan_version
, version_vals
, true);
485 prefs_register_enum_preference(vlan_module
, "priority_drop",
486 "Priorities and drop eligibility",
487 "Number of priorities supported, and number of those drop eligible (not used for 802.1Q-1998)",
488 &vlan_priority_drop
, priority_drop_vals
, false);
489 vlan_handle
= register_dissector("vlan", dissect_vlan
, proto_vlan
);
493 proto_reg_handoff_vlan(void)
495 static bool prefs_initialized
= false;
496 static unsigned int old_q_in_q_ethertype
;
497 capture_dissector_handle_t vlan_cap_handle
;
499 if (!prefs_initialized
)
501 dissector_add_uint("ethertype", ETHERTYPE_VLAN
, vlan_handle
);
502 vlan_cap_handle
= create_capture_dissector_handle(capture_vlan
, proto_vlan
);
503 capture_dissector_add_uint("ethertype", ETHERTYPE_VLAN
, vlan_cap_handle
);
505 prefs_initialized
= true;
509 dissector_delete_uint("ethertype", old_q_in_q_ethertype
, vlan_handle
);
512 old_q_in_q_ethertype
= q_in_q_ethertype
;
513 ethertype_handle
= find_dissector_add_dependency("ethertype", proto_vlan
);
515 dissector_add_uint("ethertype", q_in_q_ethertype
, vlan_handle
);
517 llc_cap_handle
= find_capture_dissector("llc");
518 ipx_cap_handle
= find_capture_dissector("ipx");
522 * Editor modelines - https://www.wireshark.org/tools/modelines.html
527 * indent-tabs-mode: nil
530 * ex: set shiftwidth=2 tabstop=8 expandtab:
531 * :indentSize=2:tabSize=8:noTabs=true: