/src/wireshark/epan/dissectors/packet-gmrp.c
Line | Count | Source |
1 | | /* packet-gmrp.c |
2 | | * Routines for GMRP (GARP Multicast Registration Protocol) dissection |
3 | | * Copyright 2001, Markus Seehofer <mseehofe@nt.hirschmann.de> |
4 | | * |
5 | | * Based on the code from packet-gvrp.c (GVRP) from |
6 | | * Kevin Shi <techishi@ms22.hinet.net> Copyright 2000 |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/expert.h> |
19 | | |
20 | | void proto_register_gmrp(void); |
21 | | |
22 | | /* Initialize the protocol and registered fields */ |
23 | | static int proto_gmrp; |
24 | | static int hf_gmrp_proto_id; |
25 | | static int hf_gmrp_attribute_type; |
26 | | static int hf_gmrp_attribute_length; |
27 | | static int hf_gmrp_attribute_event; |
28 | | static int hf_gmrp_attribute_value_group_membership; |
29 | | static int hf_gmrp_attribute_value_service_requirement; |
30 | | static int hf_gmrp_end_of_mark; |
31 | | |
32 | | /* Initialize the subtree pointers */ |
33 | | static int ett_gmrp; |
34 | | static int ett_gmrp_message; |
35 | | static int ett_gmrp_attribute_list; |
36 | | /*static int ett_gmrp_attribute;*/ |
37 | | |
38 | | static expert_field ei_gmrp_proto_id; |
39 | | |
40 | | |
41 | | /* Constant definitions */ |
42 | 0 | #define GARP_DEFAULT_PROTOCOL_ID 0x0001 |
43 | 0 | #define GARP_END_OF_MARK 0x00 |
44 | | |
45 | 0 | #define GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP 0x01 |
46 | 0 | #define GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT 0x02 |
47 | | |
48 | | #define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL 0x00 |
49 | | #define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL_UNREGISTERED 0x01 |
50 | | |
51 | | static const value_string attribute_type_vals[] = { |
52 | | { GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP ,"Group Membership" }, |
53 | | { GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT ,"Service Requirement" }, |
54 | | { 0, NULL } |
55 | | }; |
56 | | |
57 | | /* The length of GMRP LeaveAll attribute should be 2 octets (one for length |
58 | | * and the other for event) */ |
59 | 0 | #define GMRP_LENGTH_LEAVEALL (int)(sizeof(uint8_t)+sizeof(uint8_t)) |
60 | | |
61 | | /* The length of GMRP attribute other than LeaveAll should be: |
62 | | * |
63 | | * 8 bytes for Group Membership (1 for length, 1 for event and 6 for mac address to register) |
64 | | * or |
65 | | * 3 bytes for Service Requirement (1 for length, 1 for event, 1 for attribute value) |
66 | | * |
67 | | */ |
68 | 0 | #define GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL (int)(sizeof(uint8_t)+sizeof(uint8_t)+(6*sizeof(uint8_t))) |
69 | 0 | #define GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL (int)(sizeof(uint8_t)+sizeof(uint8_t)+sizeof(uint8_t)) |
70 | | |
71 | | /* Packet offset definitions */ |
72 | 0 | #define GARP_PROTOCOL_ID 0 |
73 | | |
74 | | /* Event definitions */ |
75 | 0 | #define GMRP_EVENT_LEAVEALL 0 |
76 | 0 | #define GMRP_EVENT_JOINEMPTY 1 |
77 | 0 | #define GMRP_EVENT_JOININ 2 |
78 | 0 | #define GMRP_EVENT_LEAVEEMPTY 3 |
79 | 0 | #define GMRP_EVENT_LEAVEIN 4 |
80 | 0 | #define GMRP_EVENT_EMPTY 5 |
81 | | |
82 | | static const value_string event_vals[] = { |
83 | | { GMRP_EVENT_LEAVEALL, "Leave All" }, |
84 | | { GMRP_EVENT_JOINEMPTY, "Join Empty" }, |
85 | | { GMRP_EVENT_JOININ, "Join In" }, |
86 | | { GMRP_EVENT_LEAVEEMPTY, "Leave Empty" }, |
87 | | { GMRP_EVENT_LEAVEIN, "Leave In" }, |
88 | | { GMRP_EVENT_EMPTY, "Empty" }, |
89 | | { 0, NULL } |
90 | | }; |
91 | | |
92 | | |
93 | | /* Code to actually dissect the packets */ |
94 | | static int |
95 | | dissect_gmrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
96 | 0 | { |
97 | 0 | proto_item *ti; |
98 | 0 | proto_tree *gmrp_tree, *msg_tree, *attr_tree; |
99 | 0 | uint16_t protocol_id; |
100 | 0 | uint8_t octet; |
101 | 0 | uint8_t attribute_type; |
102 | 0 | int msg_index, attr_index, offset = 0, length = tvb_reported_length(tvb); |
103 | |
|
104 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "GMRP"); |
105 | |
|
106 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "GMRP"); |
107 | |
|
108 | 0 | ti = proto_tree_add_item(tree, proto_gmrp, tvb, 0, -1, ENC_NA); |
109 | |
|
110 | 0 | gmrp_tree = proto_item_add_subtree(ti, ett_gmrp); |
111 | | |
112 | | /* Read in GARP protocol ID */ |
113 | 0 | protocol_id = tvb_get_ntohs(tvb, GARP_PROTOCOL_ID); |
114 | |
|
115 | 0 | ti = proto_tree_add_uint_format_value(gmrp_tree, hf_gmrp_proto_id, tvb, |
116 | 0 | GARP_PROTOCOL_ID, 2, protocol_id, |
117 | 0 | "0x%04x (%s)", protocol_id, |
118 | 0 | protocol_id == GARP_DEFAULT_PROTOCOL_ID ? |
119 | 0 | "GARP Multicast Registration Protocol" : |
120 | 0 | "Unknown Protocol"); |
121 | | |
122 | | /* Currently only one protocol ID is supported */ |
123 | 0 | if (protocol_id != GARP_DEFAULT_PROTOCOL_ID) |
124 | 0 | { |
125 | 0 | expert_add_info(pinfo, ti, &ei_gmrp_proto_id); |
126 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, GARP_PROTOCOL_ID + 2), |
127 | 0 | pinfo, tree); |
128 | 0 | return tvb_captured_length(tvb); |
129 | 0 | } |
130 | | |
131 | 0 | offset += 2; |
132 | 0 | length -= 2; |
133 | |
|
134 | 0 | msg_index = 0; |
135 | | |
136 | | /* Begin to parse GARP messages */ |
137 | 0 | while (length) |
138 | 0 | { |
139 | 0 | proto_item *msg_item; |
140 | 0 | int msg_start = offset; |
141 | | |
142 | | /* Read in attribute type. */ |
143 | 0 | attribute_type = octet = tvb_get_uint8(tvb, offset); |
144 | | |
145 | | /* Check for end of mark */ |
146 | 0 | if (octet == GARP_END_OF_MARK) |
147 | 0 | { |
148 | | /* End of GARP PDU */ |
149 | 0 | if (msg_index) |
150 | 0 | { |
151 | 0 | proto_tree_add_uint_format(gmrp_tree, hf_gmrp_end_of_mark, tvb, offset, 1, octet, "End of pdu"); |
152 | 0 | break; |
153 | 0 | } |
154 | 0 | else |
155 | 0 | { |
156 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
157 | 0 | pinfo, tree); |
158 | 0 | return tvb_captured_length(tvb); |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | 0 | offset += 1; |
163 | 0 | length -= 1; |
164 | |
|
165 | 0 | msg_tree = proto_tree_add_subtree_format(gmrp_tree, tvb, msg_start, -1, |
166 | 0 | ett_gmrp_message, &msg_item, "Message %d", msg_index + 1); |
167 | |
|
168 | 0 | proto_tree_add_uint(msg_tree, hf_gmrp_attribute_type, tvb, |
169 | 0 | msg_start, 1, octet); |
170 | | |
171 | | /* GMRP supports Group Membership and Service Requirement as attribute types */ |
172 | 0 | if ( (octet != GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP) && (octet != GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT) ) |
173 | 0 | { |
174 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, |
175 | 0 | tree); |
176 | 0 | return tvb_captured_length(tvb); |
177 | 0 | } |
178 | | |
179 | 0 | attr_index = 0; |
180 | |
|
181 | 0 | while (length) |
182 | 0 | { |
183 | 0 | int attr_start = offset; |
184 | 0 | proto_item *attr_item; |
185 | | |
186 | | /* Read in attribute length. */ |
187 | 0 | octet = tvb_get_uint8(tvb, offset); |
188 | | |
189 | | /* Check for end of mark */ |
190 | 0 | if (octet == GARP_END_OF_MARK) |
191 | 0 | { |
192 | | /* If at least one message has been already read, |
193 | | * check for another end of mark. |
194 | | */ |
195 | 0 | if (attr_index) |
196 | 0 | { |
197 | 0 | proto_tree_add_uint_format(msg_tree, hf_gmrp_end_of_mark, tvb, offset, |
198 | 0 | 1, octet, " End of mark"); |
199 | |
|
200 | 0 | offset += 1; |
201 | 0 | length -= 1; |
202 | |
|
203 | 0 | proto_item_set_len(msg_item, offset - msg_start); |
204 | 0 | break; |
205 | 0 | } |
206 | 0 | else |
207 | 0 | { |
208 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
209 | 0 | pinfo, tree); |
210 | 0 | return tvb_captured_length(tvb); |
211 | 0 | } |
212 | 0 | } |
213 | 0 | else |
214 | 0 | { |
215 | 0 | uint8_t event; |
216 | |
|
217 | 0 | offset += 1; |
218 | 0 | length -= 1; |
219 | |
|
220 | 0 | attr_tree = proto_tree_add_subtree_format(msg_tree, tvb, attr_start, -1, |
221 | 0 | ett_gmrp_attribute_list, &attr_item, " Attribute %d", attr_index + 1); |
222 | |
|
223 | 0 | proto_tree_add_uint(attr_tree, hf_gmrp_attribute_length, |
224 | 0 | tvb, attr_start, 1, octet); |
225 | | |
226 | | /* Read in attribute event */ |
227 | 0 | event = tvb_get_uint8(tvb, offset); |
228 | |
|
229 | 0 | proto_tree_add_uint(attr_tree, hf_gmrp_attribute_event, |
230 | 0 | tvb, offset, 1, event); |
231 | |
|
232 | 0 | offset += 1; |
233 | 0 | length -= 1; |
234 | |
|
235 | 0 | switch (event) { |
236 | | |
237 | 0 | case GMRP_EVENT_LEAVEALL: |
238 | 0 | if (octet != GMRP_LENGTH_LEAVEALL) |
239 | 0 | { |
240 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
241 | 0 | pinfo, tree); |
242 | 0 | return tvb_captured_length(tvb); |
243 | 0 | } |
244 | 0 | break; |
245 | | |
246 | 0 | case GMRP_EVENT_JOINEMPTY: |
247 | 0 | case GMRP_EVENT_JOININ: |
248 | 0 | case GMRP_EVENT_LEAVEEMPTY: |
249 | 0 | case GMRP_EVENT_LEAVEIN: |
250 | 0 | case GMRP_EVENT_EMPTY: |
251 | 0 | if ( (octet != GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL) && |
252 | 0 | (octet != GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL) ) |
253 | 0 | { |
254 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
255 | 0 | pinfo, tree); |
256 | 0 | return tvb_captured_length(tvb); |
257 | 0 | } |
258 | | |
259 | | /* Show attribute value */ |
260 | | |
261 | 0 | if ( GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP == attribute_type ) |
262 | 0 | { |
263 | | /* Group Membership */ |
264 | 0 | proto_tree_add_item(attr_tree, hf_gmrp_attribute_value_group_membership, |
265 | 0 | tvb, offset, 6, ENC_NA); |
266 | |
|
267 | 0 | offset += 6; |
268 | 0 | length -= 6; |
269 | 0 | } |
270 | 0 | else |
271 | 0 | if ( GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT == attribute_type ) |
272 | 0 | { |
273 | | /* Service Requirement */ |
274 | 0 | proto_tree_add_item(attr_tree, hf_gmrp_attribute_value_service_requirement, |
275 | 0 | tvb, offset, 1, ENC_BIG_ENDIAN); |
276 | |
|
277 | 0 | offset += 1; |
278 | 0 | length -= 1; |
279 | 0 | } |
280 | 0 | else |
281 | 0 | { |
282 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
283 | 0 | pinfo, tree); |
284 | 0 | return tvb_captured_length(tvb); |
285 | 0 | } |
286 | | |
287 | 0 | break; |
288 | | |
289 | 0 | default: |
290 | 0 | call_data_dissector(tvb_new_subset_remaining(tvb, offset), |
291 | 0 | pinfo, tree); |
292 | 0 | return tvb_captured_length(tvb); |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 0 | proto_item_set_len(attr_item, offset - attr_start); |
297 | |
|
298 | 0 | attr_index++; |
299 | 0 | } |
300 | | |
301 | 0 | msg_index++; |
302 | 0 | } |
303 | 0 | return tvb_captured_length(tvb); |
304 | 0 | } |
305 | | |
306 | | |
307 | | |
308 | | /* Register the protocol with Wireshark */ |
309 | | void |
310 | | proto_register_gmrp(void) |
311 | 14 | { |
312 | 14 | static hf_register_info hf[] = { |
313 | 14 | { &hf_gmrp_proto_id, |
314 | 14 | { "Protocol Identifier", "gmrp.protocol_id", |
315 | 14 | FT_UINT16, BASE_HEX, NULL, 0x0, |
316 | 14 | NULL , HFILL } |
317 | 14 | }, |
318 | 14 | { &hf_gmrp_attribute_type, |
319 | 14 | { "Type", "gmrp.attribute_type", |
320 | 14 | FT_UINT8, BASE_HEX, VALS(attribute_type_vals), 0x0, |
321 | 14 | NULL , HFILL } |
322 | 14 | }, |
323 | 14 | { &hf_gmrp_attribute_length, |
324 | 14 | { "Length", "gmrp.attribute_length", |
325 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
326 | 14 | NULL , HFILL } |
327 | 14 | }, |
328 | 14 | { &hf_gmrp_attribute_event, |
329 | 14 | { "Event", "gmrp.attribute_event", |
330 | 14 | FT_UINT8, BASE_DEC, VALS(event_vals), 0x0, |
331 | 14 | NULL , HFILL } |
332 | 14 | }, |
333 | 14 | { &hf_gmrp_attribute_value_group_membership, |
334 | 14 | { "Value", "gmrp.attribute_value_group_membership", |
335 | 14 | FT_ETHER, BASE_NONE, NULL, 0x0, |
336 | 14 | NULL , HFILL } |
337 | 14 | }, |
338 | 14 | { &hf_gmrp_attribute_value_service_requirement, |
339 | 14 | { "Value", "gmrp.attribute_value_service_requirement", |
340 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
341 | 14 | NULL , HFILL } |
342 | 14 | }, |
343 | 14 | { &hf_gmrp_end_of_mark, |
344 | 14 | { "End of mark", "gmrp.end_of_mark", |
345 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
346 | 14 | NULL , HFILL } |
347 | 14 | } |
348 | | |
349 | 14 | }; |
350 | | |
351 | 14 | static int *ett[] = { |
352 | 14 | &ett_gmrp, |
353 | 14 | &ett_gmrp_message, |
354 | 14 | &ett_gmrp_attribute_list |
355 | 14 | }; |
356 | | |
357 | 14 | static ei_register_info ei[] = { |
358 | 14 | { &ei_gmrp_proto_id, { "gmrp.protocol_id.not_gmrp", PI_UNDECODED, PI_WARN, "This version of Wireshark only knows about protocol id = 1", EXPFILL }}, |
359 | 14 | }; |
360 | | |
361 | 14 | expert_module_t* expert_gmrp; |
362 | | |
363 | | /* Register the protocol name and description for GMRP */ |
364 | 14 | proto_gmrp = proto_register_protocol("GARP Multicast Registration Protocol", "GMRP", "gmrp"); |
365 | | |
366 | | /* Required function calls to register the header fields and subtrees |
367 | | * used by GMRP */ |
368 | 14 | proto_register_field_array(proto_gmrp, hf, array_length(hf)); |
369 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
370 | 14 | expert_gmrp = expert_register_protocol(proto_gmrp); |
371 | 14 | expert_register_field_array(expert_gmrp, ei, array_length(ei)); |
372 | | |
373 | 14 | register_dissector("gmrp", dissect_gmrp, proto_gmrp); |
374 | | |
375 | 14 | } |
376 | | |
377 | | /* |
378 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
379 | | * |
380 | | * Local variables: |
381 | | * c-basic-offset: 4 |
382 | | * tab-width: 8 |
383 | | * indent-tabs-mode: nil |
384 | | * End: |
385 | | * |
386 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
387 | | * :indentSize=4:tabSize=8:noTabs=true: |
388 | | */ |