Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-pw-eth.c
blob524dbe696fe62b72d6c950c83d22d75ace5a57e7
1 /* packet-pw-eth.c
2 * Routines for ethernet PW dissection: it should conform to RFC 4448.
4 * Copyright 2008 _FF_
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
15 #include "config.h"
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;
33 static int hf_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;
42 static int
43 dissect_pw_eth_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
45 tvbuff_t *next_tvb;
46 uint16_t sequence_number;
48 if (tvb_reported_length_remaining(tvb, 0) < 4) {
49 return 0;
52 if (dissect_try_cw_first_nibble(tvb, pinfo, tree))
53 return tvb_captured_length(tvb);
55 sequence_number = tvb_get_ntohs(tvb, 2);
57 if (tree) {
58 proto_tree *pw_eth_tree;
59 proto_item *ti;
61 ti = proto_tree_add_boolean(tree, hf_pw_eth_cw,
62 tvb, 0, 0, true);
63 proto_item_set_hidden(ti);
64 ti = proto_tree_add_item(tree, proto_pw_eth_cw,
65 tvb, 0, 4, ENC_NA);
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",
72 sequence_number);
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);
83 static int
84 dissect_pw_eth_nocw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
86 tvbuff_t *next_tvb;
88 if (tree) {
89 proto_item *ti;
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.
104 static int
105 looks_like_plain_eth(tvbuff_t *tvb, int offset)
107 const char *manuf_name_da;
108 const char *manuf_name_sa;
109 uint16_t etype;
110 int ret = 2;
112 /* Don't throw an exception. If the packet is truncated, you lose. */
113 if (tvb_captured_length_remaining(tvb, offset) < 14) {
114 return 0;
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) */
124 if (da[0] & 0x2) {
125 // U/L bit; locally assigned addresses are a less solid heuristic
126 ret = 1;
127 } else {
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) {
133 return 0;
137 offset += 6;
139 tvb_memcpy(tvb, sa, offset, 6);
140 if (sa[0] & 0x1) {
141 // Group bit should not be set on source
142 return 0;
144 if (sa[0] & 0x2) {
145 // U/L bit; locally assigned addresses are a less solid heuristic
146 ret = 1;
147 } else {
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) {
152 return 0;
156 offset += 6;
157 etype = tvb_get_ntohs(tvb, offset);
159 if (etype > IEEE_802_3_MAX_LEN) {
160 if (etype < ETHERNET_II_MIN_LEN) {
161 return 0;
164 if (!try_val_to_str(etype, etype_vals)) {
165 return 0;
167 } else {
168 offset += 2;
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) {
173 return 0;
176 if (tvb_captured_length_remaining(tvb, offset) < 3) {
177 return 0;
179 uint8_t sap;
180 sap = tvb_get_uint8(tvb, offset);
181 if (!try_val_to_str(sap, sap_vals)) {
182 return 0;
184 offset += 1;
185 sap = tvb_get_uint8(tvb, offset);
186 if (!try_val_to_str(sap, sap_vals)) {
187 return 0;
189 /* We could go deeper, and see if this looks like SNAP if the dsap
190 * and ssap are both 0xAA (the common case).
194 return ret;
197 static int
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);
210 } else {
211 call_dissector(pw_eth_handle_nocw, tvb, pinfo, tree);
213 } else {
214 call_dissector(pw_eth_handle_nocw, tvb, pinfo, tree);
216 return tvb_captured_length(tvb);
219 static bool
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)) {
223 return false;
225 dissect_pw_eth_nocw(tvb, pinfo, tree, data);
226 return true;
229 void
230 proto_register_pw_eth(void)
232 static hf_register_info hf[] = {
234 &hf_pw_eth,
236 "PW (ethernet)",
237 "pweth", FT_BOOLEAN,
238 BASE_NONE, NULL, 0x0, NULL, HFILL
242 &hf_pw_eth_cw,
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[] = {
260 &ett_pw_eth
263 proto_pw_eth_cw =
264 proto_register_protocol("PW Ethernet Control Word",
265 "Ethernet PW (with CW)",
266 "pwethcw");
267 proto_pw_eth_nocw =
268 proto_register_protocol("Ethernet PW (no CW)", /* not displayed */
269 "Ethernet PW (no CW)",
270 "pwethnocw");
271 proto_pw_eth_heuristic =
272 proto_register_protocol("Ethernet PW (CW heuristic)", /* not disp. */
273 "Ethernet PW (CW heuristic)",
274 "pwethheuristic");
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);
283 void
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,
288 HEURISTIC_ENABLE);
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
303 * Local variables:
304 * c-basic-offset: 4
305 * tab-width: 8
306 * indent-tabs-mode: nil
307 * End:
309 * vi: set shiftwidth=4 tabstop=8 expandtab:
310 * :indentSize=4:tabSize=8:noTabs=true: