/src/wireshark/epan/dissectors/packet-auto_rp.c
Line | Count | Source |
1 | | /* packet-auto_rp.c |
2 | | * Routines for the Cisco Auto-RP protocol |
3 | | * ftp://ftpeng.cisco.com/ftp/ipmulticast/specs/pim-autorp-spec01.txt |
4 | | * |
5 | | * Heikki Vatiainen <hessu@cs.tut.fi> |
6 | | * |
7 | | * Wireshark - Network traffic analyzer |
8 | | * By Gerald Combs <gerald@wireshark.org> |
9 | | * Copyright 1998 Gerald Combs |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | |
16 | | #include <epan/packet.h> |
17 | | #include <epan/to_str.h> |
18 | | |
19 | | #include <wsutil/str_util.h> |
20 | | |
21 | | void proto_register_auto_rp(void); |
22 | | void proto_reg_handoff_auto_rp(void); |
23 | | |
24 | | static dissector_handle_t auto_rp_handle; |
25 | | |
26 | | static int proto_auto_rp; |
27 | | static int ett_auto_rp; |
28 | | static int ett_auto_rp_ver_type; |
29 | | static int ett_auto_rp_map; |
30 | | static int ett_auto_rp_group; |
31 | | |
32 | | static int hf_auto_rp_version; |
33 | | static int hf_auto_rp_type; |
34 | | static int hf_auto_rp_count; |
35 | | static int hf_auto_rp_holdtime; |
36 | | static int hf_auto_rp_pim_ver; |
37 | | static int hf_auto_rp_rp_addr; |
38 | | static int hf_auto_rp_prefix_sgn; |
39 | | static int hf_auto_rp_mask_len; |
40 | | static int hf_auto_rp_group_prefix; |
41 | | static int hf_auto_rp_reserved; |
42 | | static int hf_auto_rp_trailing_junk; |
43 | | static int hf_auto_rp_group_num; |
44 | | |
45 | 16 | #define UDP_PORT_PIM_RP_DISC 496 |
46 | | |
47 | | struct auto_rp_fixed_hdr { |
48 | 16 | #define AUTO_RP_VERSION_MASK 0xf0 |
49 | 16 | #define AUTO_RP_TYPE_MASK 0x0f |
50 | | uint8_t ver_type; /* pim-autorp-spec01.txt defines version 1+ */ |
51 | | uint8_t rp_count; /* Number of struct auto_rp_maps that follow the this header */ |
52 | | uint16_t holdtime; /* Time in seconds this announcement is valid. 0 equals forever */ |
53 | | uint32_t reserved; |
54 | | }; |
55 | | |
56 | | struct auto_rp_map_hdr { |
57 | | uint32_t rp_address; /* The unicast IPv4 address of this RP */ |
58 | 16 | #define AUTO_RP_PIM_VER_MASK 0x03 |
59 | | uint8_t pim_version; /* RP's highest PIM version. 2-bit field */ |
60 | | uint8_t group_count; /* Number of encoded group addresses that follow this header */ |
61 | | }; |
62 | | |
63 | | struct auto_rp_enc_grp_hdr { /* Encoded group address */ |
64 | 397 | #define AUTO_RP_SIGN_MASK 0x01 |
65 | | uint8_t prefix_sgn; /* 0 positive, 1 negative group prefix */ |
66 | | uint8_t mask_len; /* Length of group prefix */ |
67 | | uint32_t addr; /* Group prefix */ |
68 | | }; |
69 | | |
70 | | #define AUTO_RP_VER_1PLUS 1 |
71 | | static const value_string auto_rp_ver_vals[] = { |
72 | | {AUTO_RP_VER_1PLUS, "1 or 1+"}, |
73 | | {0, NULL} |
74 | | }; |
75 | | |
76 | | #define AUTO_RP_TYPE_ANNOUNCEMENT 1 |
77 | | #define AUTO_RP_TYPE_MAPPING 2 |
78 | | static const value_string auto_rp_type_vals[] = { |
79 | | {AUTO_RP_TYPE_ANNOUNCEMENT, "RP announcement"}, |
80 | | {AUTO_RP_TYPE_MAPPING, "RP mapping"}, |
81 | | {0, NULL} |
82 | | }; |
83 | | |
84 | | #define AUTO_RP_PIM_VERSION_UNKNOWN 0x00 |
85 | | #define AUTO_RP_PIM_VERSION_1 0x01 |
86 | | #define AUTO_RP_PIM_VERSION_2 0x02 |
87 | | #define AUTO_RP_PIM_VERSION_DUAL 0x03 |
88 | | static const value_string auto_rp_pim_ver_vals[] = { |
89 | | {AUTO_RP_PIM_VERSION_UNKNOWN, "Version unknown"}, |
90 | | {AUTO_RP_PIM_VERSION_1, "Version 1"}, |
91 | | {AUTO_RP_PIM_VERSION_2, "Version 2"}, |
92 | | {AUTO_RP_PIM_VERSION_DUAL, "Dual version 1 and 2"}, |
93 | | {0, NULL} |
94 | | }; |
95 | | |
96 | | #define AUTO_RP_GROUP_MASK_SIGN_POS 0 |
97 | | #define AUTO_RP_GROUP_MASK_SIGN_NEG 1 |
98 | | static const value_string auto_rp_mask_sign_vals[] = { |
99 | | {AUTO_RP_GROUP_MASK_SIGN_POS, "Positive group prefix"}, |
100 | | {AUTO_RP_GROUP_MASK_SIGN_NEG, "Negative group prefix"}, |
101 | | {0, NULL} |
102 | | }; |
103 | | |
104 | | static int do_auto_rp_map(wmem_allocator_t *scope, tvbuff_t *tvb, unsigned offset, proto_tree *auto_rp_tree); |
105 | | |
106 | | static int dissect_auto_rp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
107 | 28 | { |
108 | 28 | uint8_t ver_type, rp_count; |
109 | | |
110 | 28 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Auto-RP"); |
111 | 28 | col_clear(pinfo->cinfo, COL_INFO); |
112 | | |
113 | 28 | ver_type = tvb_get_uint8(tvb, 0); |
114 | 28 | rp_count = tvb_get_uint8(tvb, 1); |
115 | 28 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s (v%s) for %u RP%s", |
116 | 28 | val_to_str_const(lo_nibble(ver_type), auto_rp_type_vals, "Unknown"), |
117 | 28 | val_to_str_const(hi_nibble(ver_type), auto_rp_ver_vals, "Unknown"), |
118 | 28 | rp_count, plurality(rp_count, "", "s")); |
119 | | |
120 | 28 | if (tree) { |
121 | 28 | proto_item *ti; |
122 | 28 | proto_tree *auto_rp_tree, *ver_type_tree; |
123 | 28 | int i, offset; |
124 | 28 | uint16_t holdtime; |
125 | | |
126 | 28 | offset = 0; |
127 | 28 | ti = proto_tree_add_item(tree, proto_auto_rp, tvb, offset, -1, ENC_NA); |
128 | 28 | auto_rp_tree = proto_item_add_subtree(ti, ett_auto_rp); |
129 | | |
130 | 28 | ver_type_tree = proto_tree_add_subtree_format(auto_rp_tree, tvb, offset, 1, |
131 | 28 | ett_auto_rp_ver_type, NULL, "Version: %s, Packet type: %s", |
132 | 28 | val_to_str_const(hi_nibble(ver_type), auto_rp_ver_vals, "Unknown"), |
133 | 28 | val_to_str_const(lo_nibble(ver_type), auto_rp_type_vals, "Unknown")); |
134 | 28 | proto_tree_add_uint(ver_type_tree, hf_auto_rp_version, tvb, offset, 1, ver_type); |
135 | 28 | proto_tree_add_uint(ver_type_tree, hf_auto_rp_type, tvb, offset, 1, ver_type); |
136 | 28 | offset++; |
137 | | |
138 | 28 | proto_tree_add_uint(auto_rp_tree, hf_auto_rp_count, tvb, offset, 1, rp_count); |
139 | 28 | offset++; |
140 | | |
141 | 28 | holdtime = tvb_get_ntohs(tvb, offset); |
142 | 28 | proto_tree_add_uint_format_value(auto_rp_tree, hf_auto_rp_holdtime, tvb, offset, 2, holdtime, |
143 | 28 | "%u second%s", holdtime, plurality(holdtime, "", "s")); |
144 | 28 | offset+=2; |
145 | | |
146 | 28 | proto_tree_add_item(auto_rp_tree, hf_auto_rp_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); |
147 | 28 | offset+=4; |
148 | | |
149 | 182 | for (i = 0; i < rp_count; i++) |
150 | 154 | offset = do_auto_rp_map(pinfo->pool, tvb, offset, auto_rp_tree); |
151 | | |
152 | 28 | if (tvb_reported_length_remaining(tvb, offset) > 0) |
153 | 2 | proto_tree_add_item(tree, hf_auto_rp_trailing_junk, tvb, offset, -1, ENC_NA); |
154 | 28 | } |
155 | | |
156 | 28 | return tvb_captured_length(tvb); |
157 | 28 | } |
158 | | |
159 | | /* |
160 | | * Handles one Auto-RP map entry. Returns the new offset. |
161 | | */ |
162 | | static int do_auto_rp_map(wmem_allocator_t *scope, tvbuff_t *tvb, unsigned offset, proto_tree *auto_rp_tree) |
163 | 154 | { |
164 | 154 | proto_tree *map_tree; |
165 | 154 | uint8_t group_count; |
166 | 154 | int i; |
167 | | |
168 | 154 | group_count = tvb_get_uint8(tvb, offset + 5); |
169 | | |
170 | | /* sizeof map header + n * sizeof encoded group addresses */ |
171 | 154 | map_tree = proto_tree_add_subtree_format(auto_rp_tree, tvb, offset, 6 + group_count * 6, |
172 | 154 | ett_auto_rp_map, NULL, |
173 | 154 | "RP %s: %u group%s", tvb_ip_to_str(scope, tvb, offset), |
174 | 154 | group_count, plurality(group_count, "", "s")); |
175 | | |
176 | 154 | proto_tree_add_item(map_tree, hf_auto_rp_rp_addr, tvb, offset, 4, ENC_BIG_ENDIAN); |
177 | 154 | offset += 4; |
178 | 154 | proto_tree_add_item(map_tree, hf_auto_rp_pim_ver, tvb, offset, 1, ENC_BIG_ENDIAN); |
179 | 154 | offset++; |
180 | 154 | proto_tree_add_uint(map_tree, hf_auto_rp_group_num, tvb, offset, 1, group_count); |
181 | 154 | offset++; |
182 | | |
183 | 535 | for (i = 0; i < group_count; i++) { |
184 | 381 | proto_tree *grp_tree; |
185 | 381 | uint8_t sign, mask_len; |
186 | | |
187 | 381 | sign = tvb_get_uint8(tvb, offset); |
188 | 381 | mask_len = tvb_get_uint8(tvb, offset + 1); |
189 | 381 | grp_tree = proto_tree_add_subtree_format(map_tree, tvb, offset, 6, |
190 | 381 | ett_auto_rp_group, NULL, "Group %s/%u (%s)", |
191 | 381 | tvb_ip_to_str(scope, tvb, offset + 2), mask_len, |
192 | 381 | val_to_str_const(sign&AUTO_RP_SIGN_MASK, auto_rp_mask_sign_vals, "")); |
193 | | |
194 | 381 | proto_tree_add_uint(grp_tree, hf_auto_rp_prefix_sgn, tvb, offset, 1, sign); |
195 | 381 | offset++; |
196 | 381 | proto_tree_add_uint(grp_tree, hf_auto_rp_mask_len, tvb, offset, 1, mask_len); |
197 | 381 | offset++; |
198 | 381 | proto_tree_add_item(grp_tree, hf_auto_rp_group_prefix, tvb, offset, 4, ENC_BIG_ENDIAN); |
199 | 381 | offset += 4; |
200 | | |
201 | 381 | } |
202 | | |
203 | 154 | return offset; |
204 | 154 | } |
205 | | |
206 | | void proto_register_auto_rp(void) |
207 | 16 | { |
208 | 16 | static hf_register_info hf[] = { |
209 | 16 | { &hf_auto_rp_version, |
210 | 16 | {"Protocol version", "auto_rp.version", |
211 | 16 | FT_UINT8, BASE_DEC, VALS(auto_rp_ver_vals), AUTO_RP_VERSION_MASK, |
212 | 16 | "Auto-RP protocol version", HFILL }}, |
213 | | |
214 | 16 | { &hf_auto_rp_type, |
215 | 16 | {"Packet type", "auto_rp.type", |
216 | 16 | FT_UINT8, BASE_DEC, VALS(auto_rp_type_vals), AUTO_RP_TYPE_MASK, |
217 | 16 | "Auto-RP packet type", HFILL }}, |
218 | | |
219 | 16 | { &hf_auto_rp_count, |
220 | 16 | {"RP count", "auto_rp.rp_count", |
221 | 16 | FT_UINT8, BASE_DEC, NULL, 0, |
222 | 16 | "The number of RP addresses contained in this message", HFILL }}, |
223 | | |
224 | 16 | { &hf_auto_rp_group_num, |
225 | 16 | {"Number of groups this RP maps to", "auto_rp.group_num", |
226 | 16 | FT_UINT8, BASE_DEC, NULL, 0, |
227 | 16 | NULL, HFILL }}, |
228 | | |
229 | 16 | { &hf_auto_rp_holdtime, |
230 | 16 | {"Holdtime", "auto_rp.holdtime", |
231 | 16 | FT_UINT16, BASE_DEC, NULL, 0, |
232 | 16 | "The amount of time in seconds this announcement is valid", HFILL }}, |
233 | | |
234 | 16 | { &hf_auto_rp_pim_ver, |
235 | 16 | {"Version", "auto_rp.pim_ver", |
236 | 16 | FT_UINT8, BASE_DEC, VALS(auto_rp_pim_ver_vals), AUTO_RP_PIM_VER_MASK, |
237 | 16 | "RP's highest PIM version", HFILL }}, |
238 | | |
239 | 16 | { &hf_auto_rp_rp_addr, |
240 | 16 | {"RP address", "auto_rp.rp_addr", |
241 | 16 | FT_IPv4, BASE_NONE, NULL, 0, |
242 | 16 | "The unicast IP address of the RP", HFILL }}, |
243 | | |
244 | 16 | { &hf_auto_rp_prefix_sgn, |
245 | 16 | {"Sign", "auto_rp.prefix_sign", |
246 | 16 | FT_UINT8, BASE_DEC, VALS(auto_rp_mask_sign_vals), AUTO_RP_SIGN_MASK, |
247 | 16 | "Group prefix sign", HFILL }}, |
248 | | |
249 | 16 | { &hf_auto_rp_mask_len, |
250 | 16 | {"Mask length", "auto_rp.mask_len", |
251 | 16 | FT_UINT8, BASE_DEC, NULL, 0x0, |
252 | 16 | "Length of group prefix", HFILL }}, |
253 | | |
254 | 16 | { &hf_auto_rp_group_prefix, |
255 | 16 | {"Prefix", "auto_rp.group_prefix", |
256 | 16 | FT_IPv4, BASE_NONE, NULL, 0, |
257 | 16 | "Group prefix", HFILL }}, |
258 | | |
259 | 16 | { &hf_auto_rp_reserved, |
260 | 16 | {"Reserved", "auto_rp.reserved", |
261 | 16 | FT_UINT32, BASE_HEX, NULL, 0, |
262 | 16 | NULL, HFILL }}, |
263 | | |
264 | 16 | { &hf_auto_rp_trailing_junk, |
265 | 16 | {"Trailing junk", "auto_rp.trailing_junk", |
266 | 16 | FT_BYTES, BASE_NONE, NULL, 0, |
267 | 16 | NULL, HFILL }}, |
268 | 16 | }; |
269 | | |
270 | 16 | static int *ett[] = { |
271 | 16 | &ett_auto_rp, |
272 | 16 | &ett_auto_rp_ver_type, |
273 | 16 | &ett_auto_rp_map, |
274 | 16 | &ett_auto_rp_group |
275 | 16 | }; |
276 | | |
277 | 16 | proto_auto_rp = proto_register_protocol("Cisco Auto-RP", "Auto-RP", "auto_rp"); |
278 | 16 | proto_register_field_array(proto_auto_rp, hf, array_length(hf)); |
279 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
280 | | |
281 | 16 | auto_rp_handle = register_dissector("auto_rp", dissect_auto_rp, proto_auto_rp); |
282 | 16 | } |
283 | | |
284 | | void |
285 | | proto_reg_handoff_auto_rp(void) |
286 | 16 | { |
287 | 16 | dissector_add_uint_with_preference("udp.port", UDP_PORT_PIM_RP_DISC, auto_rp_handle); |
288 | 16 | } |
289 | | |
290 | | /* |
291 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
292 | | * |
293 | | * Local variables: |
294 | | * c-basic-offset: 8 |
295 | | * tab-width: 8 |
296 | | * indent-tabs-mode: nil |
297 | | * End: |
298 | | * |
299 | | * vi: set shiftwidth=8 tabstop=8 expandtab: |
300 | | * :indentSize=8:tabSize=8:noTabs=true: |
301 | | */ |