2 * Routines for ethernet PW dissection: it should conform to RFC 4448.
6 * Francesco Fondelli <francesco dot fondelli, gmail dot com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/addr_resolv.h>
19 #include <epan/etypes.h>
20 #include <epan/dissectors/packet-llc.h>
22 #include "packet-mpls.h"
24 void proto_register_pw_eth(void);
25 void proto_reg_handoff_pw_eth(void);
27 static int proto_pw_eth_cw
;
28 static int proto_pw_eth_nocw
;
29 static int proto_pw_eth_heuristic
;
31 static int ett_pw_eth
;
34 static int hf_pw_eth_cw
;
35 static int hf_pw_eth_cw_sequence_number
;
37 static dissector_handle_t eth_withoutfcs_handle
;
38 static dissector_handle_t pw_eth_handle_cw
;
39 static dissector_handle_t pw_eth_handle_nocw
;
40 static dissector_handle_t pw_eth_handle_heuristic
;
43 dissect_pw_eth_cw(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
46 uint16_t sequence_number
;
48 if (tvb_reported_length_remaining(tvb
, 0) < 4) {
52 if (dissect_try_cw_first_nibble(tvb
, pinfo
, tree
))
53 return tvb_captured_length(tvb
);
55 sequence_number
= tvb_get_ntohs(tvb
, 2);
58 proto_tree
*pw_eth_tree
;
61 ti
= proto_tree_add_boolean(tree
, hf_pw_eth_cw
,
63 proto_item_set_hidden(ti
);
64 ti
= proto_tree_add_item(tree
, proto_pw_eth_cw
,
66 pw_eth_tree
= proto_item_add_subtree(ti
, ett_pw_eth
);
68 proto_tree_add_uint_format(pw_eth_tree
,
69 hf_pw_eth_cw_sequence_number
,
70 tvb
, 2, 2, sequence_number
,
71 "Sequence Number: %d",
75 next_tvb
= tvb_new_subset_remaining(tvb
, 4);
77 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
80 return tvb_captured_length(tvb
);
84 dissect_pw_eth_nocw(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
90 ti
= proto_tree_add_boolean(tree
, hf_pw_eth
, tvb
, 0, 0, true);
91 proto_item_set_hidden(ti
);
94 next_tvb
= tvb_new_subset_remaining(tvb
, 0);
95 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
97 return tvb_captured_length(tvb
);
101 * FF: this function returns true if the first 12 bytes in tvb looks like
102 * two valid ethernet addresses. false otherwise.
105 looks_like_plain_eth(tvbuff_t
*tvb
, int offset
)
107 const char *manuf_name_da
;
108 const char *manuf_name_sa
;
112 /* Don't throw an exception. If the packet is truncated, you lose. */
113 if (tvb_captured_length_remaining(tvb
, offset
) < 14) {
117 /* Copy the source and destination addresses, as tvb_get_manuf_name_if_known
118 * only uses the first three bytes (it's for an OUI in, e.g., IEEE 802.11),
119 * and returns NULL for MA-M and MA-S.
121 uint8_t da
[6], sa
[6];
122 tvb_memcpy(tvb
, da
, offset
, 6);
123 /* da[0] & 0x2 is the U/L bit; if it's set, none of this helps. (#13039) */
125 // U/L bit; locally assigned addresses are a less solid heuristic
128 manuf_name_da
= get_manuf_name_if_known(da
, 6);
129 if (!manuf_name_da
) {
130 /* Try looking for an exact match in the ethers file. */
131 manuf_name_da
= get_ether_name_if_known(da
);
132 if (!manuf_name_da
) {
139 tvb_memcpy(tvb
, sa
, offset
, 6);
141 // Group bit should not be set on source
145 // U/L bit; locally assigned addresses are a less solid heuristic
148 manuf_name_sa
= get_manuf_name_if_known(sa
, 6);
149 if (!manuf_name_sa
) {
150 manuf_name_sa
= get_ether_name_if_known(sa
);
151 if (!manuf_name_sa
) {
157 etype
= tvb_get_ntohs(tvb
, offset
);
159 if (etype
> IEEE_802_3_MAX_LEN
) {
160 if (etype
< ETHERNET_II_MIN_LEN
) {
164 if (!try_val_to_str(etype
, etype_vals
)) {
169 /* XXX - There are unusual cases like Cisco ISL, Novell raw 802.3
170 * for IPX/SPX, etc. See packet-eth capture_eth()
172 if (tvb_reported_length_remaining(tvb
, offset
) < etype
) {
176 if (tvb_captured_length_remaining(tvb
, offset
) < 3) {
180 sap
= tvb_get_uint8(tvb
, offset
);
181 if (!try_val_to_str(sap
, sap_vals
)) {
185 sap
= tvb_get_uint8(tvb
, offset
);
186 if (!try_val_to_str(sap
, sap_vals
)) {
189 /* We could go deeper, and see if this looks like SNAP if the dsap
190 * and ssap are both 0xAA (the common case).
198 dissect_pw_eth_heuristic(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
201 * RFC 8469 states that that both ingress and egress SHOULD support the PW
202 * CW, and if they do, the CW MUST be used. So it looks equally likely to
203 * have the CW as not, assume CW.
205 uint8_t first_nibble
= (tvb_get_uint8(tvb
, 0) >> 4) & 0x0F;
207 if (first_nibble
== 0) {
208 if (looks_like_plain_eth(tvb
, 4) >= looks_like_plain_eth(tvb
, 0)) {
209 call_dissector(pw_eth_handle_cw
, tvb
, pinfo
, tree
);
211 call_dissector(pw_eth_handle_nocw
, tvb
, pinfo
, tree
);
214 call_dissector(pw_eth_handle_nocw
, tvb
, pinfo
, tree
);
216 return tvb_captured_length(tvb
);
220 dissect_pw_eth_nocw_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
222 if (!looks_like_plain_eth(tvb
, 0)) {
225 dissect_pw_eth_nocw(tvb
, pinfo
, tree
, data
);
230 proto_register_pw_eth(void)
232 static hf_register_info hf
[] = {
238 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
244 "PW Control Word (ethernet)",
245 "pweth.cw", FT_BOOLEAN
,
246 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
250 &hf_pw_eth_cw_sequence_number
,
252 "PW sequence number (ethernet)",
253 "pweth.cw.sequence_number", FT_UINT16
,
254 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
259 static int *ett
[] = {
264 proto_register_protocol("PW Ethernet Control Word",
265 "Ethernet PW (with CW)",
268 proto_register_protocol("Ethernet PW (no CW)", /* not displayed */
269 "Ethernet PW (no CW)",
271 proto_pw_eth_heuristic
=
272 proto_register_protocol("Ethernet PW (CW heuristic)", /* not disp. */
273 "Ethernet PW (CW heuristic)",
275 proto_register_field_array(proto_pw_eth_cw
, hf
, array_length(hf
));
276 proto_register_subtree_array(ett
, array_length(ett
));
277 pw_eth_handle_cw
= register_dissector("pw_eth_cw", dissect_pw_eth_cw
, proto_pw_eth_cw
);
278 pw_eth_handle_nocw
= register_dissector("pw_eth_nocw", dissect_pw_eth_nocw
, proto_pw_eth_nocw
);
279 pw_eth_handle_heuristic
= register_dissector("pw_eth_heuristic", dissect_pw_eth_heuristic
,
280 proto_pw_eth_heuristic
);
284 proto_reg_handoff_pw_eth(void)
286 heur_dissector_add("mpls", dissect_pw_eth_nocw_heur
,
287 "Ethernet PW (no CW)", "pwethnocw", proto_pw_eth_nocw
,
289 eth_withoutfcs_handle
= find_dissector_add_dependency("eth_withoutfcs", proto_pw_eth_cw
);
291 dissector_add_for_decode_as("mpls.label", pw_eth_handle_cw
);
292 dissector_add_for_decode_as("mpls.label", pw_eth_handle_nocw
);
294 dissector_add_for_decode_as("mpls.label", pw_eth_handle_heuristic
);
296 dissector_add_for_decode_as("mpls.pfn", pw_eth_handle_cw
);
297 dissector_add_for_decode_as("mpls.pfn", pw_eth_handle_nocw
);
301 * Editor modelines - https://www.wireshark.org/tools/modelines.html
306 * indent-tabs-mode: nil
309 * vi: set shiftwidth=4 tabstop=8 expandtab:
310 * :indentSize=4:tabSize=8:noTabs=true: