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