Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-vpp.c
blob5573824fb352c17f03d2e490ae46eac14001482b
1 /* packet-vpp.c
3 * Routines for the disassembly of fd.io vpp project
4 * dispatch captures
6 * Copyright 2019, Dave Barach <wireshark@barachs.net>
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/expert.h>
19 #include <epan/to_str.h>
20 #include <epan/nlpid.h>
21 #include <epan/etypes.h>
22 #include <epan/ws_printf.h>
23 #include <wiretap/wtap.h>
25 void proto_register_vpp(void);
26 void proto_reg_handoff_vpp(void);
28 static int proto_vpp;
29 static int proto_vpp_metadata;
30 static int proto_vpp_opaque;
31 static int proto_vpp_opaque2;
32 static int proto_vpp_trace;
33 static int hf_vpp_nodename;
34 static int hf_vpp_metadata;
35 static int hf_vpp_buffer_index;
36 static int hf_vpp_buffer_opaque;
37 static int hf_vpp_buffer_opaque2;
38 static int hf_vpp_buffer_trace;
39 static int hf_vpp_major_version;
40 static int hf_vpp_minor_version;
41 static int hf_vpp_protocol_hint;
43 static expert_module_t* expert_vpp;
45 static expert_field ei_vpp_major_version_error;
46 static expert_field ei_vpp_minor_version_error;
47 static expert_field ei_vpp_protocol_hint_error;
49 static int ett_vpp;
50 static int ett_vpp_opaque;
51 static int ett_vpp_opaque2;
52 static int ett_vpp_metadata;
53 static int ett_vpp_trace;
55 static dissector_handle_t vpp_dissector_handle;
56 static dissector_handle_t vpp_opaque_dissector_handle;
57 static dissector_handle_t vpp_opaque2_dissector_handle;
58 static dissector_handle_t vpp_metadata_dissector_handle;
59 static dissector_handle_t vpp_trace_dissector_handle;
61 #define VPP_MAJOR_VERSION 1
62 #define VPP_MINOR_VERSION 0
63 #define IP4_TYPICAL_VERSION_LENGTH 0x45
64 #define IP6_TYPICAL_VERSION_AND_TRAFFIC_CLASS 0x60
66 typedef enum
68 VLIB_NODE_PROTO_HINT_NONE = 0,
69 VLIB_NODE_PROTO_HINT_ETHERNET,
70 VLIB_NODE_PROTO_HINT_IP4,
71 VLIB_NODE_PROTO_HINT_IP6,
72 VLIB_NODE_PROTO_HINT_TCP,
73 VLIB_NODE_PROTO_HINT_UDP,
74 VLIB_NODE_N_PROTO_HINTS,
75 } vlib_node_proto_hint_t;
77 static dissector_handle_t next_dissectors[VLIB_NODE_N_PROTO_HINTS];
79 /* List of next dissectors hints that we know about */
80 #define foreach_next_dissector \
81 _(VLIB_NODE_PROTO_HINT_ETHERNET, eth_withoutfcs) \
82 _(VLIB_NODE_PROTO_HINT_IP4, ip) \
83 _(VLIB_NODE_PROTO_HINT_IP6, ipv6) \
84 _(VLIB_NODE_PROTO_HINT_TCP, tcp) \
85 _(VLIB_NODE_PROTO_HINT_UDP, udp)
87 static void
88 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
89 int start,
90 int len, int hf)
92 int next;
93 int line_len;
94 int data_len;
96 while(len > 0) {
97 line_len = tvb_find_line_end(tvb, start, len, &next, false);
98 data_len = next - start;
99 proto_tree_add_string(tree, hf, tvb, start, data_len,
100 tvb_format_stringzpad(pinfo->pool, tvb, start, line_len));
101 start += data_len;
102 len -= data_len;
106 static int
107 dissect_vpp_metadata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
108 void* data _U_)
110 int offset = 0;
111 proto_item *ti;
112 proto_tree *metadata_tree;
113 int metadata_string_length;
115 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Metadata");
116 col_clear(pinfo->cinfo, COL_INFO);
118 ti = proto_tree_add_item(tree, proto_vpp_metadata, tvb, offset, -1, ENC_NA);
119 metadata_tree = proto_item_add_subtree(ti, ett_vpp_metadata);
121 /* How long is the metadata string? */
122 metadata_string_length = tvb_strsize(tvb, offset);
124 add_multi_line_string_to_tree(metadata_tree, tvb, pinfo, 0,
125 metadata_string_length,
126 hf_vpp_metadata);
127 return tvb_captured_length(tvb);
130 static int
131 dissect_vpp_trace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
132 void* data _U_)
134 int offset = 0;
135 proto_item *ti;
136 proto_tree *trace_tree;
137 int trace_string_length;
139 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Trace");
140 col_clear(pinfo->cinfo, COL_INFO);
142 ti = proto_tree_add_item(tree, proto_vpp_trace, tvb, offset, -1, ENC_NA);
143 trace_tree = proto_item_add_subtree(ti, ett_vpp_trace);
145 /* How long is the trace string? */
146 trace_string_length = tvb_strsize(tvb, offset);
148 add_multi_line_string_to_tree(trace_tree, tvb, pinfo, 0,
149 trace_string_length,
150 hf_vpp_buffer_trace);
151 return tvb_captured_length(tvb);
155 static int
156 dissect_vpp_opaque(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
157 void* data _U_)
159 int offset = 0;
160 proto_item *ti;
161 proto_tree *opaque_tree;
162 int opaque_string_length;
164 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque");
165 col_clear(pinfo->cinfo, COL_INFO);
167 ti = proto_tree_add_item(tree, proto_vpp_opaque, tvb, offset, -1, ENC_NA);
168 opaque_tree = proto_item_add_subtree(ti, ett_vpp_opaque);
170 opaque_string_length = tvb_strsize(tvb, offset);
171 add_multi_line_string_to_tree(opaque_tree, tvb, pinfo, 0, opaque_string_length,
172 hf_vpp_buffer_opaque);
174 return tvb_captured_length(tvb);
177 static int
178 dissect_vpp_opaque2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
179 void* data _U_)
181 int offset = 0;
182 proto_item *ti;
183 proto_tree *opaque2_tree;
184 int opaque2_string_length;
186 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque2");
187 col_clear(pinfo->cinfo, COL_INFO);
189 ti = proto_tree_add_item(tree, proto_vpp_opaque2, tvb, offset, -1, ENC_NA);
190 opaque2_tree = proto_item_add_subtree(ti, ett_vpp_opaque2);
192 opaque2_string_length = tvb_strsize(tvb, offset);
193 add_multi_line_string_to_tree(opaque2_tree, tvb, pinfo, 0, opaque2_string_length,
194 hf_vpp_buffer_opaque2);
196 return tvb_captured_length(tvb);
200 static int
201 dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
203 proto_item *ti;
204 proto_tree *vpp_tree;
205 tvbuff_t *metadata_tvb, *opaque_tvb, *opaque2_tvb, *eth_tvb, *trace_tvb;
206 int offset = 0;
207 uint8_t major_version, minor_version, string_count, protocol_hint;
208 uint8_t *name;
209 unsigned len;
210 uint8_t maybe_protocol_id;
211 dissector_handle_t use_this_dissector;
213 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP");
214 col_clear(pinfo->cinfo, COL_INFO);
216 ti = proto_tree_add_item(tree, proto_vpp, tvb, offset, -1, ENC_NA);
217 vpp_tree = proto_item_add_subtree(ti, ett_vpp);
219 major_version = tvb_get_uint8(tvb, offset);
220 /* If the major version doesn't match, quit on the spot */
221 if(major_version != VPP_MAJOR_VERSION) {
222 proto_item *major_version_item;
223 major_version_item =
224 proto_tree_add_item(tree, hf_vpp_major_version,
225 tvb, offset, 1, ENC_NA);
226 expert_add_info_format(pinfo, major_version_item,
227 &ei_vpp_major_version_error,
228 "Major Version Mismatch read %d not %d",
229 (int)major_version, VPP_MAJOR_VERSION);
230 return tvb_captured_length(tvb);
232 offset++;
234 minor_version = tvb_get_uint8(tvb, offset);
235 /* If the minor version doesn't match, make a note and try to continue */
236 if(minor_version != VPP_MINOR_VERSION) {
237 proto_item *minor_version_item;
238 minor_version_item =
239 proto_tree_add_item(tree, hf_vpp_minor_version,
240 tvb, offset, 1, ENC_NA);
241 expert_add_info_format(pinfo, minor_version_item,
242 &ei_vpp_minor_version_error,
243 "Minor Version Mismatch read %d not %d",
244 (int)minor_version, VPP_MINOR_VERSION);
246 offset++;
248 /* Number of counted strings in this trace record */
249 string_count = tvb_get_uint8(tvb, offset);
250 offset++;
253 * Hint: protocol which should be at b->data[b->current_data]
254 * It will be a while before vpp sends useful hints for every
255 * possible node, see heuristic below.
257 protocol_hint = tvb_get_uint8(tvb, offset);
259 if(protocol_hint >= array_length(next_dissectors)) {
260 proto_item *protocol_hint_item;
261 protocol_hint_item =
262 proto_tree_add_item(tree, hf_vpp_protocol_hint,
263 tvb, offset, 1, ENC_NA);
264 expert_add_info_format(pinfo, protocol_hint_item,
265 &ei_vpp_protocol_hint_error,
266 "Protocol hint %d out of range, max %d",
267 (int)protocol_hint,
268 (int)array_length(next_dissectors));
269 protocol_hint = 0;
272 offset++;
274 /* Buffer Index */
275 proto_tree_add_item(vpp_tree, hf_vpp_buffer_index, tvb,
276 offset, 4, ENC_BIG_ENDIAN);
277 offset += 4;
279 /* Nodename */
280 len = tvb_strsize(tvb, offset);
281 name = tvb_get_string_enc(pinfo->pool, tvb, offset, len,
282 ENC_ASCII);
283 proto_tree_add_string(tree, hf_vpp_nodename, tvb, offset, len, name);
284 offset += len;
286 /* Metadata */
287 len = tvb_strsize(tvb, offset);
288 metadata_tvb = tvb_new_subset_remaining(tvb, offset);
289 call_dissector(vpp_metadata_dissector_handle, metadata_tvb, pinfo, tree);
290 offset += len;
292 /* Opaque */
293 len = tvb_strsize(tvb, offset);
294 opaque_tvb = tvb_new_subset_remaining(tvb, offset);
295 call_dissector(vpp_opaque_dissector_handle, opaque_tvb, pinfo, tree);
296 offset += len;
298 /* Opaque2 */
299 len = tvb_strsize(tvb, offset);
300 opaque2_tvb = tvb_new_subset_remaining(tvb, offset);
301 call_dissector(vpp_opaque2_dissector_handle, opaque2_tvb, pinfo, tree);
302 offset += len;
304 /* Trace, if present */
305 if(string_count > 4) {
306 len = tvb_strsize(tvb, offset);
307 trace_tvb = tvb_new_subset_remaining(tvb, offset);
308 call_dissector(vpp_trace_dissector_handle, trace_tvb, pinfo, tree);
309 offset += len;
312 eth_tvb = tvb_new_subset_remaining(tvb, offset);
315 * Delegate the rest of the packet dissection to the per-node
316 * next dissector in the foreach_node_to_dissector_pair list
318 * Failing that, pretend its an ethernet packet
320 /* See setup for hint == 0 below */
321 use_this_dissector = next_dissectors [protocol_hint];
322 if(protocol_hint == 0) {
323 maybe_protocol_id = tvb_get_uint8(tvb, offset);
325 switch(maybe_protocol_id) {
326 case IP4_TYPICAL_VERSION_LENGTH:
327 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP4];
328 break;
329 case IP6_TYPICAL_VERSION_AND_TRAFFIC_CLASS:
330 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP6];
331 break;
332 default:
333 break;
336 call_dissector(use_this_dissector, eth_tvb, pinfo, tree);
337 return tvb_captured_length(tvb);
340 void
341 proto_register_vpp(void)
343 static hf_register_info vpp_hf[] = {
344 { &hf_vpp_buffer_index,
345 { "BufferIndex", "vpp.BufferIndex", FT_UINT32, BASE_HEX, NULL, 0x0,
346 NULL, HFILL },
348 { &hf_vpp_nodename,
349 { "NodeName", "vpp.NodeName", FT_STRINGZ, BASE_NONE, NULL, 0x0,
350 NULL, HFILL },
352 { &hf_vpp_major_version,
353 { "MajorVersion", "vpp.MajorVersion", FT_UINT8, BASE_DEC, NULL, 0x0,
354 NULL, HFILL },
356 { &hf_vpp_minor_version,
357 { "MinorVersion", "vpp.MinorVersion", FT_UINT8, BASE_DEC, NULL, 0x0,
358 NULL, HFILL },
360 { &hf_vpp_protocol_hint,
361 { "ProtocolHint", "vpp.ProtocolHint", FT_UINT8, BASE_DEC, NULL, 0x0,
362 NULL, HFILL },
366 static ei_register_info vpp_ei[] = {
367 { &ei_vpp_major_version_error,
368 { "vpp.bad_major_version", PI_MALFORMED, PI_ERROR,
369 "Bad Major Version", EXPFILL }},
370 { &ei_vpp_minor_version_error,
371 { "vpp.bad_minor_version", PI_UNDECODED, PI_WARN,
372 "Bad Minor Version", EXPFILL }},
373 { &ei_vpp_protocol_hint_error,
374 { "vpp.bad_protocol_hint", PI_PROTOCOL, PI_WARN,
375 "Bad Protocol Hint", EXPFILL }},
378 static hf_register_info metadata_hf[] = {
379 { &hf_vpp_metadata,
380 { "Metadata", "vpp.metadata",
381 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
385 static hf_register_info opaque_hf[] = {
386 { &hf_vpp_buffer_opaque,
387 { "Opaque", "vpp.opaque",
388 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
392 static hf_register_info opaque2_hf[] = {
393 { &hf_vpp_buffer_opaque2,
394 { "Opaque2", "vpp.opaque2",
395 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
399 static hf_register_info trace_hf[] = {
400 { &hf_vpp_buffer_trace,
401 { "Trace", "vpp.trace", FT_STRINGZ, BASE_NONE, NULL, 0x0,
402 NULL, HFILL },
406 static int *vpp_ett[] = {
407 &ett_vpp,
409 static int *ett_metadata[] = {
410 &ett_vpp_metadata,
412 static int *ett_opaque[] = {
413 &ett_vpp_opaque,
415 static int *ett_opaque2[] = {
416 &ett_vpp_opaque2,
418 static int *ett_trace[] = {
419 &ett_vpp_trace,
422 proto_vpp = proto_register_protocol("VPP Dispatch Trace", "VPP", "vpp");
423 proto_register_field_array(proto_vpp, vpp_hf, array_length(vpp_hf));
424 proto_register_subtree_array(vpp_ett, array_length(vpp_ett));
425 register_dissector("vpp", dissect_vpp, proto_vpp);
427 expert_vpp = expert_register_protocol(proto_vpp);
428 expert_register_field_array(expert_vpp, vpp_ei, array_length(vpp_ei));
430 proto_vpp_metadata = proto_register_protocol("VPP Buffer Metadata",
431 "VPP-Metadata",
432 "vpp-metadata");
433 proto_register_field_array(proto_vpp_metadata, metadata_hf,
434 array_length(metadata_hf));
435 proto_register_subtree_array(ett_metadata, array_length(ett_metadata));
436 register_dissector("vppMetadata", dissect_vpp_metadata, proto_vpp_metadata);
438 proto_vpp_opaque = proto_register_protocol("VPP Buffer Opaque", "VPP-Opaque",
439 "vpp-opaque");
440 proto_register_field_array(proto_vpp_opaque, opaque_hf,
441 array_length(opaque_hf));
442 proto_register_subtree_array(ett_opaque, array_length(ett_opaque));
443 register_dissector("vppOpaque", dissect_vpp_opaque, proto_vpp_opaque);
445 proto_vpp_opaque2 = proto_register_protocol("VPP Buffer Opaque2",
446 "VPP-Opaque2", "vpp-opaque2");
447 proto_register_field_array(proto_vpp_opaque2, opaque2_hf,
448 array_length(opaque2_hf));
449 proto_register_subtree_array(ett_opaque2, array_length(ett_opaque2));
450 register_dissector("vppOpaque2", dissect_vpp_opaque2, proto_vpp_opaque2);
453 proto_vpp_trace = proto_register_protocol("VPP Buffer Trace", "VPP-Trace",
454 "vpp-trace");
455 proto_register_field_array(proto_vpp_trace, trace_hf,
456 array_length(trace_hf));
457 proto_register_subtree_array(ett_trace, array_length(ett_trace));
458 register_dissector("vppTrace", dissect_vpp_trace, proto_vpp_trace);
460 #define _(idx,dname) next_dissectors[idx] = find_dissector(#dname);
461 foreach_next_dissector;
462 #undef _
464 /* if all else fails, dissect data as if ethernet MAC */
465 next_dissectors[VLIB_NODE_PROTO_HINT_NONE] =
466 next_dissectors [VLIB_NODE_PROTO_HINT_ETHERNET];
469 void
470 proto_reg_handoff_vpp(void)
472 vpp_dissector_handle = find_dissector("vpp");
473 vpp_metadata_dissector_handle = find_dissector("vppMetadata");
474 vpp_opaque_dissector_handle = find_dissector("vppOpaque");
475 vpp_opaque2_dissector_handle = find_dissector("vppOpaque2");
476 vpp_trace_dissector_handle = find_dissector("vppTrace");
477 dissector_add_uint("wtap_encap", WTAP_ENCAP_VPP, vpp_dissector_handle);
481 * Editor modelines - https://www.wireshark.org/tools/modelines.html
483 * Local variables:
484 * c-basic-offset: 4
485 * tab-width: 8
486 * indent-tabs-mode: nil
487 * End:
489 * vi: set shiftwidth=4 tabstop=8 expandtab:
490 * :indentSize=4:tabSize=8:noTabs=true: