epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-iperf.c
blob3d790ce22dd57691023a6b0d3745a11b14f1b977
1 /* packet-iperf.c
2 * Routines for iPerf dissection
3 * By Anish Bhatt <anish@gatech.edu>
5 * Updates for iperf 2.1.9
6 * By Andrii Vladyka <a.vladyka@ukr.net>
7 * By Robert McMahon <rjmcmahon@rjmcmahon.com>
8 * TODO: server-side packets (pending clarifications form Bob)
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include "config.h"
18 #include <epan/packet.h>
19 #include <epan/tvbparse.h>
21 #define IPERF2_UDP_HDR_SIZE 160
23 void proto_register_iperf2(void);
24 void proto_reg_handoff_iperf2(void);
26 static int proto_iperf2;
28 static int hf_iperf2_sequence;
29 static int hf_iperf2_sec;
30 static int hf_iperf2_usec;
31 static int hf_iperf2_timestamp;
32 static int hf_iperf2_sequence_upper;
33 static int hf_iperf2_flags;
34 static int hf_iperf2_num_threads;
35 static int hf_iperf2_mport;
36 static int hf_iperf2_bufferlen;
37 static int hf_iperf2_mwinband;
38 static int hf_iperf2_mamount;
39 static int hf_iperf2_type;
40 static int hf_iperf2_length;
41 static int hf_iperf2_up_flags;
42 static int hf_iperf2_low_flags;
43 static int hf_iperf2_version_major;
44 static int hf_iperf2_version_minor;
45 static int hf_iperf2_version;
46 static int hf_iperf2_reserved;
47 static int hf_iperf2_tos;
48 static int hf_iperf2_rate;
49 static int hf_iperf2_rate_units;
50 static int hf_iperf2_realtime;
51 static int hf_iperf2_permit_key_len;
52 static int hf_iperf2_permit_key;
53 static int hf_iperf2_isoch_burst_period;
54 static int hf_iperf2_isoch_start_ts_s;
55 static int hf_iperf2_isoch_start_ts_us;
56 static int hf_iperf2_isoch_start_ts;
57 static int hf_iperf2_isoch_prev_frameid;
58 static int hf_iperf2_isoch_frameid;
59 static int hf_iperf2_isoch_burstsize;
60 static int hf_iperf2_isoch_bytes_remaining;
61 static int hf_iperf2_isoch_reserved;
62 static int hf_iperf2_reserved2;
63 static int hf_iperf2_start_tv_sec;
64 static int hf_iperf2_start_tv_usec;
65 static int hf_iperf2_start_tv;
66 static int hf_iperf2_fq_ratel;
67 static int hf_iperf2_fq_rateu;
68 static int hf_iperf2_fpsl;
69 static int hf_iperf2_fpsu;
70 static int hf_iperf2_meanl;
71 static int hf_iperf2_meanu;
72 static int hf_iperf2_variancel;
73 static int hf_iperf2_varianceu;
74 static int hf_iperf2_burstipgl;
75 static int hf_iperf2_burstipg;
76 static int hf_iperf2_cca_len;
77 static int hf_iperf2_cca_value;
78 static int hf_iperf2_bb_size;
79 static int hf_iperf2_bb_id;
80 static int hf_iperf2_bb_flags;
81 static int hf_iperf2_bb_tos;
82 static int hf_iperf2_bb_run_time;
83 static int hf_iperf2_bb_clienttx_ts_sec;
84 static int hf_iperf2_bb_clienttx_ts_usec;
85 static int hf_iperf2_bb_clienttx_ts;
86 static int hf_iperf2_bb_serverrx_ts_sec;
87 static int hf_iperf2_bb_serverrx_ts_usec;
88 static int hf_iperf2_bb_serverrx_ts;
89 static int hf_iperf2_bb_servertx_ts_sec;
90 static int hf_iperf2_bb_servertx_ts_usec;
91 static int hf_iperf2_bb_servertx_ts;
92 static int hf_iperf2_bb_hold;
93 static int hf_iperf2_bb_rtt;
94 static int hf_iperf2_bb_read_ts_sec;
95 static int hf_iperf2_bb_read_ts_usec;
96 static int hf_iperf2_bb_read_ts;
97 static int hf_iperf2_bb_reply_size;
99 // Flags definition for hf_iperf2_flags. See include/Listener.hpp in iperf2 source code
100 #define HEADER_VERSION1 0x80000000
101 #define HEADER_EXTEND 0x40000000
102 #define HEADER_UDPTESTS 0x20000000
103 #define HEADER_SEQNO64B 0x08000000
104 #define HEADER_VERSION2 0x04000000
105 #define HEADER_V2PEERDETECT 0x02000000
106 #define HEADER_UDPAVOID2 0x02000000
107 #define HEADER_UDPAVOID1 0x01000000
108 #define HEADER_BOUNCEBACK 0x00800000
109 #define HEADER32_SMALL_TRIPTIMES 0x00020000
110 #define HEADER_LEN_BIT 0x00010000
111 #define HEADER_LEN_MASK 0x000001FE
112 #define RUN_NOW 0x00000001
113 #define HEADER16_SMALL_TRIPTIMES 0x00020000
115 #define HEADER_ISOCH 0x0001
116 #define HEADER_L2ETHPIPV6 0x0002
117 #define HEADER_L2LENCHECK 0x0004
118 #define HEADER_NOUDPFIN 0x0008
119 #define HEADER_TRIPTIME 0x0010
120 #define HEADER_UNUSED2 0x0020
121 #define HEADER_ISOCH_SETTINGS 0x0040
122 #define HEADER_UNITS_PPS 0x0080
123 #define HEADER_BWSET 0x0100
124 #define HEADER_FQRATESET 0x0200
125 #define HEADER_REVERSE 0x0400
126 #define HEADER_FULLDUPLEX 0x0800
127 #define HEADER_EPOCH_START 0x1000
128 #define HEADER_PERIODICBURST 0x2000
129 #define HEADER_WRITEPREFETCH 0x4000
130 #define HEADER_TCPQUICKACK 0x8000
131 // Bounceback flags
132 #define HEADER_BBQUICKACK 0x8000
133 #define HEADER_BBCLOCKSYNCED 0x4000
134 #define HEADER_BBTOS 0x2000
135 #define HEADER_BBSTOP 0x1000
136 #define HEADER_BBREPLYSIZE 0x0800
138 // lower flags (16 bit)
139 #define HEADER_CCA 0x8000
141 // Flags fields declarations for hf_iperf2_flags
142 static int hf_iperf2_flag_header_version1;
143 static int hf_iperf2_flag_header_extend;
144 static int hf_iperf2_header_udptests;
145 static int hf_iperf2_header_seqno64b;
146 static int hf_iperf2_header_version2;
147 static int hf_iperf2_header_v2peerdetect;
148 static int hf_iperf2_header_udpavoid;
149 static int hf_iperf2_header_bounceback;
150 static int hf_iperf2_header_len_bit;
151 static int hf_iperf2_header_len_mask;
152 static int hf_iperf2_run_now;
153 static int hf_iperf2_header16_small_triptimes;
154 static int hf_iperf2_payload;
156 static int * const iperf2_flags[] = {
157 &hf_iperf2_flag_header_version1,
158 &hf_iperf2_flag_header_extend,
159 &hf_iperf2_header_udptests,
160 &hf_iperf2_header_seqno64b,
161 &hf_iperf2_header_version2,
162 &hf_iperf2_header_v2peerdetect,
163 &hf_iperf2_header_udpavoid,
164 &hf_iperf2_header_bounceback,
165 &hf_iperf2_header_len_mask,
166 &hf_iperf2_header16_small_triptimes,
167 &hf_iperf2_header_len_bit,
168 &hf_iperf2_run_now,
169 NULL
172 // Flags fields declarations for iperf2_upper_flags
173 static int hf_iperf2_upper_header_isoch;
174 static int hf_iperf2_upper_header_l2ethpipv6;
175 static int hf_iperf2_upper_header_l2lencheck;
176 static int hf_iperf2_upper_header_noudpfin;
177 static int hf_iperf2_upper_header_triptime;
178 static int hf_iperf2_upper_header_unused2;
179 static int hf_iperf2_upper_header_isoch_settings;
180 static int hf_iperf2_upper_header_units_pps;
181 static int hf_iperf2_upper_header_bwset;
182 static int hf_iperf2_upper_header_fqrateset;
183 static int hf_iperf2_upper_header_reverse;
184 static int hf_iperf2_upper_header_fullduplex;
185 static int hf_iperf2_upper_header_epoch_start;
186 static int hf_iperf2_upper_header_periodicburst;
187 static int hf_iperf2_upper_header_writeprefetch;
188 static int hf_iperf2_upper_header_tcpquickack;
190 static int * const iperf2_upper_flags[] = {
191 &hf_iperf2_upper_header_tcpquickack,
192 &hf_iperf2_upper_header_writeprefetch,
193 &hf_iperf2_upper_header_periodicburst,
194 &hf_iperf2_upper_header_epoch_start,
195 &hf_iperf2_upper_header_fullduplex,
196 &hf_iperf2_upper_header_reverse,
197 &hf_iperf2_upper_header_fqrateset,
198 &hf_iperf2_upper_header_bwset,
199 &hf_iperf2_upper_header_units_pps,
200 &hf_iperf2_upper_header_isoch_settings,
201 &hf_iperf2_upper_header_unused2,
202 &hf_iperf2_upper_header_triptime,
203 &hf_iperf2_upper_header_noudpfin,
204 &hf_iperf2_upper_header_l2lencheck,
205 &hf_iperf2_upper_header_l2ethpipv6,
206 &hf_iperf2_upper_header_isoch,
207 NULL
210 // Flags fields declarations for iperf2_lower_flags
211 static int hf_iperf2_lower_header_cca;
213 static int * const iperf2_lower_flags[] = {
214 &hf_iperf2_lower_header_cca,
215 NULL
218 // Flags fields declarations for iperf2_bb_flags
219 static int hf_iperf2_header_bbquickack;
220 static int hf_iperf2_header_bbclocksynced;
221 static int hf_iperf2_header_bbtos;
222 static int hf_iperf2_header_bbstop;
223 static int hf_iperf2_header_bbreplysize;
225 static int * const iperf2_bb_flags[] = {
226 &hf_iperf2_header_bbquickack,
227 &hf_iperf2_header_bbclocksynced,
228 &hf_iperf2_header_bbtos,
229 &hf_iperf2_header_bbstop,
230 &hf_iperf2_header_bbreplysize,
231 NULL
234 static int ett_iperf2_udp;
235 static int ett_iperf2_tcp;
236 static int ett_udphdr;
237 static int ett_clienthdr;
238 static int ett_bbhdr;
239 static int ett_extendedhdr;
240 static int ett_permit_key;
241 static int ett_client_upper_flags;
242 static int ett_client_lower_flags;
243 static int ett_isochhdr;
244 static int ett_fqhdr;
245 static int ett_ext_isochhdr;
246 static int ett_client_hdr;
247 static int ett_client_hdr_flags;
248 static int ett_cca_hdr;
249 static int ett_bb_hdr_flags;
250 static int ett_bbclienttx_ts;
251 static int ett_bbserverrx_ts;
252 static int ett_bbservertx_ts;
253 static int ett_bbread_ts;
254 static int ett_data;
256 /* parser definitions for iperf2 payload */
257 static tvbparse_wanted_t *want;
258 static tvbparse_wanted_t *want_trailing;
260 static dissector_handle_t iperf2_handle_tcp;
261 static dissector_handle_t iperf2_handle_udp;
263 typedef struct {
264 bool first_packet_processed;
265 bool second_packet_processed;
266 } iperf2_conversation_t;
268 static void
269 format_version(char *buf, uint32_t value) {
270 snprintf(buf, ITEM_LABEL_LENGTH, "%d.%d", (value & 0xFFFF0000) >> 16, (value & 0xFFFF));
273 static void
274 format_version_long(char *buf, uint64_t value) {
275 snprintf(buf, ITEM_LABEL_LENGTH, "%d.%d.%d.%d",
276 (uint32_t)((value & 0xFFFF000000000000) >> 48), (uint32_t)((value & 0xFFFF00000000) >> 32),
277 (uint32_t)((value & 0xFFFF0000) >> 16), (uint32_t)(value & 0xFFFF));
280 static int
281 dissect_iperf2_payload(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
283 proto_tree *data_tree;
285 data_tree = proto_tree_add_subtree(tree, tvb, offset, tvb_reported_length(tvb) - offset, ett_data, NULL, "iPerf2 Payload");
286 proto_tree_add_item(data_tree, hf_iperf2_payload, tvb, offset, tvb_reported_length(tvb) - offset, ENC_NA);
287 offset = tvb_reported_length(tvb);
289 return offset;
292 static int
293 dissect_iperf2_client_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, bool is_udp)
295 uint32_t small_packets = 0;
296 uint32_t initial_offset = offset;
297 int client_header_size = 24;
298 proto_tree *client_tree;
300 if (is_udp) {
301 small_packets = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
302 if (small_packets & HEADER32_SMALL_TRIPTIMES) {
303 client_header_size = 4;
307 client_tree = proto_tree_add_subtree(tree, tvb, offset, client_header_size, ett_clienthdr, NULL, "iPerf2 Client Header");
308 proto_tree_add_bitmask(client_tree, tvb, offset, hf_iperf2_flags, ett_client_hdr_flags, iperf2_flags, ENC_BIG_ENDIAN);
309 offset += 4;
311 if (is_udp) {
312 if (small_packets & HEADER32_SMALL_TRIPTIMES) {
313 if ((tvb_reported_length(tvb) - offset) > 0) {
314 return dissect_iperf2_payload(tvb, tree, offset);
315 } else {
316 return offset - initial_offset;
321 proto_tree_add_item(client_tree, hf_iperf2_num_threads, tvb, offset, 4, ENC_BIG_ENDIAN);
322 offset += 4;
323 proto_tree_add_item(client_tree, hf_iperf2_mport, tvb, offset, 4, ENC_BIG_ENDIAN);
324 offset += 4;
325 proto_tree_add_item(client_tree, hf_iperf2_bufferlen, tvb, offset, 4, ENC_BIG_ENDIAN);
326 offset += 4;
327 proto_tree_add_item(client_tree, hf_iperf2_mwinband, tvb, offset, 4, ENC_BIG_ENDIAN);
328 offset += 4;
329 proto_tree_add_item(client_tree, hf_iperf2_mamount, tvb, offset, 4, ENC_BIG_ENDIAN);
330 offset += 4;
332 return offset - initial_offset;
335 static int
336 dissect_iperf2_extended_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
338 uint32_t initial_offset = offset, permit_key_len = 0;
339 proto_tree *extended_tree, *permit_key_tree;
340 proto_item *ti;
342 extended_tree = proto_tree_add_subtree(tree, tvb, offset, 36, ett_extendedhdr, NULL, "iPerf2 Extended Header");
343 proto_tree_add_item(extended_tree, hf_iperf2_type, tvb, offset, 4, ENC_BIG_ENDIAN);
344 offset += 4;
345 proto_tree_add_item(extended_tree, hf_iperf2_length, tvb, offset, 4, ENC_BIG_ENDIAN);
346 offset += 4;
347 proto_tree_add_bitmask(extended_tree, tvb, offset, hf_iperf2_up_flags, ett_client_upper_flags, iperf2_upper_flags, ENC_BIG_ENDIAN);
348 offset += 2;
349 proto_tree_add_bitmask(extended_tree, tvb, offset, hf_iperf2_low_flags, ett_client_lower_flags, iperf2_lower_flags, ENC_BIG_ENDIAN);
350 offset += 2;
351 proto_tree_add_item(extended_tree, hf_iperf2_version_major, tvb, offset, 4, ENC_BIG_ENDIAN);
352 offset += 4;
353 proto_tree_add_item(extended_tree, hf_iperf2_version_minor, tvb, offset, 4, ENC_BIG_ENDIAN);
354 offset += 4;
355 ti = proto_tree_add_item(extended_tree, hf_iperf2_version, tvb, offset - 8, 8, ENC_BIG_ENDIAN);
356 proto_item_set_generated(ti);
357 proto_tree_add_item(extended_tree, hf_iperf2_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
358 offset += 2;
359 proto_tree_add_item(extended_tree, hf_iperf2_tos, tvb, offset, 2, ENC_BIG_ENDIAN);
360 offset += 2;
361 proto_tree_add_item(extended_tree, hf_iperf2_rate, tvb, offset, 4, ENC_BIG_ENDIAN);
362 offset += 4;
363 proto_tree_add_item(extended_tree, hf_iperf2_rate_units, tvb, offset, 4, ENC_BIG_ENDIAN);
364 offset += 4;
365 proto_tree_add_item(extended_tree, hf_iperf2_realtime, tvb, offset, 4, ENC_BIG_ENDIAN);
366 offset += 4;
368 // There may be an optional permit key at the end of this header. Flags are not reliable - do some heuristics here instead.
369 if (tvb_reported_length(tvb) - offset >= 2) {
370 permit_key_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
371 if ((permit_key_len != 0) && (permit_key_len <= (tvb_reported_length(tvb) - offset - 2))) {
372 permit_key_tree = proto_tree_add_subtree(tree, tvb, offset, permit_key_len + 2, ett_permit_key, NULL, "iPerf2 Permit Key");
373 proto_tree_add_item(permit_key_tree, hf_iperf2_permit_key_len, tvb, offset, 2, ENC_BIG_ENDIAN);
374 offset += 2;
375 proto_tree_add_item(permit_key_tree, hf_iperf2_permit_key, tvb, offset, permit_key_len, ENC_ASCII);
376 offset += permit_key_len;
379 return offset - initial_offset;
382 static int
383 dissect_iperf2_isoch_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
385 uint32_t initial_offset = offset;
386 proto_tree *ext_isoch_tree;
388 ext_isoch_tree = proto_tree_add_subtree(tree, tvb, offset, 32, ett_ext_isochhdr, NULL, "iPerf2 Extended Isochronous Header");
389 proto_tree_add_item(ext_isoch_tree, hf_iperf2_fpsl, tvb, offset, 4, ENC_BIG_ENDIAN);
390 offset += 4;
391 proto_tree_add_item(ext_isoch_tree, hf_iperf2_fpsu, tvb, offset, 4, ENC_BIG_ENDIAN);
392 offset += 4;
393 proto_tree_add_item(ext_isoch_tree, hf_iperf2_meanl, tvb, offset, 4, ENC_BIG_ENDIAN);
394 offset += 4;
395 proto_tree_add_item(ext_isoch_tree, hf_iperf2_meanu, tvb, offset, 4, ENC_BIG_ENDIAN);
396 offset += 4;
397 proto_tree_add_item(ext_isoch_tree, hf_iperf2_variancel, tvb, offset, 4, ENC_BIG_ENDIAN);
398 offset += 4;
399 proto_tree_add_item(ext_isoch_tree, hf_iperf2_varianceu, tvb, offset, 4, ENC_BIG_ENDIAN);
400 offset += 4;
401 proto_tree_add_item(ext_isoch_tree, hf_iperf2_burstipgl, tvb, offset, 4, ENC_BIG_ENDIAN);
402 offset += 4;
403 proto_tree_add_item(ext_isoch_tree, hf_iperf2_burstipg, tvb, offset, 4, ENC_BIG_ENDIAN);
404 offset += 4;
406 return offset - initial_offset;
409 static int
410 dissect_iperf2_isoch_payload_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
412 proto_item *ti;
413 uint32_t initial_offset = offset;
414 proto_tree *isoch_tree;
415 nstime_t isoch_timestamp;
416 unsigned isoch_ts_sec = 0;
417 unsigned isoch_ts_usec = 0;
419 isoch_tree = proto_tree_add_subtree(tree, tvb, offset, 32, ett_isochhdr, NULL, "iPerf2 Isochronous Header");
420 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_burst_period, tvb, offset, 4, ENC_BIG_ENDIAN);
421 offset += 4;
422 proto_tree_add_item_ret_uint(isoch_tree, hf_iperf2_isoch_start_ts_s, tvb, offset, 4, ENC_BIG_ENDIAN, &isoch_ts_sec);
423 offset += 4;
424 proto_tree_add_item_ret_uint(isoch_tree, hf_iperf2_isoch_start_ts_us, tvb, offset, 4, ENC_BIG_ENDIAN, &isoch_ts_usec);
425 offset += 4;
426 isoch_timestamp.secs = (time_t)isoch_ts_sec;
427 isoch_timestamp.nsecs = (int)isoch_ts_usec * 1000;
428 ti = proto_tree_add_time(isoch_tree, hf_iperf2_isoch_start_ts, tvb, offset - 8, 8, &isoch_timestamp);
429 proto_item_set_generated(ti);
430 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_prev_frameid, tvb, offset, 4, ENC_BIG_ENDIAN);
431 offset += 4;
432 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_frameid, tvb, offset, 4, ENC_BIG_ENDIAN);
433 offset += 4;
434 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_burstsize, tvb, offset, 4, ENC_BIG_ENDIAN);
435 offset += 4;
436 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_bytes_remaining, tvb, offset, 4, ENC_BIG_ENDIAN);
437 offset += 4;
438 proto_tree_add_item(isoch_tree, hf_iperf2_isoch_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
439 offset += 4;
441 return offset - initial_offset;
444 static int
445 dissect_iperf2_fq_start_time_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
447 proto_item *ti;
448 uint32_t initial_offset = offset;
449 proto_tree *fq_tree;
450 unsigned fq_ts_sec = 0;
451 unsigned fq_ts_usec = 0;
452 nstime_t fq_timestamp;
454 fq_tree = proto_tree_add_subtree(tree, tvb, offset, 20, ett_fqhdr, NULL, "iPerf2 Fair Queue Start Time Header");
455 proto_tree_add_item(fq_tree, hf_iperf2_reserved2, tvb, offset, 4, ENC_BIG_ENDIAN);
456 offset += 4;
457 proto_tree_add_item_ret_uint(fq_tree, hf_iperf2_start_tv_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &fq_ts_sec);
458 offset += 4;
459 proto_tree_add_item_ret_uint(fq_tree, hf_iperf2_start_tv_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &fq_ts_usec);
460 offset += 4;
461 fq_timestamp.secs = (time_t)fq_ts_sec;
462 fq_timestamp.nsecs = (int)fq_ts_usec * 1000;
463 ti = proto_tree_add_time(fq_tree, hf_iperf2_start_tv, tvb, offset - 8, 8, &fq_timestamp);
464 proto_item_set_generated(ti);
465 proto_tree_add_item(fq_tree, hf_iperf2_fq_ratel, tvb, offset, 4, ENC_BIG_ENDIAN);
466 offset += 4;
467 proto_tree_add_item(fq_tree, hf_iperf2_fq_rateu, tvb, offset, 4, ENC_BIG_ENDIAN);
468 offset += 4;
470 return offset - initial_offset;
473 static int
474 dissect_iperf2_cca_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
476 uint32_t initial_offset = offset;
477 unsigned cca_payload_len;
478 proto_tree *cca_tree;
480 cca_payload_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
481 cca_tree = proto_tree_add_subtree(tree, tvb, offset, cca_payload_len + 2, ett_cca_hdr, NULL, "iPerf2 CCA Header");
482 proto_tree_add_item(cca_tree, hf_iperf2_cca_len, tvb, offset, 2, ENC_BIG_ENDIAN);
483 offset += 2;
484 proto_tree_add_item(cca_tree, hf_iperf2_cca_value, tvb, offset, cca_payload_len, ENC_ASCII);
485 offset += cca_payload_len;
487 return offset - initial_offset;
490 static int
491 dissect_iperf2_bounceback_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
493 proto_tree *bb_tree, *bb_tree_clienttx_ts, *bb_tree_serverrx_ts, *bb_tree_servertx_ts, *bb_tree_read_ts;
494 proto_item *ti;
495 unsigned ts_sec = 0, ts_usec = 0;
496 nstime_t clienttx_ts, serverrx_ts, servertx_ts, read_ts;
498 bb_tree = proto_tree_add_subtree(tree, tvb, offset, 64, ett_bbhdr, NULL, "iPerf2 Bounceback Header");
499 proto_tree_add_bitmask(bb_tree, tvb, offset, hf_iperf2_flags, ett_client_hdr_flags, iperf2_flags, ENC_BIG_ENDIAN);
500 offset += 4;
501 proto_tree_add_item(bb_tree, hf_iperf2_bb_size, tvb, offset, 4, ENC_BIG_ENDIAN);
502 offset += 4;
503 proto_tree_add_item(bb_tree, hf_iperf2_bb_id, tvb, offset, 4, ENC_BIG_ENDIAN);
504 offset += 4;
505 proto_tree_add_bitmask(bb_tree, tvb, offset, hf_iperf2_bb_flags, ett_bb_hdr_flags, iperf2_bb_flags, ENC_BIG_ENDIAN);
506 offset += 2;
507 proto_tree_add_item(bb_tree, hf_iperf2_bb_tos, tvb, offset, 2, ENC_BIG_ENDIAN);
508 offset += 2;
509 unsigned bb_run_time = 0;
510 ti = proto_tree_add_item_ret_uint(bb_tree, hf_iperf2_bb_run_time, tvb, offset, 4, ENC_BIG_ENDIAN, &bb_run_time);
511 proto_item_append_text(ti, "%d ms", bb_run_time * 10);
512 offset += 4;
514 bb_tree_clienttx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbclienttx_ts, NULL, "Client Tx Timestamp");
515 proto_tree_add_item_ret_uint(bb_tree_clienttx_ts, hf_iperf2_bb_clienttx_ts_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
516 offset += 4;
517 proto_tree_add_item_ret_uint(bb_tree_clienttx_ts, hf_iperf2_bb_clienttx_ts_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
518 offset += 4;
519 clienttx_ts.secs = (time_t)ts_sec;
520 clienttx_ts.nsecs = (int)ts_usec * 1000;
521 ti = proto_tree_add_time(bb_tree_clienttx_ts, hf_iperf2_bb_clienttx_ts, tvb, offset - 8, 8, &clienttx_ts);
522 proto_item_set_generated(ti);
524 bb_tree_serverrx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbserverrx_ts, NULL, "Server Rx Timestamp");
525 proto_tree_add_item_ret_uint(bb_tree_serverrx_ts, hf_iperf2_bb_serverrx_ts_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
526 offset += 4;
527 proto_tree_add_item_ret_uint(bb_tree_serverrx_ts, hf_iperf2_bb_serverrx_ts_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
528 offset += 4;
529 serverrx_ts.secs = (time_t)ts_sec;
530 serverrx_ts.nsecs = (int)ts_usec * 1000;
531 ti = proto_tree_add_time(bb_tree_serverrx_ts, hf_iperf2_bb_serverrx_ts, tvb, offset - 8, 8, &serverrx_ts);
532 proto_item_set_generated(ti);
534 bb_tree_servertx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbservertx_ts, NULL, "Server Tx Timestamp");
535 proto_tree_add_item_ret_uint(bb_tree_servertx_ts, hf_iperf2_bb_servertx_ts_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
536 offset += 4;
537 proto_tree_add_item_ret_uint(bb_tree_servertx_ts, hf_iperf2_bb_servertx_ts_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
538 offset += 4;
539 servertx_ts.secs = (time_t)ts_sec;
540 servertx_ts.nsecs = (int)ts_usec * 1000;
541 ti = proto_tree_add_time(bb_tree_servertx_ts, hf_iperf2_bb_servertx_ts, tvb, offset - 8, 8, &servertx_ts);
542 proto_item_set_generated(ti);
544 proto_tree_add_item(bb_tree, hf_iperf2_bb_hold, tvb, offset, 4, ENC_BIG_ENDIAN);
545 offset += 4;
546 proto_tree_add_item(bb_tree, hf_iperf2_bb_rtt, tvb, offset, 4, ENC_BIG_ENDIAN);
547 offset += 4;
549 bb_tree_read_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbread_ts, NULL, "Read Timestamp");
550 proto_tree_add_item_ret_uint(bb_tree_read_ts, hf_iperf2_bb_read_ts_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
551 offset += 4;
552 proto_tree_add_item_ret_uint(bb_tree_read_ts, hf_iperf2_bb_read_ts_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
553 offset += 4;
554 read_ts.secs = (time_t)ts_sec;
555 read_ts.nsecs = (int)ts_usec * 1000;
556 ti = proto_tree_add_time(bb_tree_read_ts, hf_iperf2_bb_read_ts, tvb, offset - 8, 8, &read_ts);
557 proto_item_set_generated(ti);
559 proto_tree_add_item(bb_tree, hf_iperf2_bb_reply_size, tvb, offset, 4, ENC_BIG_ENDIAN);
560 offset += 4;
561 return offset;
564 static int
565 dissect_iperf2_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
567 proto_item *ti = NULL;
568 proto_tree *iperf2_tree = NULL;
569 uint32_t offset = 0, flags = 0, upper_flags = 0, lower_flags = 0, pdu_len = 24;
570 uint16_t cca_len;
571 tvbparse_t *tt;
573 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iPerf2");
574 col_clear(pinfo->cinfo, COL_INFO);
576 // Is it the TCP first write with test information
577 if ((tvb_reported_length(tvb) - offset) < pdu_len) { // We don't have enough data to decode the header
578 offset += tvb_reported_length(tvb);
579 pinfo->desegment_offset = offset;
580 pinfo->desegment_len = pdu_len - offset;
581 return tvb_reported_length(tvb);
584 flags = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
585 ti = proto_tree_add_item(tree, proto_iperf2, tvb, offset, pdu_len, ENC_NA);
586 iperf2_tree = proto_item_add_subtree(ti, ett_iperf2_tcp);
588 // Check if we got iPerf2 payload
589 // First, check if the first 10 bytes look like payload
590 tt = tvbparse_init(pinfo->pool, tvb, offset, 10, NULL, NULL);
591 if (tvbparse_get(tt, want)) { // Okay, the first 10 bytes follow the pattern, continue...
592 tvbparse_reset(tt, offset + 10, tvb_reported_length(tvb) - 10);
593 while(tvbparse_curr_offset(tt) < tvb_reported_length(tvb)) {
594 if(tvbparse_get(tt, want) == NULL)
595 break;
597 // Special case for the trailing payload bytes less than 10 bytes of length
598 if ((tvb_reported_length(tvb) - tvbparse_curr_offset(tt)) <= 10) {
599 tvbparse_get(tt, want_trailing);
601 if (tvbparse_curr_offset(tt) == tvb_reported_length(tvb)) {
602 col_set_str(pinfo->cinfo, COL_INFO, "Payload only");
603 offset += dissect_iperf2_payload(tvb, iperf2_tree, offset);
604 proto_item_set_len(ti, tvb_reported_length(tvb));
605 return offset;
608 /* Here we try to understand what extra headers are present. The options are:
609 - client_hdrext (36 bytes)
610 - may contain permitKey (up to 130 bytes)
611 - client_hdrext_starttime_fq (20 bytes)
612 - client_hdrext_isoch_settings (40 bytes)
613 - cca_field (34 bytes)
614 - Combinations of the above
615 - OR a bounnceback header (64 bytes in total)
617 We do two pass analysis to avoid code duplication:
618 - First, we collect the total headers length
619 - Second, we confirm that TCP buffer provided enough bytes to decode all headers
620 - If needed, stop decoding and ask TCP for more data */
621 for (int pass = 1; pass <= 2; pass++) {
622 if (flags & HEADER_BOUNCEBACK) {
623 (pass == 1) ? (pdu_len = 64) : (offset += dissect_iperf2_bounceback_header(tvb, iperf2_tree, offset));
624 col_set_str(pinfo->cinfo, COL_INFO, "Bounceback");
625 } else {
626 if (pass == 2)
627 offset += dissect_iperf2_client_header(tvb, iperf2_tree, offset, false);
628 if (flags & HEADER_EXTEND) {
629 if (pass == 1)
630 pdu_len += 36;
631 else {
632 upper_flags = tvb_get_uint16(tvb, offset + 8, ENC_BIG_ENDIAN);
633 lower_flags = tvb_get_uint16(tvb, offset + 10, ENC_BIG_ENDIAN);
634 offset += dissect_iperf2_extended_header(tvb, iperf2_tree, offset);
637 // If CCA header is present, the the previous two headers are also present, though the flags may not be set
638 if (lower_flags & HEADER_CCA) {
639 if (pass == 1) {
640 cca_len = tvb_get_uint16(tvb, offset + 20 + 40, ENC_BIG_ENDIAN) + 2;
641 pdu_len += 20 + 40 + cca_len;
643 else {
644 offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset);
645 offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset);
646 offset += dissect_iperf2_cca_header(tvb, iperf2_tree, offset);
648 } else {
649 if (upper_flags & HEADER_TRIPTIME || upper_flags & HEADER_FQRATESET ||
650 upper_flags & HEADER_ISOCH_SETTINGS || upper_flags & HEADER_EPOCH_START) {
651 (pass == 1) ? (pdu_len += 20) : (offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset));
653 if (upper_flags & HEADER_FULLDUPLEX || upper_flags & HEADER_REVERSE || upper_flags & HEADER_PERIODICBURST) {
654 (pass == 1) ? (pdu_len += 40) : (offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset));
658 if ((pass == 1) && (tvb_reported_length(tvb) - offset) < pdu_len) { // We don't have enough data to decode all headers
659 offset += tvb_reported_length(tvb);
660 pinfo->desegment_offset = offset;
661 pinfo->desegment_len = pdu_len - offset;
662 proto_item_set_len(ti, tvb_reported_length(tvb));
663 return tvb_reported_length(tvb);
666 if ((tvb_reported_length(tvb) - offset) > 0) {
667 offset += dissect_iperf2_payload(tvb, iperf2_tree, offset);
669 proto_item_set_len(ti, offset);
670 return offset;
673 static int
674 dissect_iperf2_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
676 uint32_t offset = 0;
677 uint32_t ext_header = 0;
678 proto_item *ti;
679 proto_tree *iperf2_tree, *udp_tree;
681 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iPerf2");
682 /* Clear out stuff in the info column */
683 col_clear(pinfo->cinfo, COL_INFO);
685 ti = proto_tree_add_item(tree, proto_iperf2, tvb, offset, IPERF2_UDP_HDR_SIZE, ENC_NA);
686 iperf2_tree = proto_item_add_subtree(ti, ett_iperf2_udp);
688 udp_tree = proto_tree_add_subtree(iperf2_tree, tvb, offset, 16, ett_udphdr, NULL, "iPerf2 UDP Header");
689 proto_tree_add_item(udp_tree, hf_iperf2_sequence, tvb, offset, 4, ENC_BIG_ENDIAN);
690 offset += 4;
691 unsigned ts_sec = 0;
692 proto_tree_add_item_ret_uint(udp_tree, hf_iperf2_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
693 offset += 4;
694 unsigned ts_usec = 0;
695 proto_tree_add_item_ret_uint(udp_tree, hf_iperf2_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
696 offset += 4;
697 nstime_t timestamp;
698 timestamp.secs = (time_t)ts_sec;
699 timestamp.nsecs = (int)ts_usec * 1000;
700 ti = proto_tree_add_time(udp_tree, hf_iperf2_timestamp, tvb, offset - 8, 8, &timestamp);
701 proto_item_set_generated(ti);
702 proto_tree_add_item(udp_tree, hf_iperf2_sequence_upper, tvb, offset, 4, ENC_BIG_ENDIAN);
703 offset += 4;
704 ext_header = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
706 offset += dissect_iperf2_client_header(tvb, iperf2_tree, offset, true);
708 if (tvb_reported_length(tvb) == offset) {
709 return offset;
711 //Check is Extended header flag is set, if it's not - do no add more subheaders
712 if (!(ext_header & HEADER_EXTEND)) {
713 return dissect_iperf2_payload(tvb, iperf2_tree, offset);
716 offset += dissect_iperf2_extended_header(tvb, iperf2_tree, offset);
718 offset += dissect_iperf2_isoch_payload_header(tvb, iperf2_tree, offset);
720 offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset);
722 offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset);
724 if ((tvb_reported_length(tvb) - offset) > 0) {
725 return dissect_iperf2_payload(tvb, iperf2_tree, offset);
726 } else {
727 return offset;
731 void
732 proto_register_iperf2(void)
734 /* Setup list of header fields */
735 static hf_register_info hf[] = {
736 { &hf_iperf2_sequence,
737 { "Sequence Number", "iperf2.udp.sequence", FT_INT32, BASE_DEC,
738 NULL, 0, NULL, HFILL }
740 { &hf_iperf2_sec,
741 { "Start Time (sec)", "iperf2.udp.sec", FT_UINT32, BASE_DEC,
742 NULL, 0, NULL, HFILL }
744 { &hf_iperf2_usec,
745 { "Start Time (usec)", "iperf2.udp.usec", FT_UINT32, BASE_DEC,
746 NULL, 0, NULL, HFILL }
748 { &hf_iperf2_timestamp,
749 { "Start Time", "iperf2.udp.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
750 NULL, 0, NULL, HFILL }
752 { &hf_iperf2_sequence_upper,
753 { "Upper Sequence Number", "iperf2.udp.sequence_upper", FT_INT32, BASE_DEC,
754 NULL, 0, NULL, HFILL }
756 { &hf_iperf2_flags,
757 { "Flags", "iperf2.client.flags", FT_UINT32, BASE_HEX,
758 NULL, 0, NULL, HFILL }
760 { &hf_iperf2_flag_header_version1,
761 { "Header Valid", "iperf2.client.flags_version1", FT_BOOLEAN, 32,
762 NULL, HEADER_VERSION1, NULL, HFILL }
764 { &hf_iperf2_flag_header_extend,
765 { "Extended Version", "iperf2.client.flags_extend", FT_BOOLEAN, 32,
766 NULL, HEADER_EXTEND, NULL, HFILL }
768 { &hf_iperf2_header_udptests,
769 { "UDP Tests", "iperf2.client.flags_udp_tests", FT_BOOLEAN, 32,
770 NULL, HEADER_UDPTESTS, NULL, HFILL }
772 { &hf_iperf2_header_seqno64b,
773 { "64 Bit Seq Num", "iperf2.client.flags_seqno64b", FT_BOOLEAN, 32,
774 NULL, HEADER_SEQNO64B, "64-bits sequence numbers are used", HFILL }
776 { &hf_iperf2_header_version2,
777 { "Version 2", "iperf2.client.flags_version2", FT_BOOLEAN, 32,
778 NULL, HEADER_VERSION2, NULL, HFILL }
780 { &hf_iperf2_header_v2peerdetect,
781 { "Version 2 Peer Detect", "iperf2.client.flags_version2_peerdetect", FT_BOOLEAN, 32,
782 NULL, HEADER_V2PEERDETECT, NULL, HFILL }
784 { &hf_iperf2_header_udpavoid,
785 { "Don't use for UDP", "iperf2.client.flags_udpavoid", FT_BOOLEAN, 32,
786 NULL, HEADER_UDPAVOID1, "Don't use these bits for UDP", HFILL }
788 { &hf_iperf2_header_bounceback,
789 { "Bounceback", "iperf2.client.flags_bounceback", FT_BOOLEAN, 32,
790 NULL, HEADER_BOUNCEBACK, NULL, HFILL }
792 { &hf_iperf2_header_len_bit,
793 { "Length Bit", "iperf2.client.flags_len_bit", FT_BOOLEAN, 32,
794 NULL, HEADER_LEN_BIT, NULL, HFILL }
796 { &hf_iperf2_header_len_mask,
797 { "Length Mask", "iperf2.client.flags_len_mask", FT_UINT32, BASE_HEX,
798 NULL, HEADER_LEN_MASK, NULL, HFILL }
800 { &hf_iperf2_run_now,
801 { "Run Now", "iperf2.client.flags_run_now", FT_BOOLEAN, 32,
802 NULL, RUN_NOW, NULL, HFILL }
804 { &hf_iperf2_header16_small_triptimes,
805 { "Small Triptimes", "iperf2.client.flags_small_triptimes", FT_BOOLEAN, 32,
806 NULL, HEADER16_SMALL_TRIPTIMES, "Don't decode other fields in this packet", HFILL }
808 { &hf_iperf2_num_threads,
809 { "Number of Threads", "iperf2.client.numthreads", FT_UINT32, BASE_DEC,
810 NULL, 0, NULL, HFILL }
812 { &hf_iperf2_mport,
813 { "Port", "iperf2.client.port", FT_UINT32, BASE_DEC,
814 NULL, 0, NULL, HFILL }
816 { &hf_iperf2_bufferlen,
817 { "Buffer Length", "iperf2.client.bufferlen", FT_UINT32, BASE_DEC,
818 NULL, 0, NULL, HFILL }
820 { &hf_iperf2_mwinband,
821 { "Bandwidth", "iperf2.client.bandwidth", FT_UINT32, BASE_DEC,
822 NULL, 0, NULL, HFILL }
824 { &hf_iperf2_mamount,
825 { "Amount (Time or Bytes)", "iperf2.client.num_bytes", FT_INT32, BASE_DEC,
826 NULL, 0, NULL, HFILL }
828 { &hf_iperf2_type,
829 { "Type", "iperf2.client.type", FT_UINT32, BASE_DEC,
830 NULL, 0, NULL, HFILL }
832 { &hf_iperf2_length,
833 { "Length", "iperf2.client.length", FT_UINT32, BASE_DEC,
834 NULL, 0, NULL, HFILL }
836 { &hf_iperf2_up_flags,
837 { "Upper Flags", "iperf2.client.up_flags", FT_UINT16, BASE_HEX,
838 NULL, 0, NULL, HFILL }
840 { &hf_iperf2_upper_header_isoch,
841 { "Isochronous Header", "iperf2.client.upper_header_isoch", FT_BOOLEAN, 16,
842 NULL, HEADER_ISOCH, NULL, HFILL }
844 { &hf_iperf2_upper_header_l2ethpipv6,
845 { "L2 ETH IPv6", "iperf2.client.upper_header_l2ethpipv6", FT_BOOLEAN, 16,
846 NULL, HEADER_L2ETHPIPV6, NULL, HFILL }
848 { &hf_iperf2_upper_header_l2lencheck,
849 { "L2 Length Check", "iperf2.client.upper_header_l2lencheck", FT_BOOLEAN, 16,
850 NULL, HEADER_L2LENCHECK, NULL, HFILL }
852 { &hf_iperf2_upper_header_noudpfin,
853 { "No UDP Fin", "iperf2.client.upper_header_noudpfin", FT_BOOLEAN, 16,
854 NULL, HEADER_NOUDPFIN, NULL, HFILL }
856 { &hf_iperf2_upper_header_triptime,
857 { "Trip Time", "iperf2.client.upper_header_triptime", FT_BOOLEAN, 16,
858 NULL, HEADER_TRIPTIME, NULL, HFILL }
860 { &hf_iperf2_upper_header_unused2,
861 { "Unused", "iperf2.client.upper_header_unused2", FT_BOOLEAN, 16,
862 NULL, HEADER_UNUSED2, NULL, HFILL }
864 { &hf_iperf2_upper_header_isoch_settings,
865 { "Isochronous Settings", "iperf2.client.upper_header_isoch_settings", FT_BOOLEAN, 16,
866 NULL, HEADER_ISOCH_SETTINGS, NULL, HFILL }
868 { &hf_iperf2_upper_header_units_pps,
869 { "Units PPS", "iperf2.client.upper_header_units_pps", FT_BOOLEAN, 16,
870 NULL, HEADER_UNITS_PPS, NULL, HFILL }
872 { &hf_iperf2_upper_header_bwset,
873 { "Header BW Set", "iperf2.client.upper_header_bwset", FT_BOOLEAN, 16,
874 NULL, HEADER_BWSET, NULL, HFILL }
876 { &hf_iperf2_upper_header_fqrateset,
877 { "Fair Queue Rate Set", "iperf2.client.upper_header_fqrateset", FT_BOOLEAN, 16,
878 NULL, HEADER_FQRATESET, NULL, HFILL }
880 { &hf_iperf2_upper_header_reverse,
881 { "Reverse", "iperf2.client.upper_header_reverse", FT_BOOLEAN, 16,
882 NULL, HEADER_REVERSE, NULL, HFILL }
884 { &hf_iperf2_upper_header_fullduplex,
885 { "Full Duplex", "iperf2.client.upper_header_fullduplex", FT_BOOLEAN, 16,
886 NULL, HEADER_FULLDUPLEX, NULL, HFILL }
888 { &hf_iperf2_upper_header_epoch_start,
889 { "Epoch Start", "iperf2.client.upper_header_epoch_start", FT_BOOLEAN, 16,
890 NULL, HEADER_EPOCH_START, NULL, HFILL }
892 { &hf_iperf2_upper_header_periodicburst,
893 { "Periodic Burst", "iperf2.client.upper_header_periodicburst", FT_BOOLEAN, 16,
894 NULL, HEADER_PERIODICBURST, NULL, HFILL }
896 { &hf_iperf2_upper_header_writeprefetch,
897 { "Write Prefetch", "iperf2.client.upper_header_writeprefetch", FT_BOOLEAN, 16,
898 NULL, HEADER_WRITEPREFETCH, NULL, HFILL }
900 { &hf_iperf2_upper_header_tcpquickack,
901 { "TCP Quick Ack", "iperf2.client.upper_header_tcpquickack", FT_BOOLEAN, 16,
902 NULL, HEADER_TCPQUICKACK, NULL, HFILL }
904 { &hf_iperf2_low_flags,
905 { "Lower Flags", "iperf2.client.low_flags", FT_UINT16, BASE_HEX,
906 NULL, 0, NULL, HFILL }
908 { &hf_iperf2_lower_header_cca,
909 { "CCA", "iperf2.client.lower_header_cca", FT_BOOLEAN, 16,
910 NULL, HEADER_CCA, NULL, HFILL }
912 { &hf_iperf2_version_major,
913 { "Major Version", "iperf2.client.version_major", FT_UINT32, BASE_CUSTOM,
914 CF_FUNC(format_version), 0, NULL, HFILL }
916 { &hf_iperf2_version_minor,
917 { "Minor Version", "iperf2.client.version_minor", FT_UINT32, BASE_CUSTOM,
918 CF_FUNC(format_version), 0, NULL, HFILL }
920 { &hf_iperf2_version,
921 { "Iperf2 Version", "iperf2.client.version", FT_UINT64, BASE_CUSTOM,
922 CF_FUNC(format_version_long), 0, NULL, HFILL }
924 { &hf_iperf2_reserved,
925 { "Reserved", "iperf2.client.reserved", FT_UINT16, BASE_HEX,
926 NULL, 0, NULL, HFILL }
928 { &hf_iperf2_tos,
929 { "TOS", "iperf2.client.tos", FT_UINT16, BASE_HEX,
930 NULL, 0, NULL, HFILL }
932 { &hf_iperf2_rate,
933 { "Rate", "iperf2.client.rate", FT_UINT32, BASE_DEC,
934 NULL, 0, NULL, HFILL }
936 { &hf_iperf2_rate_units,
937 { "Rate Units", "iperf2.client.rate_units", FT_UINT32, BASE_DEC,
938 NULL, 0, NULL, HFILL }
940 { &hf_iperf2_realtime,
941 { "TCP Realtime", "iperf2.client.realtime", FT_UINT32, BASE_DEC,
942 NULL, 0, NULL, HFILL }
944 { &hf_iperf2_permit_key_len,
945 { "Permit Key Length", "iperf2.client.permit_key_length", FT_UINT16, BASE_DEC,
946 NULL, 0, NULL, HFILL }
948 { &hf_iperf2_permit_key,
949 { "Permit Key", "iperf2.client.permit_key", FT_STRING, BASE_NONE,
950 NULL, 0, NULL, HFILL }
952 { &hf_iperf2_isoch_burst_period,
953 { "Burst Period", "iperf2.client.isoch_burst_period", FT_UINT32, BASE_DEC,
954 NULL, 0, NULL, HFILL }
956 { &hf_iperf2_isoch_start_ts_s,
957 { "Start Timestamp (s)", "iperf2.client.isoch_start_ts_s", FT_UINT32, BASE_DEC,
958 NULL, 0, NULL, HFILL }
960 { &hf_iperf2_isoch_start_ts_us,
961 { "Start Timestamp (us)", "iperf2.client.isoch_start_ts_us", FT_UINT32, BASE_DEC,
962 NULL, 0, NULL, HFILL }
964 { &hf_iperf2_isoch_start_ts,
965 { "Start Timestamp", "iperf2.client.isoch_start_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
966 NULL, 0, NULL, HFILL }
968 { &hf_iperf2_isoch_prev_frameid,
969 { "Previous Frame ID", "iperf2.client.isoch_prev_frameid", FT_UINT32, BASE_DEC,
970 NULL, 0, NULL, HFILL }
972 { &hf_iperf2_isoch_frameid,
973 { "Frame ID", "iperf2.client.isoch_frameid", FT_UINT32, BASE_DEC,
974 NULL, 0, NULL, HFILL }
976 { &hf_iperf2_isoch_burstsize,
977 { "Burst Size", "iperf2.client.isoch_burstsize", FT_UINT32, BASE_DEC,
978 NULL, 0, NULL, HFILL }
980 { &hf_iperf2_isoch_bytes_remaining,
981 { "Bytes Remaining", "iperf2.client.isoch_bytes_remaining", FT_UINT32, BASE_DEC,
982 NULL, 0, NULL, HFILL }
984 { &hf_iperf2_isoch_reserved,
985 { "Reserved", "iperf2.client.isoch_reserved", FT_UINT32, BASE_HEX,
986 NULL, 0, NULL, HFILL }
988 { &hf_iperf2_reserved2,
989 { "Reserved", "iperf2.client.reserved2", FT_UINT32, BASE_HEX,
990 NULL, 0, NULL, HFILL }
992 { &hf_iperf2_start_tv_sec,
993 { "Start TV (s)", "iperf2.client.start_tv_sec", FT_UINT32, BASE_DEC,
994 NULL, 0, NULL, HFILL }
996 { &hf_iperf2_start_tv_usec,
997 { "Start TV (us)", "iperf2.client.start_tv_usec", FT_UINT32, BASE_DEC,
998 NULL, 0, NULL, HFILL }
1000 { &hf_iperf2_start_tv,
1001 { "Start TV", "iperf2.client.start_tv", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1002 NULL, 0, NULL, HFILL }
1004 { &hf_iperf2_fq_ratel,
1005 { "Fair-Queuing Rate Lower", "iperf2.client.fq_ratel", FT_UINT32, BASE_DEC,
1006 NULL, 0, NULL, HFILL }
1008 { &hf_iperf2_fq_rateu,
1009 { "Fair-Queuing Rate Upper", "iperf2.client.fq_rateu", FT_UINT32, BASE_DEC,
1010 NULL, 0, NULL, HFILL }
1012 { &hf_iperf2_fpsl,
1013 { "FPS Lower", "iperf2.client.fpsl", FT_UINT32, BASE_DEC,
1014 NULL, 0, NULL, HFILL }
1016 { &hf_iperf2_fpsu,
1017 { "FPS Upper", "iperf2.client.fpsu", FT_UINT32, BASE_DEC,
1018 NULL, 0, NULL, HFILL }
1020 { &hf_iperf2_meanl,
1021 { "Mean Lower", "iperf2.client.meanl", FT_UINT32, BASE_DEC,
1022 NULL, 0, NULL, HFILL }
1024 { &hf_iperf2_meanu,
1025 { "Mean Upper", "iperf2.client.meanu", FT_UINT32, BASE_DEC,
1026 NULL, 0, NULL, HFILL }
1028 { &hf_iperf2_variancel,
1029 { "Variance Lower", "iperf2.client.variancel", FT_UINT32, BASE_DEC,
1030 NULL, 0, NULL, HFILL }
1032 { &hf_iperf2_varianceu,
1033 { "Variance Upper", "iperf2.client.varianceu", FT_UINT32, BASE_DEC,
1034 NULL, 0, NULL, HFILL }
1036 { &hf_iperf2_burstipgl,
1037 { "Burst Inter-packet Gap Lower", "iperf2.client.burstipgl", FT_UINT32, BASE_DEC,
1038 NULL, 0, NULL, HFILL }
1040 { &hf_iperf2_burstipg,
1041 { "Burst Inter-packet Gap", "iperf2.client.burstipg", FT_UINT32, BASE_DEC,
1042 NULL, 0, NULL, HFILL }
1044 { &hf_iperf2_cca_len,
1045 { "CCA Length", "iperf2.client.cca_len", FT_UINT16, BASE_DEC,
1046 NULL, 0, NULL, HFILL }
1048 { &hf_iperf2_cca_value,
1049 { "CCA Value", "iperf2.client.cca_value", FT_STRING, BASE_NONE,
1050 NULL, 0, NULL, HFILL }
1052 { &hf_iperf2_bb_size,
1053 { "Bounceback Size", "iperf2.client.bb_size", FT_UINT32, BASE_DEC,
1054 NULL, 0, NULL, HFILL }
1056 { &hf_iperf2_bb_id,
1057 { "Bounceback ID", "iperf2.client.bb_id", FT_UINT32, BASE_DEC,
1058 NULL, 0, NULL, HFILL }
1060 { &hf_iperf2_bb_flags,
1061 { "Bounceback Flags", "iperf2.client.bb_flags", FT_UINT16, BASE_HEX,
1062 NULL, 0, NULL, HFILL }
1064 { &hf_iperf2_header_bbquickack,
1065 { "Quick Ack", "iperf2.client.bb_flags_quickack", FT_BOOLEAN, 16,
1066 NULL, HEADER_BBQUICKACK, NULL, HFILL }
1068 { &hf_iperf2_header_bbclocksynced,
1069 { "Clock Synced", "iperf2.client.bb_flags_clock_synced", FT_BOOLEAN, 16,
1070 NULL, HEADER_BBCLOCKSYNCED, NULL, HFILL }
1072 { &hf_iperf2_header_bbtos,
1073 { "ToS", "iperf2.client.bb_flags_tos", FT_BOOLEAN, 16,
1074 NULL, HEADER_BBTOS, NULL, HFILL }
1076 { &hf_iperf2_header_bbstop,
1077 { "Stop", "iperf2.client.bb_flags_stop", FT_BOOLEAN, 16,
1078 NULL, HEADER_BBSTOP, NULL, HFILL }
1080 { &hf_iperf2_header_bbreplysize,
1081 { "Reply Size", "iperf2.client.bb_flags_reply_size", FT_BOOLEAN, 16,
1082 NULL, HEADER_BBREPLYSIZE, NULL, HFILL }
1084 { &hf_iperf2_bb_tos,
1085 { "Bounceback ToS", "iperf2.client.bb_tos", FT_UINT16, BASE_HEX,
1086 NULL, 0, NULL, HFILL }
1088 { &hf_iperf2_bb_run_time,
1089 { "Bounceback Run Time", "iperf2.client.bb_run_time", FT_UINT32, BASE_DEC,
1090 NULL, 0, NULL, HFILL }
1092 { &hf_iperf2_bb_clienttx_ts_sec,
1093 { "Client TX Timestamp (s)", "iperf2.client.bb_clienttx_ts_sec", FT_UINT32, BASE_DEC,
1094 NULL, 0, NULL, HFILL }
1096 { &hf_iperf2_bb_clienttx_ts_usec,
1097 { "Client TX Timestamp (us)", "iperf2.client.bb_clienttx_ts_usec", FT_UINT32, BASE_DEC,
1098 NULL, 0, NULL, HFILL }
1100 { &hf_iperf2_bb_clienttx_ts,
1101 { "Client TX Timestamp", "iperf2.client.bb_clienttx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1102 NULL, 0, NULL, HFILL }
1104 { &hf_iperf2_bb_serverrx_ts_sec,
1105 { "Server RX Timestamp (s)", "iperf2.client.bb_serverrx_ts_sec", FT_UINT32, BASE_DEC,
1106 NULL, 0, NULL, HFILL }
1108 { &hf_iperf2_bb_serverrx_ts_usec,
1109 { "Server RX Timestamp (us)", "iperf2.client.bb_serverrx_ts_usec", FT_UINT32, BASE_DEC,
1110 NULL, 0, NULL, HFILL }
1112 { &hf_iperf2_bb_serverrx_ts,
1113 { "Server RX Timestamp", "iperf2.client.bb_serverrx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1114 NULL, 0, NULL, HFILL }
1116 { &hf_iperf2_bb_servertx_ts_sec,
1117 { "Server TX Timestamp (s)", "iperf2.client.bb_servertx_ts_sec", FT_UINT32, BASE_DEC,
1118 NULL, 0, NULL, HFILL }
1120 { &hf_iperf2_bb_servertx_ts_usec,
1121 { "Server TX Timestamp (us)", "iperf2.client.bb_servertx_ts_usec", FT_UINT32, BASE_DEC,
1122 NULL, 0, NULL, HFILL }
1124 { &hf_iperf2_bb_servertx_ts,
1125 { "Server TX Timestamp", "iperf2.client.bb_servertx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1126 NULL, 0, NULL, HFILL }
1128 { &hf_iperf2_bb_hold,
1129 { "Bounceback Hold", "iperf2.client.bb_hold", FT_UINT32, BASE_DEC,
1130 NULL, 0, NULL, HFILL }
1132 { &hf_iperf2_bb_rtt,
1133 { "Bounceback RTT", "iperf2.client.bb_rtt", FT_UINT32, BASE_DEC,
1134 NULL, 0, NULL, HFILL }
1136 { &hf_iperf2_bb_read_ts_sec,
1137 { "Read Timestamp (s)", "iperf2.client.bb_read_ts_sec", FT_UINT32, BASE_DEC,
1138 NULL, 0, NULL, HFILL }
1140 { &hf_iperf2_bb_read_ts_usec,
1141 { "Read Timestamp (us)", "iperf2.client.bb_read_ts_usec", FT_UINT32, BASE_DEC,
1142 NULL, 0, NULL, HFILL }
1144 { &hf_iperf2_bb_read_ts,
1145 { "Read Timestamp", "iperf2.client.bb_read_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1146 NULL, 0, NULL, HFILL }
1148 { &hf_iperf2_bb_reply_size,
1149 { "Bounceback Reply Size", "iperf2.client.bb_reply_size", FT_UINT32, BASE_DEC,
1150 NULL, 0, NULL, HFILL }
1152 { &hf_iperf2_payload,
1153 { "Data", "iperf2.client.payload", FT_BYTES, BASE_NONE,
1154 NULL, 0, NULL, HFILL }
1158 /* Setup protocol subtree array */
1159 static int *ett[] = {
1160 &ett_iperf2_udp,
1161 &ett_iperf2_tcp,
1162 &ett_udphdr,
1163 &ett_clienthdr,
1164 &ett_bbhdr,
1165 &ett_extendedhdr,
1166 &ett_permit_key,
1167 &ett_client_upper_flags,
1168 &ett_client_lower_flags,
1169 &ett_isochhdr,
1170 &ett_fqhdr,
1171 &ett_ext_isochhdr,
1172 &ett_client_hdr,
1173 &ett_client_hdr_flags,
1174 &ett_cca_hdr,
1175 &ett_bb_hdr_flags,
1176 &ett_bbclienttx_ts,
1177 &ett_bbserverrx_ts,
1178 &ett_bbservertx_ts,
1179 &ett_bbread_ts,
1180 &ett_data
1183 /* Register the protocol name and description */
1184 proto_iperf2 = proto_register_protocol("iPerf2 Packet Data", "iPerf2", "iperf2");
1186 proto_register_field_array(proto_iperf2, hf, array_length(hf));
1187 proto_register_subtree_array(ett, array_length(ett));
1189 /* Set up string templates for iperf2 payload */
1190 want = tvbparse_set_oneof(0, NULL, NULL, NULL,
1191 tvbparse_string(-1,"0123456789",NULL,NULL,NULL),
1192 tvbparse_string(-1,"1234567890",NULL,NULL,NULL),
1193 tvbparse_string(-1,"2345678901",NULL,NULL,NULL),
1194 tvbparse_string(-1,"3456789012",NULL,NULL,NULL),
1195 tvbparse_string(-1,"4567890123",NULL,NULL,NULL),
1196 tvbparse_string(-1,"5678901234",NULL,NULL,NULL),
1197 tvbparse_string(-1,"6789012345",NULL,NULL,NULL),
1198 tvbparse_string(-1,"7890123456",NULL,NULL,NULL),
1199 tvbparse_string(-1,"8901234567",NULL,NULL,NULL),
1200 tvbparse_string(-1,"9012345678",NULL,NULL,NULL),
1201 NULL);
1202 want_trailing = tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL);
1204 iperf2_handle_tcp = register_dissector("iperf2_tcp", dissect_iperf2_tcp, proto_iperf2);
1205 iperf2_handle_udp = register_dissector("iperf2_udp", dissect_iperf2_udp, proto_iperf2);
1208 void
1209 proto_reg_handoff_iperf2(void)
1211 dissector_add_for_decode_as_with_preference("tcp.port", iperf2_handle_tcp);
1212 dissector_add_for_decode_as_with_preference("udp.port", iperf2_handle_udp);
1216 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1218 * Local variables:
1219 * c-basic-offset: 4
1220 * tab-width: 8
1221 * indent-tabs-mode: nil
1222 * End:
1224 * vi: set shiftwidth=4 tabstop=8 expandtab:
1225 * :indentSize=4:tabSize=8:noTabs=true: