/src/wireshark/epan/dissectors/packet-netperfmeter.c
Line | Count | Source |
1 | | /* packet-netperfmeter.c |
2 | | * Routines for the NetPerfMeter protocol used by the Open Source |
3 | | * network performance meter application NetPerfMeter: |
4 | | * https://www.uni-due.de/~be0001/netperfmeter/ |
5 | | * |
6 | | * Copyright 2009-2021 by Thomas Dreibholz <dreibh [AT] iem.uni-due.de> |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * Copied from README.developer |
13 | | * |
14 | | * SPDX-License-Identifier: GPL-2.0-or-later |
15 | | */ |
16 | | |
17 | | #include "config.h" |
18 | | |
19 | | #include <epan/packet.h> |
20 | | #include <epan/stat_tap_ui.h> |
21 | | #include <epan/tfs.h> |
22 | | |
23 | | #include <wsutil/array.h> |
24 | | |
25 | | #include "packet-sctp.h" |
26 | | #include "packet-tcp.h" |
27 | | |
28 | | void proto_register_npm(void); |
29 | | void proto_reg_handoff_npm(void); |
30 | | |
31 | | static dissector_handle_t npm_handle; |
32 | | |
33 | | static bool npm_desegment = true; |
34 | | |
35 | | static int proto_npm; |
36 | | static int tap_npm = -1; |
37 | | static int ett_npm; |
38 | | static int ett_addflow_flags; |
39 | | static int ett_identifyflow_flags; |
40 | | static int ett_start_flags; |
41 | | static int ett_data_flags; |
42 | | static int ett_results_flags; |
43 | | static int ett_onoffarray; |
44 | | |
45 | | static uint64_t npm_total_msgs; |
46 | | static uint64_t npm_total_bytes; |
47 | | |
48 | | |
49 | 16 | #define PPID_NETPERFMETER_CONTROL_LEGACY 0x29097605 |
50 | 16 | #define PPID_NETPERFMETER_DATA_LEGACY 0x29097606 |
51 | | |
52 | 32 | #define ALPN_NETPERFMETER_CONTROL "netperfmeter/control" |
53 | 32 | #define ALPN_NETPERFMETER_DATA "netperfmeter/data" |
54 | | |
55 | | /* Initialize the protocol and registered fields */ |
56 | | |
57 | 3 | #define NETPERFMETER_ACKNOWLEDGE 0x01 |
58 | 18 | #define NETPERFMETER_ADD_FLOW 0x02 |
59 | 2 | #define NETPERFMETER_REMOVE_FLOW 0x03 |
60 | 84 | #define NETPERFMETER_IDENTIFY_FLOW 0x04 |
61 | 73 | #define NETPERFMETER_DATA 0x05 |
62 | 2 | #define NETPERFMETER_START 0x06 |
63 | 0 | #define NETPERFMETER_STOP 0x07 |
64 | 2 | #define NETPERFMETER_RESULTS 0x08 |
65 | | |
66 | | static const value_string message_type_values[] = { |
67 | | { NETPERFMETER_ACKNOWLEDGE, "NetPerfMeter Acknowledge" }, |
68 | | { NETPERFMETER_ADD_FLOW, "NetPerfMeter Add Flow" }, |
69 | | { NETPERFMETER_REMOVE_FLOW, "NetPerfMeter Remove Flow" }, |
70 | | { NETPERFMETER_IDENTIFY_FLOW, "NetPerfMeter Identify Flow" }, |
71 | | { NETPERFMETER_DATA, "NetPerfMeter Data" }, |
72 | | { NETPERFMETER_START, "NetPerfMeter Start Measurement" }, |
73 | | { NETPERFMETER_STOP, "NetPerfMeter Stop Measurement" }, |
74 | | { NETPERFMETER_RESULTS, "NetPerfMeter Results" }, |
75 | | { 0, NULL } |
76 | | }; |
77 | | |
78 | | static int hf_message_type; |
79 | | static int hf_message_flags; |
80 | | static int hf_message_length; |
81 | | |
82 | | static int hf_acknowledge_flowid; |
83 | | static int hf_acknowledge_measurementid; |
84 | | static int hf_acknowledge_streamid; |
85 | | // static int hf_acknowledge_padding; |
86 | | static int hf_acknowledge_status; |
87 | | |
88 | | static int hf_addflow_flag_debug; |
89 | | static int hf_addflow_flag_nodelay; |
90 | | static int hf_addflow_flag_repeatonoff; |
91 | | static int hf_addflow_flowid; |
92 | | static int hf_addflow_measurementid; |
93 | | static int hf_addflow_streamid; |
94 | | static int hf_addflow_protocol; |
95 | | static int hf_addflow_description; |
96 | | static int hf_addflow_ordered; |
97 | | static int hf_addflow_reliable; |
98 | | static int hf_addflow_retranstrials; |
99 | | static int hf_addflow_framerate1; |
100 | | static int hf_addflow_framerate2; |
101 | | static int hf_addflow_framerate3; |
102 | | static int hf_addflow_framerate4; |
103 | | static int hf_addflow_framesize1; |
104 | | static int hf_addflow_framesize2; |
105 | | static int hf_addflow_framesize3; |
106 | | static int hf_addflow_framesize4; |
107 | | static int hf_addflow_frameraterng; |
108 | | static int hf_addflow_framesizerng; |
109 | | static int hf_addflow_rcvbuffersize; |
110 | | static int hf_addflow_sndbuffersize; |
111 | | static int hf_addflow_maxmsgsize; |
112 | | static int hf_addflow_cmt; |
113 | | static int hf_addflow_ccid; |
114 | | static int hf_addflow_onoffevents; |
115 | | static int hf_addflow_onoffeventarray; |
116 | | |
117 | | static int hf_removeflow_flowid; |
118 | | static int hf_removeflow_measurementid; |
119 | | static int hf_removeflow_streamid; |
120 | | |
121 | | static int hf_identifyflow_flag_compress_vectors; |
122 | | static int hf_identifyflow_flag_no_vectors; |
123 | | static int hf_identifyflow_flowid; |
124 | | static int hf_identifyflow_magicnumber; |
125 | | static int hf_identifyflow_measurementid; |
126 | | static int hf_identifyflow_streamid; |
127 | | |
128 | 62 | #define NETPERFMETER_IDENTIFY_FLOW_MAGIC_NUMBER 0x4bcdf3aa303c6774ULL |
129 | | |
130 | | static int hf_data_flag_frame_begin; |
131 | | static int hf_data_flag_frame_end; |
132 | | static int hf_data_flowid; |
133 | | static int hf_data_measurementid; |
134 | | static int hf_data_streamid; |
135 | | static int hf_data_padding; |
136 | | static int hf_data_frameid; |
137 | | static int hf_data_packetseqnumber; |
138 | | static int hf_data_byteseqnumber; |
139 | | static int hf_data_timestamp; |
140 | | static int hf_data_payload; |
141 | | |
142 | | static int hf_start_flag_compress_vectors; |
143 | | static int hf_start_flag_compress_scalars; |
144 | | static int hf_start_flag_no_vectors; |
145 | | static int hf_start_flag_no_scalars; |
146 | | // static int hf_start_padding; |
147 | | static int hf_start_measurementid; |
148 | | |
149 | | // static int hf_stop_padding; |
150 | | static int hf_stop_measurementid; |
151 | | |
152 | | static int hf_results_flag_eof; |
153 | | static int hf_results_data; |
154 | | |
155 | | |
156 | | /* Setup list of Transport Layer protocol types */ |
157 | | static const value_string proto_type_values[] = { |
158 | | { 6, "TCP" }, |
159 | | { 8, "MPTCP (old)" }, // NetPerfMeter 1.x, deprecated |
160 | | { 17, "UDP" }, |
161 | | { 33, "DCCP" }, |
162 | | { 132, "SCTP" }, |
163 | | { 261, "QUIC" }, |
164 | | { 262, "MPTCP" }, |
165 | | { 0, NULL } |
166 | | }; |
167 | | |
168 | | /* Setup list of CMT values */ |
169 | | static const value_string cmt_values[] = { |
170 | | { 0, "Off" }, |
171 | | { 1, "CMT" }, |
172 | | { 2, "CMT/RPv1" }, |
173 | | { 3, "CMT/RPv2" }, |
174 | | { 4, "MPTCP-Like" }, |
175 | | { 0, NULL } |
176 | | }; |
177 | | |
178 | | /* Setup list of random number generator types */ |
179 | | static const value_string rng_type_values[] = { |
180 | | { 0, "Constant" }, |
181 | | { 1, "Uniform" }, |
182 | | { 2, "Neg. Exponential" }, |
183 | | { 3, "Pareto" }, |
184 | | { 4, "Normal" }, |
185 | | { 5, "Truncated Normal" }, |
186 | | { 0, NULL } |
187 | | }; |
188 | | |
189 | | /* Message flags */ |
190 | | #define NPMAFF_DEBUG (1 << 0) |
191 | | #define NPMAFF_NODELAY (1 << 1) |
192 | | #define NPMAFF_REPEATONOFF (1 << 2) |
193 | | |
194 | | #define NPMIF_COMPRESS_VECTORS (1 << 0) |
195 | | #define NPMIF_NO_VECTORS (1 << 1) |
196 | | |
197 | | #define NPMSF_COMPRESS_VECTORS (1 << 0) |
198 | | #define NPMSF_COMPRESS_SCALARS (1 << 1) |
199 | | #define NPMSF_NO_VECTORS (1 << 2) |
200 | | #define NPMSF_NO_SCALARS (1 << 3) |
201 | | |
202 | | #define NPMDF_FRAME_BEGIN (1 << 0) |
203 | | #define NPMDF_FRAME_END (1 << 1) |
204 | | |
205 | | #define NPMRF_EOF (1 << 0) |
206 | | |
207 | | |
208 | | /* Setup list of header fields */ |
209 | | static hf_register_info hf[] = { |
210 | | { &hf_message_type, { "Type", "netperfmeter.message_type", FT_UINT8, BASE_DEC, VALS(message_type_values), 0x0, NULL, HFILL } }, |
211 | | { &hf_message_flags, { "Flags", "netperfmeter.message_flags", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
212 | | { &hf_message_length, { "Length", "netperfmeter.message_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
213 | | |
214 | | { &hf_acknowledge_flowid, { "Flow ID", "netperfmeter.acknowledge_flowid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
215 | | { &hf_acknowledge_measurementid, { "Measurement ID", "netperfmeter.acknowledge_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
216 | | { &hf_acknowledge_streamid, { "Stream ID", "netperfmeter.acknowledge_streamid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
217 | | #if 0 |
218 | | { &hf_acknowledge_padding, { "Padding", "netperfmeter.acknowledge_padding", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
219 | | #endif |
220 | | { &hf_acknowledge_status, { "Status", "netperfmeter.acknowledge_status", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
221 | | |
222 | | { &hf_addflow_flowid, { "Flow ID", "netperfmeter.addflow_flowid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
223 | | { &hf_addflow_measurementid, { "Measurement ID", "netperfmeter.addflow_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
224 | | { &hf_addflow_streamid, { "Stream ID", "netperfmeter.addflow_streamid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
225 | | { &hf_addflow_protocol, { "Protocol", "netperfmeter.addflow_protocol", FT_UINT16, BASE_DEC, VALS(proto_type_values), 0x0, NULL, HFILL } }, |
226 | | { &hf_addflow_description, { "Description", "netperfmeter.addflow_description", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
227 | | { &hf_addflow_ordered, { "Ordered", "netperfmeter.addflow_ordered", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
228 | | { &hf_addflow_reliable, { "Reliable", "netperfmeter.addflow_reliable", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
229 | | { &hf_addflow_retranstrials, { "Retransmission Trials", "netperfmeter.addflow_retranstrials", FT_UINT32, BASE_CUSTOM, NULL, 0x0, NULL, HFILL } }, |
230 | | { &hf_addflow_frameraterng, { "Frame Rate RNG", "netperfmeter.addflow_frameraterng", FT_UINT8, BASE_DEC, VALS(rng_type_values), 0x0, NULL, HFILL } }, |
231 | | { &hf_addflow_framerate1, { "Frame Rate 1", "netperfmeter.addflow_framerate1", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
232 | | { &hf_addflow_framerate2, { "Frame Rate 2", "netperfmeter.addflow_framerate2", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
233 | | { &hf_addflow_framerate3, { "Frame Rate 3", "netperfmeter.addflow_framerate3", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
234 | | { &hf_addflow_framerate4, { "Frame Rate 4", "netperfmeter.addflow_framerate4", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
235 | | { &hf_addflow_framesizerng, { "Frame Size RNG", "netperfmeter.addflow_framesizerng", FT_UINT8, BASE_DEC, VALS(rng_type_values), 0x0, NULL, HFILL } }, |
236 | | { &hf_addflow_framesize1, { "Frame Size 1", "netperfmeter.addflow_framesize1", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
237 | | { &hf_addflow_framesize2, { "Frame Size 2", "netperfmeter.addflow_framesize2", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
238 | | { &hf_addflow_framesize3, { "Frame Size 3", "netperfmeter.addflow_framesize3", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
239 | | { &hf_addflow_framesize4, { "Frame Size 4", "netperfmeter.addflow_framesize4", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
240 | | { &hf_addflow_rcvbuffersize, { "Receive Buffer Size", "netperfmeter.addflow_rcvbuffersize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
241 | | { &hf_addflow_sndbuffersize, { "Send Buffer Size", "netperfmeter.addflow_sndbuffersize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
242 | | { &hf_addflow_maxmsgsize, { "Max. Message Size", "netperfmeter.addflow_maxmsgsize", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
243 | | { &hf_addflow_cmt, { "CMT", "netperfmeter.addflow_cmt", FT_UINT8, BASE_HEX, VALS(cmt_values), 0x0, NULL, HFILL } }, |
244 | | { &hf_addflow_ccid, { "CCID", "netperfmeter.addflow_ccid", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
245 | | { &hf_addflow_onoffevents, { "On/Off Events", "netperfmeter.addflow_onoffevents", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
246 | | { &hf_addflow_onoffeventarray, { "On/Off Event", "netperfmeter.addflow_onoffeventarray", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
247 | | { &hf_addflow_flag_debug, { "Debug", "netperfmeter.addflow_flags.debug", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMAFF_DEBUG, NULL, HFILL } }, |
248 | | { &hf_addflow_flag_nodelay, { "No Delay", "netperfmeter.addflow_flags.nodelay", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMAFF_NODELAY, NULL, HFILL } }, |
249 | | { &hf_addflow_flag_repeatonoff, { "Repeat On/Off", "netperfmeter.addflow_flags.repeatonoff", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMAFF_REPEATONOFF, NULL, HFILL } }, |
250 | | |
251 | | { &hf_removeflow_flowid, { "Flow ID", "netperfmeter.removeflow_flowid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
252 | | { &hf_removeflow_measurementid, { "Measurement ID", "netperfmeter.removeflow_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
253 | | { &hf_removeflow_streamid, { "Stream ID", "netperfmeter.removeflow_streamid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
254 | | |
255 | | { &hf_identifyflow_flowid, { "Flow ID", "netperfmeter.identifyflow_flowid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
256 | | { &hf_identifyflow_magicnumber, { "Magic Number", "netperfmeter.identifyflow_magicnumber", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
257 | | { &hf_identifyflow_measurementid, { "Measurement ID", "netperfmeter.identifyflow_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
258 | | { &hf_identifyflow_streamid, { "Stream ID", "netperfmeter.identifyflow_streamid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
259 | | { &hf_identifyflow_flag_compress_vectors, { "Compress Vectors", "netperfmeter.dentifyflow_flags.compress_vectors", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMIF_COMPRESS_VECTORS, NULL, HFILL } }, |
260 | | { &hf_identifyflow_flag_no_vectors, { "No Vectors", "netperfmeter.dentifyflow_flags.no_vectors", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMIF_NO_VECTORS, NULL, HFILL } }, |
261 | | |
262 | | { &hf_data_flowid, { "Flow ID", "netperfmeter.data_flowid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
263 | | { &hf_data_measurementid, { "Measurement ID", "netperfmeter.data_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
264 | | { &hf_data_streamid, { "Stream ID", "netperfmeter.data_streamid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
265 | | { &hf_data_padding, { "Padding", "netperfmeter.data_padding", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
266 | | { &hf_data_frameid, { "Frame ID", "netperfmeter.data_frameid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
267 | | { &hf_data_packetseqnumber, { "Packet Seq Number", "netperfmeter.data_packetseqnumber", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
268 | | { &hf_data_byteseqnumber, { "Byte Seq Number", "netperfmeter.data_byteseqnumber", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
269 | | { &hf_data_timestamp, { "Time Stamp", "netperfmeter.data_timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0, NULL, HFILL } }, |
270 | | { &hf_data_payload, { "Payload", "netperfmeter.data_payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
271 | | { &hf_data_flag_frame_begin, { "Begin of Frame", "netperfmeter.data_flags.frame_begin", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMDF_FRAME_BEGIN, NULL, HFILL } }, |
272 | | { &hf_data_flag_frame_end, { "End of Frame", "netperfmeter.data_flags.frame_end", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMDF_FRAME_END, NULL, HFILL } }, |
273 | | |
274 | | #if 0 |
275 | | { &hf_start_padding, { "Padding", "netperfmeter.start_padding", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
276 | | #endif |
277 | | { &hf_start_measurementid, { "Measurement ID", "netperfmeter.start_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
278 | | { &hf_start_flag_compress_vectors,{ "Compress Vectors", "netperfmeter.start_flags.compress_vectors", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMSF_COMPRESS_VECTORS, NULL, HFILL } }, |
279 | | { &hf_start_flag_compress_scalars,{ "Compress Scalars", "netperfmeter.start_flags.compress_scalars", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMSF_COMPRESS_SCALARS, NULL, HFILL } }, |
280 | | { &hf_start_flag_no_vectors, { "No Vectors", "netperfmeter.start_flags.no_vectors", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMSF_NO_VECTORS, NULL, HFILL } }, |
281 | | { &hf_start_flag_no_scalars, { "No Scalars", "netperfmeter.start_flags.no_scalars", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMSF_NO_SCALARS, NULL, HFILL } }, |
282 | | |
283 | | #if 0 |
284 | | { &hf_stop_padding, { "Padding", "netperfmeter.stop_padding", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
285 | | #endif |
286 | | { &hf_stop_measurementid, { "Measurement ID", "netperfmeter.stop_measurementid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
287 | | |
288 | | { &hf_results_data, { "Data", "netperfmeter.results_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
289 | | { &hf_results_flag_eof, { "End of File", "netperfmeter.results_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), NPMRF_EOF, NULL, HFILL } } |
290 | | }; |
291 | | |
292 | | |
293 | | typedef struct _tap_npm_rec_t { |
294 | | uint8_t type; |
295 | | uint16_t size; |
296 | | const char* type_string; |
297 | | } tap_npm_rec_t; |
298 | | |
299 | | |
300 | | static void |
301 | | dissect_npm_acknowledge_message(tvbuff_t *message_tvb, proto_tree *message_tree) |
302 | 3 | { |
303 | 3 | proto_tree_add_item(message_tree, hf_acknowledge_flowid, message_tvb, 4, 4, ENC_BIG_ENDIAN); |
304 | 3 | proto_tree_add_item(message_tree, hf_acknowledge_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
305 | 3 | proto_tree_add_item(message_tree, hf_acknowledge_streamid, message_tvb, 16, 2, ENC_BIG_ENDIAN); |
306 | | /* proto_tree_add_item(message_tree, acknowledge_padding, message_tvb, 18, 2, ENC_BIG_ENDIAN); */ |
307 | 3 | proto_tree_add_item(message_tree, hf_acknowledge_status, message_tvb, 20, 4, ENC_BIG_ENDIAN); |
308 | 3 | } |
309 | | |
310 | | |
311 | | static void |
312 | | dissect_npm_add_flow_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_item *flags_item) |
313 | 18 | { |
314 | 18 | uint32_t retranstrials; |
315 | 18 | proto_item *onoffitem; |
316 | 18 | proto_tree *onofftree; |
317 | 18 | proto_tree *flags_tree; |
318 | 18 | uint16_t onoffevents; |
319 | 18 | uint32_t onoffvalue; |
320 | 18 | unsigned int i; |
321 | | |
322 | 18 | flags_tree = proto_item_add_subtree(flags_item, ett_addflow_flags); |
323 | 18 | proto_tree_add_item(flags_tree, hf_addflow_flag_debug, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
324 | 18 | proto_tree_add_item(flags_tree, hf_addflow_flag_nodelay, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
325 | 18 | proto_tree_add_item(flags_tree, hf_addflow_flag_repeatonoff, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
326 | | |
327 | 18 | proto_tree_add_item(message_tree, hf_addflow_flowid, message_tvb, 4, 4, ENC_BIG_ENDIAN); |
328 | 18 | proto_tree_add_item(message_tree, hf_addflow_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
329 | 18 | proto_tree_add_item(message_tree, hf_addflow_streamid, message_tvb, 16, 2, ENC_BIG_ENDIAN); |
330 | 18 | proto_tree_add_item(message_tree, hf_addflow_protocol, message_tvb, 18, 2, ENC_LITTLE_ENDIAN); |
331 | 18 | proto_tree_add_item(message_tree, hf_addflow_description, message_tvb, 20, 32, ENC_UTF_8); |
332 | | |
333 | 18 | proto_tree_add_double_format_value(message_tree, hf_addflow_ordered, message_tvb, 52, 4, |
334 | 18 | 100.0 * tvb_get_ntohl(message_tvb, 52) / (double)0xffffffff, "%1.3f%%", |
335 | 18 | 100.0 * tvb_get_ntohl(message_tvb, 52) / (double)0xffffffff); |
336 | 18 | proto_tree_add_double_format_value(message_tree, hf_addflow_reliable, message_tvb, 56, 4, |
337 | 18 | 100.0 * tvb_get_ntohl(message_tvb, 56) / (double)0xffffffff, "%1.3f%%", |
338 | 18 | 100.0 * tvb_get_ntohl(message_tvb, 56) / (double)0xffffffff); |
339 | | |
340 | 18 | retranstrials = tvb_get_ntohl(message_tvb, 60); |
341 | 18 | const char* retranstrials_format; |
342 | 18 | if((retranstrials & 0x7fffffff) == 0x7fffffff) { |
343 | 2 | retranstrials_format = "default"; |
344 | 2 | } |
345 | 16 | else if(retranstrials & (1U << 31)) { |
346 | 9 | retranstrials_format = "%u ms"; // value is ms |
347 | 9 | } |
348 | 7 | else { |
349 | 7 | retranstrials_format = "%u trials"; |
350 | 7 | } |
351 | 18 | proto_tree_add_uint_format_value(message_tree, hf_addflow_retranstrials, message_tvb, 60, 4, |
352 | 18 | retranstrials, retranstrials_format, |
353 | 18 | retranstrials &~ (1U << 31)); |
354 | | |
355 | 18 | proto_tree_add_item(message_tree, hf_addflow_frameraterng, message_tvb, 128, 1, ENC_BIG_ENDIAN); |
356 | 18 | proto_tree_add_item(message_tree, hf_addflow_framerate1, message_tvb, 64, 8, ENC_BIG_ENDIAN); |
357 | 18 | proto_tree_add_item(message_tree, hf_addflow_framerate2, message_tvb, 72, 8, ENC_BIG_ENDIAN); |
358 | 18 | proto_tree_add_item(message_tree, hf_addflow_framerate3, message_tvb, 80, 8, ENC_BIG_ENDIAN); |
359 | 18 | proto_tree_add_item(message_tree, hf_addflow_framerate4, message_tvb, 88, 8, ENC_BIG_ENDIAN); |
360 | 18 | proto_tree_add_item(message_tree, hf_addflow_framesizerng, message_tvb, 129, 1, ENC_BIG_ENDIAN); |
361 | 18 | proto_tree_add_item(message_tree, hf_addflow_framesize1, message_tvb, 96, 8, ENC_BIG_ENDIAN); |
362 | 18 | proto_tree_add_item(message_tree, hf_addflow_framesize2, message_tvb, 104, 8, ENC_BIG_ENDIAN); |
363 | 18 | proto_tree_add_item(message_tree, hf_addflow_framesize3, message_tvb, 112, 8, ENC_BIG_ENDIAN); |
364 | 18 | proto_tree_add_item(message_tree, hf_addflow_framesize4, message_tvb, 120, 8, ENC_BIG_ENDIAN); |
365 | 18 | proto_tree_add_item(message_tree, hf_addflow_rcvbuffersize, message_tvb, 130, 4, ENC_BIG_ENDIAN); |
366 | 18 | proto_tree_add_item(message_tree, hf_addflow_sndbuffersize, message_tvb, 134, 4, ENC_BIG_ENDIAN); |
367 | 18 | proto_tree_add_item(message_tree, hf_addflow_maxmsgsize, message_tvb, 138, 2, ENC_BIG_ENDIAN); |
368 | 18 | proto_tree_add_item(message_tree, hf_addflow_cmt, message_tvb, 140, 1, ENC_BIG_ENDIAN); |
369 | 18 | proto_tree_add_item(message_tree, hf_addflow_ccid, message_tvb, 141, 1, ENC_BIG_ENDIAN); |
370 | | |
371 | 18 | onoffitem = proto_tree_add_item_ret_uint16(message_tree, hf_addflow_onoffevents, message_tvb, 142, 2, ENC_BIG_ENDIAN, &onoffevents); |
372 | 18 | if (onoffevents > 0) { |
373 | 11 | onofftree = proto_item_add_subtree(onoffitem, ett_onoffarray); |
374 | 378 | for(i = 0;i < onoffevents;i++) { |
375 | 367 | onoffvalue = tvb_get_ntohl(message_tvb, 144 + (int)(sizeof(uint32_t) * i)); |
376 | 367 | proto_tree_add_uint_format(onofftree, hf_addflow_onoffeventarray, message_tvb, |
377 | 367 | 144 + (int)(sizeof(uint32_t) * i), (int)sizeof(uint32_t), |
378 | 367 | onoffvalue, "%1.3f s: set to %s", onoffvalue / 1000.0, (i & 1) ? "OFF" : "ON"); |
379 | 367 | } |
380 | 11 | } |
381 | 18 | } |
382 | | |
383 | | |
384 | | static void |
385 | | dissect_npm_remove_flow_message(tvbuff_t *message_tvb, proto_tree *message_tree) |
386 | 2 | { |
387 | 2 | proto_tree_add_item(message_tree, hf_removeflow_flowid, message_tvb, 4, 4, ENC_BIG_ENDIAN); |
388 | 2 | proto_tree_add_item(message_tree, hf_removeflow_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
389 | 2 | proto_tree_add_item(message_tree, hf_removeflow_streamid, message_tvb, 16, 2, ENC_BIG_ENDIAN); |
390 | 2 | } |
391 | | |
392 | | |
393 | | static void |
394 | | dissect_npm_identify_flow_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_item *flags_item) |
395 | 2 | { |
396 | 2 | proto_tree* flags_tree; |
397 | | |
398 | 2 | flags_tree = proto_item_add_subtree(flags_item, ett_identifyflow_flags); |
399 | 2 | proto_tree_add_item(flags_tree, hf_identifyflow_flag_compress_vectors, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
400 | 2 | proto_tree_add_item(flags_tree, hf_identifyflow_flag_no_vectors, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
401 | | |
402 | 2 | proto_tree_add_item(message_tree, hf_identifyflow_flowid, message_tvb, 4, 4, ENC_BIG_ENDIAN); |
403 | 2 | proto_tree_add_item(message_tree, hf_identifyflow_magicnumber, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
404 | 2 | proto_tree_add_item(message_tree, hf_identifyflow_measurementid, message_tvb, 16, 8, ENC_BIG_ENDIAN); |
405 | 2 | proto_tree_add_item(message_tree, hf_identifyflow_streamid, message_tvb, 24, 2, ENC_BIG_ENDIAN); |
406 | 2 | } |
407 | | |
408 | | |
409 | | static void |
410 | | dissect_npm_data_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_item *flags_item) |
411 | 1 | { |
412 | 1 | proto_tree *flags_tree; |
413 | 1 | const uint16_t message_length = tvb_get_ntohs(message_tvb, 2); |
414 | | |
415 | 1 | flags_tree = proto_item_add_subtree(flags_item, ett_data_flags); |
416 | 1 | proto_tree_add_item(flags_tree, hf_data_flag_frame_begin, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
417 | 1 | proto_tree_add_item(flags_tree, hf_data_flag_frame_end, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
418 | | |
419 | 1 | proto_tree_add_item(message_tree, hf_data_flowid, message_tvb, 4, 4, ENC_BIG_ENDIAN); |
420 | 1 | proto_tree_add_item(message_tree, hf_data_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
421 | 1 | proto_tree_add_item(message_tree, hf_data_streamid, message_tvb, 16, 2, ENC_BIG_ENDIAN); |
422 | 1 | proto_tree_add_item(message_tree, hf_data_padding, message_tvb, 18, 2, ENC_BIG_ENDIAN); |
423 | 1 | proto_tree_add_item(message_tree, hf_data_frameid, message_tvb, 20, 4, ENC_BIG_ENDIAN); |
424 | 1 | proto_tree_add_item(message_tree, hf_data_packetseqnumber, message_tvb, 24, 8, ENC_BIG_ENDIAN); |
425 | 1 | proto_tree_add_item(message_tree, hf_data_byteseqnumber, message_tvb, 32, 8, ENC_BIG_ENDIAN); |
426 | 1 | proto_tree_add_item(message_tree, hf_data_timestamp, message_tvb, 40, 8, ENC_TIME_USECS|ENC_BIG_ENDIAN); |
427 | | |
428 | 1 | if (message_length > 48) { |
429 | 1 | proto_tree_add_item(message_tree, hf_data_payload, message_tvb, 48, message_length - 48, ENC_NA); |
430 | 1 | } |
431 | 1 | } |
432 | | |
433 | | |
434 | | static void |
435 | | dissect_npm_start_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_item *flags_item) |
436 | 2 | { |
437 | 2 | proto_tree* flags_tree; |
438 | | |
439 | 2 | flags_tree = proto_item_add_subtree(flags_item, ett_start_flags); |
440 | 2 | proto_tree_add_item(flags_tree, hf_start_flag_compress_vectors, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
441 | 2 | proto_tree_add_item(flags_tree, hf_start_flag_compress_scalars, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
442 | 2 | proto_tree_add_item(flags_tree, hf_start_flag_no_vectors, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
443 | 2 | proto_tree_add_item(flags_tree, hf_start_flag_no_scalars, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
444 | | |
445 | 2 | proto_tree_add_item(message_tree, hf_start_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
446 | 2 | } |
447 | | |
448 | | |
449 | | static void |
450 | | dissect_npm_stop_message(tvbuff_t *message_tvb, proto_tree *message_tree) |
451 | 0 | { |
452 | 0 | proto_tree_add_item(message_tree, hf_stop_measurementid, message_tvb, 8, 8, ENC_BIG_ENDIAN); |
453 | 0 | } |
454 | | |
455 | | |
456 | | static void |
457 | | dissect_npm_results_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_item *flags_item) |
458 | 2 | { |
459 | 2 | proto_tree* flags_tree; |
460 | | |
461 | 2 | flags_tree = proto_item_add_subtree(flags_item, ett_data_flags); |
462 | 2 | proto_tree_add_item(flags_tree, hf_results_flag_eof, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
463 | | |
464 | 2 | const uint16_t message_length = tvb_get_ntohs(message_tvb, 2); |
465 | 2 | if (message_length > 4) { |
466 | 2 | proto_tree_add_item(message_tree, hf_results_data, message_tvb, 4, message_length - 4, ENC_NA); |
467 | 2 | } |
468 | 2 | } |
469 | | |
470 | | |
471 | | static int |
472 | | dissect_npm_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
473 | 54 | { |
474 | 54 | proto_tree *flags_tree; |
475 | 54 | proto_item *npm_item; |
476 | 54 | proto_tree *npm_tree; |
477 | 54 | const uint8_t type = tvb_get_uint8(message_tvb, 0); |
478 | 54 | const uint16_t length = tvb_get_ntohs(message_tvb, 2); |
479 | | |
480 | 54 | tap_npm_rec_t* tap_rec = wmem_new0(pinfo->pool, tap_npm_rec_t); |
481 | 54 | tap_rec->type = type; |
482 | 54 | tap_rec->size = length; |
483 | 54 | tap_rec->type_string = val_to_str_const(tap_rec->type, message_type_values, "Unknown NetPerfMeter message type"); |
484 | 54 | tap_queue_packet(tap_npm, pinfo, tap_rec); |
485 | | |
486 | | /* In the interest of speed, if "tree" is NULL, don't do any work not |
487 | | necessary to generate protocol tree items. */ |
488 | 54 | if (tree) { |
489 | | /* create the npm protocol tree */ |
490 | 54 | npm_item = proto_tree_add_item(tree, proto_npm, message_tvb, 0, -1, ENC_NA); |
491 | 54 | npm_tree = proto_item_add_subtree(npm_item, ett_npm); |
492 | 54 | } else { |
493 | 0 | npm_tree = NULL; |
494 | 0 | }; |
495 | | |
496 | 54 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", tap_rec->type_string); |
497 | | |
498 | 54 | proto_tree_add_item(npm_tree, hf_message_type, message_tvb, 0, 1, ENC_BIG_ENDIAN); |
499 | 54 | flags_tree = proto_tree_add_item(npm_tree, hf_message_flags, message_tvb, 1, 1, ENC_BIG_ENDIAN); |
500 | 54 | proto_tree_add_item(npm_tree, hf_message_length, message_tvb, 2, 2, ENC_BIG_ENDIAN); |
501 | | |
502 | 54 | switch (tap_rec->type) { |
503 | 3 | case NETPERFMETER_ACKNOWLEDGE: |
504 | 3 | dissect_npm_acknowledge_message(message_tvb, npm_tree); |
505 | 3 | break; |
506 | 18 | case NETPERFMETER_ADD_FLOW: |
507 | 18 | dissect_npm_add_flow_message(message_tvb, npm_tree, flags_tree); |
508 | 18 | break; |
509 | 2 | case NETPERFMETER_REMOVE_FLOW: |
510 | 2 | dissect_npm_remove_flow_message(message_tvb, npm_tree); |
511 | 2 | break; |
512 | 2 | case NETPERFMETER_IDENTIFY_FLOW: |
513 | 2 | dissect_npm_identify_flow_message(message_tvb, npm_tree, flags_tree); |
514 | 2 | break; |
515 | 1 | case NETPERFMETER_DATA: |
516 | 1 | dissect_npm_data_message(message_tvb, npm_tree, flags_tree); |
517 | 1 | break; |
518 | 2 | case NETPERFMETER_START: |
519 | 2 | dissect_npm_start_message(message_tvb, npm_tree, flags_tree); |
520 | 2 | break; |
521 | 0 | case NETPERFMETER_STOP: |
522 | 0 | dissect_npm_stop_message(message_tvb, npm_tree); |
523 | 0 | break; |
524 | 2 | case NETPERFMETER_RESULTS: |
525 | 2 | dissect_npm_results_message(message_tvb, npm_tree, flags_tree); |
526 | 2 | break; |
527 | 54 | } |
528 | 37 | return length; |
529 | 54 | } |
530 | | |
531 | | static unsigned |
532 | | get_npm_message_length(packet_info *pinfo _U_, tvbuff_t *tvb, |
533 | | int offset, void *data _U_) |
534 | 58 | { |
535 | 58 | return tvb_get_ntohs(tvb, offset + 2); |
536 | 58 | } |
537 | | |
538 | | static int |
539 | | dissect_npm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
540 | 39 | { |
541 | 39 | col_append_sep_fstr(pinfo->cinfo, COL_PROTOCOL, NULL, "NetPerfMeter"); |
542 | | |
543 | 39 | tcp_dissect_pdus(tvb, pinfo, tree, npm_desegment, |
544 | 39 | 4, get_npm_message_length, dissect_npm_message, data); |
545 | 39 | return tvb_captured_length(tvb); |
546 | 39 | } |
547 | | |
548 | | |
549 | | static bool |
550 | | dissect_npm_heur(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
551 | 4.51k | { |
552 | 4.51k | const unsigned length = tvb_captured_length(message_tvb); |
553 | 4.51k | if (length < 4) |
554 | 383 | return false; |
555 | | |
556 | | /* For TCP, UDP or DCCP: |
557 | | Type must either be NETPERFMETER_DATA or NETPERFMETER_IDENTIFY_FLOW */ |
558 | 4.12k | const uint8_t type = tvb_get_uint8(message_tvb, 0); |
559 | 4.12k | switch(type) { |
560 | 72 | case NETPERFMETER_DATA: |
561 | 72 | if (length < 48 + 8) |
562 | 52 | return false; |
563 | | /* Identify NetPerfMeter flow by payload pattern */ |
564 | 24 | for(int i = 0; i < 8; i++) { |
565 | 24 | uint8_t d = tvb_get_uint8(message_tvb, 48 + i); |
566 | 24 | if( (d != 30 + i) && (d != 127 - i) ) |
567 | 20 | return false; |
568 | 24 | } |
569 | 0 | break; |
570 | 82 | case NETPERFMETER_IDENTIFY_FLOW: |
571 | 82 | if (length < 24 + 2) |
572 | 20 | return false; |
573 | 62 | if (tvb_get_ntoh64(message_tvb, 8) != NETPERFMETER_IDENTIFY_FLOW_MAGIC_NUMBER) { |
574 | | /* Identify NetPerfMeter flow by NETPERFMETER_IDENTIFY_FLOW_MAGIC_NUMBER */ |
575 | 60 | return false; |
576 | 60 | } |
577 | 2 | break; |
578 | 3.97k | default: |
579 | | /* Not a NetPerfMeter packet */ |
580 | 3.97k | return false; |
581 | 0 | break; |
582 | 4.12k | } |
583 | 2 | dissect_npm(message_tvb, pinfo, tree, data); |
584 | 2 | return true; |
585 | 4.12k | } |
586 | | |
587 | | |
588 | | /* TAP STAT INFO */ |
589 | | typedef enum |
590 | | { |
591 | | MESSAGE_TYPE_COLUMN = 0, |
592 | | MESSAGES_COLUMN, |
593 | | MESSAGES_SHARE_COLUMN, |
594 | | BYTES_COLUMN, |
595 | | BYTES_SHARE_COLUMN, |
596 | | FIRST_SEEN_COLUMN, |
597 | | LAST_SEEN_COLUMN, |
598 | | INTERVAL_COLUMN, |
599 | | MESSAGE_RATE_COLUMN, |
600 | | BYTE_RATE_COLUMN |
601 | | } npm_stat_columns; |
602 | | |
603 | | static stat_tap_table_item npm_stat_fields[] = { |
604 | | { TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "NetPerfMeter Message Type", "%-25s" }, |
605 | | { TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Messages ", "%u" }, |
606 | | { TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Messages Share (%)" , "%1.3f %%" }, |
607 | | { TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Bytes (B)", "%u" }, |
608 | | { TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Bytes Share (%) ", "%1.3f %%" }, |
609 | | { TABLE_ITEM_FLOAT, TAP_ALIGN_LEFT, "First Seen (s)", "%1.6f" }, |
610 | | { TABLE_ITEM_FLOAT, TAP_ALIGN_LEFT, "Last Seen (s)", "%1.6f" }, |
611 | | { TABLE_ITEM_FLOAT, TAP_ALIGN_LEFT, "Interval (s)", "%1.6f" }, |
612 | | { TABLE_ITEM_FLOAT, TAP_ALIGN_LEFT, "Message Rate (Msg/s)", "%1.2f" }, |
613 | | { TABLE_ITEM_FLOAT, TAP_ALIGN_LEFT, "Byte Rate (B/s)", "%1.2f" } |
614 | | }; |
615 | | |
616 | | static void npm_stat_init(stat_tap_table_ui* new_stat) |
617 | 0 | { |
618 | 0 | const char *table_name = "NetPerfMeter Statistics"; |
619 | 0 | int num_fields = array_length(npm_stat_fields); |
620 | 0 | stat_tap_table *table; |
621 | 0 | int i = 0; |
622 | 0 | stat_tap_table_item_type items[array_length(npm_stat_fields)]; |
623 | |
|
624 | 0 | table = stat_tap_find_table(new_stat, table_name); |
625 | 0 | if (table) { |
626 | 0 | if (new_stat->stat_tap_reset_table_cb) { |
627 | 0 | new_stat->stat_tap_reset_table_cb(table); |
628 | 0 | } |
629 | 0 | return; |
630 | 0 | } |
631 | | |
632 | 0 | table = stat_tap_init_table(table_name, num_fields, 0, NULL); |
633 | 0 | stat_tap_add_table(new_stat, table); |
634 | |
|
635 | 0 | memset(items, 0x0, sizeof(items)); |
636 | | /* Add a row for each value type */ |
637 | 0 | while (message_type_values[i].strptr) { |
638 | 0 | items[MESSAGE_TYPE_COLUMN].type = TABLE_ITEM_STRING; |
639 | 0 | items[MESSAGE_TYPE_COLUMN].value.string_value = message_type_values[i].strptr; |
640 | 0 | items[MESSAGES_COLUMN].type = TABLE_ITEM_UINT; |
641 | 0 | items[MESSAGES_COLUMN].value.uint_value = 0; |
642 | 0 | items[MESSAGES_SHARE_COLUMN].type = TABLE_ITEM_NONE; |
643 | 0 | items[MESSAGES_SHARE_COLUMN].value.float_value = -1.0; |
644 | 0 | items[BYTES_COLUMN].type = TABLE_ITEM_UINT; |
645 | 0 | items[BYTES_COLUMN].value.uint_value = 0; |
646 | 0 | items[BYTES_SHARE_COLUMN].type = TABLE_ITEM_NONE; |
647 | 0 | items[BYTES_SHARE_COLUMN].value.float_value = -1.0; |
648 | 0 | items[FIRST_SEEN_COLUMN].type = TABLE_ITEM_NONE; |
649 | 0 | items[FIRST_SEEN_COLUMN].value.float_value = DBL_MAX; |
650 | 0 | items[LAST_SEEN_COLUMN].type = TABLE_ITEM_NONE; |
651 | 0 | items[LAST_SEEN_COLUMN].value.float_value = DBL_MIN; |
652 | 0 | items[INTERVAL_COLUMN].type = TABLE_ITEM_NONE; |
653 | 0 | items[INTERVAL_COLUMN].value.float_value = -1.0; |
654 | 0 | items[MESSAGE_RATE_COLUMN].type = TABLE_ITEM_NONE; |
655 | 0 | items[MESSAGE_RATE_COLUMN].value.float_value = -1.0; |
656 | 0 | items[BYTE_RATE_COLUMN].type = TABLE_ITEM_NONE; |
657 | 0 | items[BYTE_RATE_COLUMN].value.float_value = -1.0; |
658 | 0 | stat_tap_init_table_row(table, i, num_fields, items); |
659 | 0 | i++; |
660 | 0 | } |
661 | 0 | } |
662 | | |
663 | | static tap_packet_status |
664 | | npm_stat_packet(void* tapdata, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* data, tap_flags_t flags _U_) |
665 | 0 | { |
666 | 0 | stat_data_t *stat_data = (stat_data_t*)tapdata; |
667 | 0 | const tap_npm_rec_t *tap_rec = (const tap_npm_rec_t*)data; |
668 | 0 | stat_tap_table *table; |
669 | 0 | stat_tap_table_item_type *msg_data; |
670 | 0 | int idx; |
671 | 0 | uint64_t messages; |
672 | 0 | uint64_t bytes; |
673 | 0 | int i = 0; |
674 | 0 | double firstSeen = -1.0; |
675 | 0 | double lastSeen = -1.0; |
676 | |
|
677 | 0 | idx = str_to_val_idx(tap_rec->type_string, message_type_values); |
678 | 0 | if (idx < 0) |
679 | 0 | return TAP_PACKET_DONT_REDRAW; |
680 | | |
681 | 0 | table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, 0); |
682 | | |
683 | | /* Update packets counter */ |
684 | 0 | npm_total_msgs++; |
685 | 0 | msg_data = stat_tap_get_field_data(table, idx, MESSAGES_COLUMN); |
686 | 0 | msg_data->value.uint_value++; |
687 | 0 | messages = msg_data->value.uint_value; |
688 | 0 | stat_tap_set_field_data(table, idx, MESSAGES_COLUMN, msg_data); |
689 | | |
690 | | /* Update bytes counter */ |
691 | 0 | npm_total_bytes += tap_rec->size; |
692 | 0 | msg_data = stat_tap_get_field_data(table, idx, BYTES_COLUMN); |
693 | 0 | msg_data->value.uint_value += tap_rec->size; |
694 | 0 | bytes = msg_data->value.uint_value; |
695 | 0 | stat_tap_set_field_data(table, idx, BYTES_COLUMN, msg_data); |
696 | | |
697 | | /* Update messages and bytes share */ |
698 | 0 | while (message_type_values[i].strptr) { |
699 | 0 | msg_data = stat_tap_get_field_data(table, i, MESSAGES_COLUMN); |
700 | 0 | const unsigned m = msg_data->value.uint_value; |
701 | 0 | msg_data = stat_tap_get_field_data(table, i, BYTES_COLUMN); |
702 | 0 | const unsigned b = msg_data->value.uint_value; |
703 | |
|
704 | 0 | msg_data = stat_tap_get_field_data(table, i, MESSAGES_SHARE_COLUMN); |
705 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
706 | 0 | msg_data->value.float_value = 100.0 * m / (double)npm_total_msgs; |
707 | 0 | stat_tap_set_field_data(table, i, MESSAGES_SHARE_COLUMN, msg_data); |
708 | |
|
709 | 0 | msg_data = stat_tap_get_field_data(table, i, BYTES_SHARE_COLUMN); |
710 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
711 | 0 | msg_data->value.float_value = 100.0 * b / (double)npm_total_bytes; |
712 | 0 | stat_tap_set_field_data(table, i, BYTES_SHARE_COLUMN, msg_data); |
713 | 0 | i++; |
714 | 0 | } |
715 | | |
716 | | /* Update first seen time */ |
717 | 0 | if (pinfo->presence_flags & PINFO_HAS_TS) { |
718 | 0 | msg_data = stat_tap_get_field_data(table, idx, FIRST_SEEN_COLUMN); |
719 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
720 | 0 | msg_data->value.float_value = MIN(msg_data->value.float_value, nstime_to_sec(&pinfo->rel_ts)); |
721 | 0 | firstSeen = msg_data->value.float_value; |
722 | 0 | stat_tap_set_field_data(table, idx, FIRST_SEEN_COLUMN, msg_data); |
723 | 0 | } |
724 | | |
725 | | /* Update last seen time */ |
726 | 0 | if (pinfo->presence_flags & PINFO_HAS_TS) { |
727 | 0 | msg_data = stat_tap_get_field_data(table, idx, LAST_SEEN_COLUMN); |
728 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
729 | 0 | msg_data->value.float_value = MAX(msg_data->value.float_value, nstime_to_sec(&pinfo->rel_ts)); |
730 | 0 | lastSeen = msg_data->value.float_value; |
731 | 0 | stat_tap_set_field_data(table, idx, LAST_SEEN_COLUMN, msg_data); |
732 | 0 | } |
733 | |
|
734 | 0 | if ((lastSeen - firstSeen) > 0.0) { |
735 | | /* Update interval */ |
736 | 0 | msg_data = stat_tap_get_field_data(table, idx, INTERVAL_COLUMN); |
737 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
738 | 0 | msg_data->value.float_value = lastSeen - firstSeen; |
739 | 0 | stat_tap_set_field_data(table, idx, INTERVAL_COLUMN, msg_data); |
740 | | |
741 | | /* Update message rate */ |
742 | 0 | msg_data = stat_tap_get_field_data(table, idx, MESSAGE_RATE_COLUMN); |
743 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
744 | 0 | msg_data->value.float_value = messages / (lastSeen - firstSeen); |
745 | 0 | stat_tap_set_field_data(table, idx, MESSAGE_RATE_COLUMN, msg_data); |
746 | | |
747 | | /* Update byte rate */ |
748 | 0 | msg_data = stat_tap_get_field_data(table, idx, BYTE_RATE_COLUMN); |
749 | 0 | msg_data->type = TABLE_ITEM_FLOAT; |
750 | 0 | msg_data->value.float_value = bytes / (lastSeen - firstSeen); |
751 | 0 | stat_tap_set_field_data(table, idx, BYTE_RATE_COLUMN, msg_data); |
752 | 0 | } |
753 | |
|
754 | 0 | return TAP_PACKET_REDRAW; |
755 | 0 | } |
756 | | |
757 | | static void |
758 | | npm_stat_reset(stat_tap_table* table) |
759 | 0 | { |
760 | 0 | unsigned element; |
761 | 0 | stat_tap_table_item_type* item_data; |
762 | |
|
763 | 0 | for (element = 0; element < table->num_elements; element++) { |
764 | 0 | item_data = stat_tap_get_field_data(table, element, MESSAGES_COLUMN); |
765 | 0 | item_data->value.uint_value = 0; |
766 | 0 | stat_tap_set_field_data(table, element, MESSAGES_COLUMN, item_data); |
767 | |
|
768 | 0 | item_data = stat_tap_get_field_data(table, element, MESSAGES_SHARE_COLUMN); |
769 | 0 | item_data->type = TABLE_ITEM_NONE; |
770 | 0 | item_data->value.float_value = -1.0; |
771 | 0 | stat_tap_set_field_data(table, element, MESSAGES_SHARE_COLUMN, item_data); |
772 | |
|
773 | 0 | item_data = stat_tap_get_field_data(table, element, BYTES_COLUMN); |
774 | 0 | item_data->value.uint_value = 0; |
775 | 0 | stat_tap_set_field_data(table, element, BYTES_COLUMN, item_data); |
776 | |
|
777 | 0 | item_data = stat_tap_get_field_data(table, element, BYTES_SHARE_COLUMN); |
778 | 0 | item_data->type = TABLE_ITEM_NONE; |
779 | 0 | item_data->value.float_value = -1.0; |
780 | 0 | stat_tap_set_field_data(table, element, BYTES_SHARE_COLUMN, item_data); |
781 | |
|
782 | 0 | item_data = stat_tap_get_field_data(table, element, FIRST_SEEN_COLUMN); |
783 | 0 | item_data->type = TABLE_ITEM_NONE; |
784 | 0 | item_data->value.float_value = DBL_MAX; |
785 | 0 | stat_tap_set_field_data(table, element, FIRST_SEEN_COLUMN, item_data); |
786 | |
|
787 | 0 | item_data = stat_tap_get_field_data(table, element, LAST_SEEN_COLUMN); |
788 | 0 | item_data->type = TABLE_ITEM_NONE; |
789 | 0 | item_data->value.float_value = DBL_MIN; |
790 | 0 | stat_tap_set_field_data(table, element, LAST_SEEN_COLUMN, item_data); |
791 | |
|
792 | 0 | item_data = stat_tap_get_field_data(table, element, INTERVAL_COLUMN); |
793 | 0 | item_data->type = TABLE_ITEM_NONE; |
794 | 0 | item_data->value.float_value = -1.0; |
795 | 0 | stat_tap_set_field_data(table, element, INTERVAL_COLUMN, item_data); |
796 | |
|
797 | 0 | item_data = stat_tap_get_field_data(table, element, MESSAGE_RATE_COLUMN); |
798 | 0 | item_data->type = TABLE_ITEM_NONE; |
799 | 0 | item_data->value.float_value = -1.0; |
800 | 0 | stat_tap_set_field_data(table, element, MESSAGE_RATE_COLUMN, item_data); |
801 | |
|
802 | 0 | item_data = stat_tap_get_field_data(table, element, BYTE_RATE_COLUMN); |
803 | 0 | item_data->type = TABLE_ITEM_NONE; |
804 | 0 | item_data->value.float_value = -1.0; |
805 | 0 | stat_tap_set_field_data(table, element, BYTE_RATE_COLUMN, item_data); |
806 | 0 | } |
807 | 0 | npm_total_msgs = 0; |
808 | 0 | npm_total_bytes = 0; |
809 | 0 | } |
810 | | |
811 | | |
812 | | /* Register the protocol with Wireshark */ |
813 | | void |
814 | | proto_register_npm(void) |
815 | 16 | { |
816 | | /* Setup protocol subtree array */ |
817 | 16 | static int *ett[] = { |
818 | 16 | &ett_npm, |
819 | 16 | &ett_addflow_flags, |
820 | 16 | &ett_identifyflow_flags, |
821 | 16 | &ett_start_flags, |
822 | 16 | &ett_data_flags, |
823 | 16 | &ett_results_flags, |
824 | 16 | &ett_onoffarray |
825 | 16 | }; |
826 | | |
827 | 16 | static tap_param npm_stat_params[] = { |
828 | 16 | { PARAM_FILTER, "filter", "Filter", NULL, true } |
829 | 16 | }; |
830 | | |
831 | 16 | static stat_tap_table_ui npm_stat_table = { |
832 | 16 | REGISTER_PACKET_STAT_GROUP_UNSORTED, |
833 | 16 | "NetPerfMeter Statistics", |
834 | 16 | "npm", |
835 | 16 | "npm,stat", |
836 | 16 | npm_stat_init, |
837 | 16 | npm_stat_packet, |
838 | 16 | npm_stat_reset, |
839 | 16 | NULL, |
840 | 16 | NULL, |
841 | 16 | array_length(npm_stat_fields), npm_stat_fields, |
842 | 16 | array_length(npm_stat_params), npm_stat_params, |
843 | 16 | NULL, |
844 | 16 | 0 |
845 | 16 | }; |
846 | | |
847 | | /* Register the protocol name and description */ |
848 | 16 | proto_npm = proto_register_protocol("NetPerfMeter Protocol", "NetPerfMeter", "netperfmeter"); |
849 | | |
850 | | /* Required function calls to register the header fields and subtrees used */ |
851 | 16 | proto_register_field_array(proto_npm, hf, array_length(hf)); |
852 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
853 | 16 | tap_npm = register_tap("npm"); |
854 | | |
855 | 16 | register_stat_tap_table_ui(&npm_stat_table); |
856 | | |
857 | 16 | module_t *npm_module = prefs_register_protocol(proto_npm, NULL); |
858 | 16 | prefs_register_bool_preference(npm_module, "desegment", |
859 | 16 | "Reassemble NetPerfMeter messages spanning multiple TCP segments", |
860 | 16 | "Whether the NetPerfMeter dissector should reassemble messages spanning multiple TCP segments." |
861 | 16 | "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
862 | 16 | &npm_desegment); |
863 | | |
864 | | /* Register the dissector */ |
865 | 16 | npm_handle = register_dissector("netperfmeter", dissect_npm, proto_npm); |
866 | 16 | } |
867 | | |
868 | | |
869 | | void |
870 | | proto_reg_handoff_npm(void) |
871 | 16 | { |
872 | | /* NetPerfMeter protocol over SCTP is detected by PPIDs */ |
873 | 16 | dissector_add_uint("sctp.ppi", PPID_NETPERFMETER_CONTROL_LEGACY, npm_handle); |
874 | 16 | dissector_add_uint("sctp.ppi", PPID_NETPERFMETER_DATA_LEGACY, npm_handle); |
875 | 16 | dissector_add_uint("sctp.ppi", NPMP_CTRL_PAYLOAD_PROTOCOL_ID, npm_handle); |
876 | 16 | dissector_add_uint("sctp.ppi", NPMP_DATA_PAYLOAD_PROTOCOL_ID, npm_handle); |
877 | | |
878 | | /* NetPerfMeter protocol over QUIC is detected by ALPN */ |
879 | 16 | dissector_add_string("quic.proto", ALPN_NETPERFMETER_CONTROL, npm_handle); |
880 | 16 | dissector_add_string("quic.proto.datagram", ALPN_NETPERFMETER_CONTROL, npm_handle); |
881 | 16 | dissector_add_string("quic.proto", ALPN_NETPERFMETER_DATA, npm_handle); |
882 | 16 | dissector_add_string("quic.proto.datagram", ALPN_NETPERFMETER_DATA, npm_handle); |
883 | | |
884 | | /* NetPerfMeter "Decode As" */ |
885 | 16 | dissector_add_for_decode_as_with_preference("tcp.port", npm_handle); |
886 | 16 | dissector_add_for_decode_as_with_preference("udp.port", npm_handle); |
887 | | |
888 | | /* Heuristic dissector for TCP, UDP and DCCP */ |
889 | 16 | heur_dissector_add("tcp", dissect_npm_heur, "NetPerfMeter over TCP", "netperfmeter_tcp", proto_npm, HEURISTIC_ENABLE); |
890 | 16 | heur_dissector_add("udp", dissect_npm_heur, "NetPerfMeter over UDP", "netperfmeter_udp", proto_npm, HEURISTIC_ENABLE); |
891 | 16 | heur_dissector_add("dccp", dissect_npm_heur, "NetPerfMeter over DCCP", "netperfmeter_dccp", proto_npm, HEURISTIC_ENABLE); |
892 | 16 | } |
893 | | |
894 | | /* |
895 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
896 | | * |
897 | | * Local Variables: |
898 | | * c-basic-offset: 2 |
899 | | * tab-width: 8 |
900 | | * indent-tabs-mode: nil |
901 | | * End: |
902 | | * |
903 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
904 | | * :indentSize=2:tabSize=8:noTabs=true: |
905 | | */ |