/src/wireshark/epan/dissectors/packet-bier.c
Line | Count | Source |
1 | | /* @file |
2 | | * Routines for Bit Index Explicit Replication (BIER) dissection |
3 | | * |
4 | | * Copyright 2024, John Thacker <johnthacker@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * |
12 | | * RFC 8296: https://www.rfc-editor.org/rfc/rfc8296.html |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/expert.h> |
19 | | #include <epan/prefs.h> |
20 | | |
21 | | void proto_register_bier(void); |
22 | | void proto_reg_handoff_bier(void); |
23 | | |
24 | | static int proto_bier; |
25 | | |
26 | | static int hf_bier_nibble; |
27 | | static int hf_bier_ver; |
28 | | static int hf_bier_bsl; |
29 | | static int hf_bier_entropy; |
30 | | static int hf_bier_oam; |
31 | | static int hf_bier_rsv; |
32 | | static int hf_bier_dscp; |
33 | | static int hf_bier_proto; |
34 | | static int hf_bier_bfir_id; |
35 | | static int hf_bier_bitstring; |
36 | | |
37 | | static int ett_bier; |
38 | | |
39 | | static expert_field ei_bier_too_deep; |
40 | | |
41 | | static dissector_table_t bier_subdissector_table; |
42 | | |
43 | | static dissector_handle_t bier_handle; |
44 | | |
45 | | static const value_string bier_bsl_vals[] = { |
46 | | { 1, "64 bits" }, |
47 | | { 2, "128 bits" }, |
48 | | { 3, "256 bits" }, |
49 | | { 4, "512 bits" }, |
50 | | { 5, "1024 bits" }, |
51 | | { 6, "2048 bits" }, |
52 | | { 7, "4096 bits" }, |
53 | | { 0, NULL } |
54 | | }; |
55 | | |
56 | | // https://www.iana.org/assignments/bier/bier.xhtml#bier-next-protocol-identifiers |
57 | | static const value_string bier_proto_vals[] = { |
58 | | { 0, "Reserved" }, |
59 | | { 1, "MPLS packet with downstream-assigned label at top of stack" }, |
60 | | { 2, "MPLS packet with upstream-assigned label at top of stack" }, |
61 | | { 3, "Ethernet frame" }, |
62 | | { 4, "IPv4 packet" }, |
63 | | { 5, "OAM packet" }, |
64 | | { 6, "IPv6 packet" }, |
65 | | { 7, "Payload is VXLAN encapsulated (no IP/UDP header)" }, |
66 | | { 8, "Payload is NVGRE encapsulated (no IP header)" }, |
67 | | { 9, "Payload is GENEVE encapsulated (no IP/UDP header)" }, |
68 | | { 63, "Reserved" }, |
69 | | { 0, NULL } |
70 | | }; |
71 | | |
72 | | static int |
73 | | dissect_bier(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_) |
74 | 43 | { |
75 | 43 | proto_item *ti; |
76 | 43 | proto_tree *bier_tree; |
77 | | |
78 | 43 | unsigned offset = 0; |
79 | 43 | uint32_t proto; |
80 | 43 | tvbuff_t *next_tvb; |
81 | | |
82 | 43 | if (tvb_reported_length(tvb) < 16) { |
83 | 9 | return 0; |
84 | 9 | } |
85 | | |
86 | 34 | if (tvb_captured_length(tvb) < 2) { |
87 | 1 | return 0; |
88 | 1 | } |
89 | | |
90 | | /* This nibble is ignored in non-MPLS */ |
91 | 33 | if (((tvb_get_uint8(tvb, 0) >> 4) & 0xF) != 0x5) { |
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | 33 | uint8_t bsl = (tvb_get_uint8(tvb, 1) >> 4) & 0xF; |
96 | 33 | if (bsl == 0 || bsl > 7) { |
97 | 13 | return 0; |
98 | 13 | } |
99 | | |
100 | 20 | unsigned bitstring_length = 1 << (bsl + 2); |
101 | | |
102 | 20 | if (tvb_reported_length_remaining(tvb, 8) < bitstring_length) { |
103 | 5 | return 0; |
104 | 5 | } |
105 | | |
106 | 15 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "BIER"); |
107 | 15 | col_clear(pinfo->cinfo, COL_INFO); |
108 | | |
109 | 15 | ti = proto_tree_add_item(tree, proto_bier, tvb, offset, 8 + bitstring_length, ENC_NA); |
110 | | |
111 | 15 | bier_tree = proto_item_add_subtree(ti, ett_bier); |
112 | | |
113 | 15 | proto_tree_add_item(bier_tree, hf_bier_nibble, tvb, offset, 1, ENC_NA); |
114 | 15 | proto_tree_add_item(bier_tree, hf_bier_ver, tvb, offset, 1, ENC_NA); |
115 | 15 | offset += 1; |
116 | | |
117 | 15 | proto_tree_add_item(bier_tree, hf_bier_bsl, tvb, offset, 1, ENC_NA); |
118 | 15 | proto_tree_add_item(bier_tree, hf_bier_entropy, tvb, offset, 3, ENC_BIG_ENDIAN); |
119 | 15 | offset += 3; |
120 | | |
121 | 15 | proto_tree_add_item(bier_tree, hf_bier_oam, tvb, offset, 1, ENC_NA); |
122 | 15 | proto_tree_add_item(bier_tree, hf_bier_rsv, tvb, offset, 1, ENC_NA); |
123 | | /* DSCP field unused in MPLS; may be as IP DSCP in non-MPLS. */ |
124 | 15 | proto_tree_add_item(bier_tree, hf_bier_dscp, tvb, offset, 2, ENC_BIG_ENDIAN); |
125 | 15 | offset += 1; |
126 | | |
127 | 15 | proto_tree_add_item_ret_uint(bier_tree, hf_bier_proto, tvb, offset, 1, ENC_NA, &proto); |
128 | 15 | col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pinfo->pool, proto, bier_proto_vals, "Unknown (0x%02x)")); |
129 | 15 | offset += 1; |
130 | | |
131 | 15 | proto_tree_add_item(bier_tree, hf_bier_bfir_id, tvb, offset, 2, ENC_BIG_ENDIAN); |
132 | 15 | offset += 2; |
133 | | |
134 | 15 | proto_tree_add_item(bier_tree, hf_bier_bitstring, tvb, offset, bitstring_length, ENC_NA); |
135 | 15 | offset += bitstring_length; |
136 | | |
137 | 15 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
138 | | /* MPLS can carry BIER again; stop before the layer limit */ |
139 | 15 | if (wmem_list_count(pinfo->layers) + 16 >= prefs.gui_max_tree_depth) { |
140 | 0 | proto_tree_add_expert_remaining(bier_tree, pinfo, &ei_bier_too_deep, next_tvb, 0); |
141 | 0 | return tvb_captured_length(tvb); |
142 | 0 | } |
143 | 15 | if (!dissector_try_uint(bier_subdissector_table, proto, next_tvb, pinfo, tree)) { |
144 | 2 | call_data_dissector(next_tvb, pinfo, tree); |
145 | 2 | } |
146 | | |
147 | 15 | return tvb_captured_length(tvb); |
148 | 15 | } |
149 | | |
150 | | void |
151 | | proto_register_bier(void) |
152 | 16 | { |
153 | 16 | static hf_register_info hf[] = { |
154 | 16 | { |
155 | 16 | &hf_bier_nibble, |
156 | 16 | { |
157 | 16 | "Nibble", "bier.nibble", FT_UINT8, |
158 | 16 | BASE_HEX, NULL, 0xF0, NULL, HFILL |
159 | 16 | } |
160 | 16 | }, |
161 | 16 | { |
162 | 16 | &hf_bier_ver, |
163 | 16 | { |
164 | 16 | "Version", "bier.ver", FT_UINT8, |
165 | 16 | BASE_DEC, NULL, 0x0F, NULL, HFILL |
166 | 16 | } |
167 | 16 | }, |
168 | 16 | { |
169 | 16 | &hf_bier_bsl, |
170 | 16 | { |
171 | 16 | "BitString Length", "bier.bsl", FT_UINT8, |
172 | 16 | BASE_DEC, VALS(bier_bsl_vals), 0xF0, NULL, HFILL |
173 | 16 | } |
174 | 16 | }, |
175 | 16 | { |
176 | 16 | &hf_bier_entropy, |
177 | 16 | { |
178 | 16 | "Entropy", "bier.entropy", FT_UINT24, |
179 | 16 | BASE_HEX, NULL, 0x0FFFFF, NULL, HFILL |
180 | 16 | } |
181 | 16 | }, |
182 | 16 | { |
183 | 16 | &hf_bier_oam, |
184 | 16 | { |
185 | 16 | "OAM", "bier.oam", FT_UINT8, |
186 | 16 | BASE_HEX, NULL, 0xC0, NULL, HFILL |
187 | 16 | } |
188 | 16 | }, |
189 | 16 | { |
190 | 16 | &hf_bier_rsv, |
191 | 16 | { |
192 | 16 | "Rsv", "bier.rsv", FT_UINT8, |
193 | 16 | BASE_HEX, NULL, 0x30, NULL, HFILL |
194 | 16 | } |
195 | 16 | }, |
196 | 16 | { |
197 | 16 | &hf_bier_dscp, |
198 | 16 | { |
199 | 16 | "DSCP", "bier.dscp", FT_UINT16, |
200 | 16 | BASE_HEX, NULL, 0x0FC0, NULL, HFILL |
201 | 16 | } |
202 | 16 | }, |
203 | 16 | { |
204 | 16 | &hf_bier_proto, |
205 | 16 | { |
206 | 16 | "Next Protocol", "bier.proto", FT_UINT8, |
207 | 16 | BASE_HEX, VALS(bier_proto_vals), 0x3F, NULL, HFILL |
208 | 16 | } |
209 | 16 | }, |
210 | 16 | { |
211 | 16 | &hf_bier_bfir_id, |
212 | 16 | { |
213 | 16 | "BFIR-id", "bier.bfir-id", FT_UINT16, |
214 | 16 | BASE_DEC, NULL, 0x0, NULL, HFILL |
215 | 16 | } |
216 | 16 | }, |
217 | 16 | { |
218 | 16 | &hf_bier_bitstring, |
219 | 16 | { |
220 | 16 | "BitString", "bier.bitstring", FT_BYTES, |
221 | 16 | BASE_NONE, NULL, 0x0, NULL, HFILL |
222 | 16 | } |
223 | 16 | }, |
224 | 16 | }; |
225 | | |
226 | 16 | static int *ett[] = { |
227 | 16 | &ett_bier |
228 | 16 | }; |
229 | | |
230 | 16 | static ei_register_info ei[] = { |
231 | 16 | { &ei_bier_too_deep, { "bier.too_deep", PI_UNDECODED, PI_WARN, "Payload nested too deep, not dissected", EXPFILL }}, |
232 | 16 | }; |
233 | | |
234 | 16 | expert_module_t *expert_bier; |
235 | | |
236 | 16 | proto_bier = |
237 | 16 | proto_register_protocol("Bit Index Explicit Replication", "BIER", "bier"); |
238 | | |
239 | 16 | proto_register_field_array(proto_bier, hf, array_length(hf)); |
240 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
241 | 16 | expert_bier = expert_register_protocol(proto_bier); |
242 | 16 | expert_register_field_array(expert_bier, ei, array_length(ei)); |
243 | 16 | bier_handle = register_dissector_with_description("bier.mpls", "BIER encapsulated in MPLS", dissect_bier, proto_bier); |
244 | | |
245 | 16 | bier_subdissector_table = register_dissector_table("bier.proto", |
246 | 16 | "BIER Next Protocol", proto_bier, FT_UINT8, BASE_DEC); |
247 | 16 | } |
248 | | |
249 | | void |
250 | | proto_reg_handoff_bier(void) |
251 | 16 | { |
252 | 16 | dissector_handle_t mpls_handle = find_dissector_add_dependency("mpls", proto_bier); |
253 | | |
254 | 16 | dissector_add_for_decode_as("mpls.label", bier_handle); |
255 | | |
256 | 16 | dissector_add_uint("mpls.pfn", 5, bier_handle); |
257 | | |
258 | 16 | dissector_add_uint("bier.proto", 1, mpls_handle); |
259 | 16 | dissector_add_uint("bier.proto", 2, mpls_handle); |
260 | 16 | dissector_add_uint("bier.proto", 3, find_dissector_add_dependency("eth_maybefcs", proto_bier)); |
261 | 16 | dissector_add_uint("bier.proto", 4, find_dissector_add_dependency("ip", proto_bier)); |
262 | | /* 5 is BIER OAM - https://datatracker.ietf.org/doc/draft-ietf-bier-ping/ */ |
263 | 16 | dissector_add_uint("bier.proto", 6, find_dissector_add_dependency("ipv6", proto_bier)); |
264 | 16 | dissector_add_uint("bier.proto", 7, find_dissector_add_dependency("vxlan", proto_bier)); |
265 | 16 | dissector_add_uint("bier.proto", 8, find_dissector_add_dependency("gre", proto_bier)); |
266 | 16 | dissector_add_uint("bier.proto", 9, find_dissector_add_dependency("geneve", proto_bier)); |
267 | 16 | } |