Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */