Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-iperf.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-iperf.c
2
 * Routines for iPerf dissection
3
 * By Anish Bhatt <anish@gatech.edu>
4
 *
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)
9
 *
10
 * Wireshark - Network traffic analyzer
11
 * By Gerald Combs <gerald@wireshark.org>
12
 * Copyright 1998 Gerald Combs
13
 *
14
 * SPDX-License-Identifier: GPL-2.0-or-later
15
 */
16
17
#include "config.h"
18
#include <epan/packet.h>
19
#include <epan/tvbparse.h>
20
21
0
#define IPERF2_UDP_HDR_SIZE 160
22
23
void proto_register_iperf2(void);
24
void proto_reg_handoff_iperf2(void);
25
26
static int proto_iperf2;
27
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;
98
99
// Flags definition for hf_iperf2_flags. See include/Listener.hpp in iperf2 source code
100
14
#define HEADER_VERSION1      0x80000000
101
14
#define HEADER_EXTEND        0x40000000
102
14
#define HEADER_UDPTESTS      0x20000000
103
14
#define HEADER_SEQNO64B      0x08000000
104
14
#define HEADER_VERSION2      0x04000000
105
14
#define HEADER_V2PEERDETECT  0x02000000
106
#define HEADER_UDPAVOID2     0x02000000
107
14
#define HEADER_UDPAVOID1     0x01000000
108
14
#define HEADER_BOUNCEBACK    0x00800000
109
0
#define HEADER32_SMALL_TRIPTIMES 0x00020000
110
14
#define HEADER_LEN_BIT       0x00010000
111
14
#define HEADER_LEN_MASK      0x000001FE
112
14
#define RUN_NOW              0x00000001
113
14
#define HEADER16_SMALL_TRIPTIMES 0x00020000
114
115
14
#define HEADER_ISOCH          0x0001
116
14
#define HEADER_L2ETHPIPV6     0x0002
117
14
#define HEADER_L2LENCHECK     0x0004
118
14
#define HEADER_NOUDPFIN       0x0008
119
14
#define HEADER_TRIPTIME       0x0010
120
14
#define HEADER_UNUSED2        0x0020
121
14
#define HEADER_ISOCH_SETTINGS 0x0040
122
14
#define HEADER_UNITS_PPS      0x0080
123
14
#define HEADER_BWSET          0x0100
124
14
#define HEADER_FQRATESET      0x0200
125
14
#define HEADER_REVERSE        0x0400
126
14
#define HEADER_FULLDUPLEX     0x0800
127
14
#define HEADER_EPOCH_START    0x1000
128
14
#define HEADER_PERIODICBURST  0x2000
129
14
#define HEADER_WRITEPREFETCH  0x4000
130
14
#define HEADER_TCPQUICKACK    0x8000
131
// Bounceback flags
132
14
#define HEADER_BBQUICKACK    0x8000
133
14
#define HEADER_BBCLOCKSYNCED 0x4000
134
14
#define HEADER_BBTOS         0x2000
135
14
#define HEADER_BBSTOP        0x1000
136
14
#define HEADER_BBREPLYSIZE   0x0800
137
138
// lower flags (16 bit)
139
14
#define HEADER_CCA          0x8000
140
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;
155
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
170
};
171
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;
189
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
208
};
209
210
// Flags fields declarations for iperf2_lower_flags
211
static int hf_iperf2_lower_header_cca;
212
213
static int * const iperf2_lower_flags[] = {
214
    &hf_iperf2_lower_header_cca,
215
    NULL
216
};
217
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;
224
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
232
};
233
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;
255
256
/* parser definitions for iperf2 payload */
257
static tvbparse_wanted_t *want;
258
static tvbparse_wanted_t *want_trailing;
259
260
static dissector_handle_t iperf2_handle_tcp;
261
static dissector_handle_t iperf2_handle_udp;
262
263
typedef struct {
264
    bool first_packet_processed;
265
    bool second_packet_processed;
266
} iperf2_conversation_t;
267
268
static void
269
0
format_version(char *buf, uint32_t value) {
270
0
    snprintf(buf, ITEM_LABEL_LENGTH, "%d.%d", (value & 0xFFFF0000) >> 16, (value & 0xFFFF));
271
0
}
272
273
static void
274
0
format_version_long(char *buf, uint64_t value) {
275
0
    snprintf(buf, ITEM_LABEL_LENGTH, "%d.%d.%d.%d",
276
0
            (uint32_t)((value & 0xFFFF000000000000) >> 48), (uint32_t)((value & 0xFFFF00000000) >> 32),
277
0
            (uint32_t)((value & 0xFFFF0000) >> 16), (uint32_t)(value & 0xFFFF));
278
0
}
279
280
static int
281
dissect_iperf2_payload(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
282
0
{
283
0
    proto_tree *data_tree;
284
285
0
    data_tree = proto_tree_add_subtree(tree, tvb, offset, tvb_reported_length(tvb) - offset, ett_data, NULL, "iPerf2 Payload");
286
0
    proto_tree_add_item(data_tree, hf_iperf2_payload, tvb, offset, tvb_reported_length(tvb) - offset, ENC_NA);
287
0
    offset = tvb_reported_length(tvb);
288
289
0
    return offset;
290
0
}
291
292
static int
293
dissect_iperf2_client_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, bool is_udp)
294
0
{
295
0
    uint32_t small_packets = 0;
296
0
    uint32_t initial_offset = offset;
297
0
    int client_header_size = 24;
298
0
    proto_tree *client_tree;
299
300
0
    if (is_udp) {
301
0
        small_packets = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
302
0
        if (small_packets & HEADER32_SMALL_TRIPTIMES) {
303
0
            client_header_size = 4;
304
0
        }
305
0
    }
306
307
0
    client_tree = proto_tree_add_subtree(tree, tvb, offset, client_header_size, ett_clienthdr, NULL, "iPerf2 Client Header");
308
0
    proto_tree_add_bitmask(client_tree, tvb, offset, hf_iperf2_flags, ett_client_hdr_flags, iperf2_flags, ENC_BIG_ENDIAN);
309
0
    offset += 4;
310
311
0
    if (is_udp) {
312
0
        if (small_packets & HEADER32_SMALL_TRIPTIMES) {
313
0
            if ((tvb_reported_length(tvb) - offset) > 0) {
314
0
                return dissect_iperf2_payload(tvb, tree, offset);
315
0
            } else {
316
0
                return offset - initial_offset;
317
0
            }
318
0
        }
319
0
    }
320
321
0
    proto_tree_add_item(client_tree, hf_iperf2_num_threads, tvb, offset, 4, ENC_BIG_ENDIAN);
322
0
    offset += 4;
323
0
    proto_tree_add_item(client_tree, hf_iperf2_mport, tvb, offset, 4, ENC_BIG_ENDIAN);
324
0
    offset += 4;
325
0
    proto_tree_add_item(client_tree, hf_iperf2_bufferlen, tvb, offset, 4, ENC_BIG_ENDIAN);
326
0
    offset += 4;
327
0
    proto_tree_add_item(client_tree, hf_iperf2_mwinband, tvb, offset, 4, ENC_BIG_ENDIAN);
328
0
    offset += 4;
329
0
    proto_tree_add_item(client_tree, hf_iperf2_mamount, tvb, offset, 4, ENC_BIG_ENDIAN);
330
0
    offset += 4;
331
332
0
    return offset - initial_offset;
333
0
}
334
335
static int
336
dissect_iperf2_extended_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
337
0
{
338
0
    uint32_t initial_offset = offset, permit_key_len = 0;
339
0
    proto_tree *extended_tree, *permit_key_tree;
340
0
    proto_item *ti;
341
342
0
    extended_tree = proto_tree_add_subtree(tree, tvb, offset, 36, ett_extendedhdr, NULL, "iPerf2 Extended Header");
343
0
    proto_tree_add_item(extended_tree, hf_iperf2_type, tvb, offset, 4, ENC_BIG_ENDIAN);
344
0
    offset += 4;
345
0
    proto_tree_add_item(extended_tree, hf_iperf2_length, tvb, offset, 4, ENC_BIG_ENDIAN);
346
0
    offset += 4;
347
0
    proto_tree_add_bitmask(extended_tree, tvb, offset, hf_iperf2_up_flags, ett_client_upper_flags, iperf2_upper_flags, ENC_BIG_ENDIAN);
348
0
    offset += 2;
349
0
    proto_tree_add_bitmask(extended_tree, tvb, offset, hf_iperf2_low_flags, ett_client_lower_flags, iperf2_lower_flags, ENC_BIG_ENDIAN);
350
0
    offset += 2;
351
0
    proto_tree_add_item(extended_tree, hf_iperf2_version_major, tvb, offset, 4, ENC_BIG_ENDIAN);
352
0
    offset += 4;
353
0
    proto_tree_add_item(extended_tree, hf_iperf2_version_minor, tvb, offset, 4, ENC_BIG_ENDIAN);
354
0
    offset += 4;
355
0
    ti = proto_tree_add_item(extended_tree, hf_iperf2_version, tvb, offset - 8, 8, ENC_BIG_ENDIAN);
356
0
    proto_item_set_generated(ti);
357
0
    proto_tree_add_item(extended_tree, hf_iperf2_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
358
0
    offset += 2;
359
0
    proto_tree_add_item(extended_tree, hf_iperf2_tos, tvb, offset, 2, ENC_BIG_ENDIAN);
360
0
    offset += 2;
361
0
    proto_tree_add_item(extended_tree, hf_iperf2_rate, tvb, offset, 4, ENC_BIG_ENDIAN);
362
0
    offset += 4;
363
0
    proto_tree_add_item(extended_tree, hf_iperf2_rate_units, tvb, offset, 4, ENC_BIG_ENDIAN);
364
0
    offset += 4;
365
0
    proto_tree_add_item(extended_tree, hf_iperf2_realtime, tvb, offset, 4, ENC_BIG_ENDIAN);
366
0
    offset += 4;
367
368
    // There may be an optional permit key at the end of this header. Flags are not reliable - do some heuristics here instead.
369
0
    if (tvb_reported_length(tvb) - offset >= 2) {
370
0
        permit_key_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
371
0
        if ((permit_key_len != 0) && (permit_key_len <= (tvb_reported_length(tvb) - offset - 2))) {
372
0
            permit_key_tree = proto_tree_add_subtree(tree, tvb, offset, permit_key_len + 2, ett_permit_key, NULL, "iPerf2 Permit Key");
373
0
            proto_tree_add_item(permit_key_tree, hf_iperf2_permit_key_len, tvb, offset, 2, ENC_BIG_ENDIAN);
374
0
            offset += 2;
375
0
            proto_tree_add_item(permit_key_tree, hf_iperf2_permit_key, tvb, offset, permit_key_len, ENC_ASCII);
376
0
            offset += permit_key_len;
377
0
        }
378
0
    }
379
0
    return offset - initial_offset;
380
0
}
381
382
static int
383
dissect_iperf2_isoch_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
384
0
{
385
0
    uint32_t initial_offset = offset;
386
0
    proto_tree *ext_isoch_tree;
387
388
0
    ext_isoch_tree = proto_tree_add_subtree(tree, tvb, offset, 32, ett_ext_isochhdr, NULL, "iPerf2 Extended Isochronous Header");
389
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_fpsl, tvb, offset, 4, ENC_BIG_ENDIAN);
390
0
    offset += 4;
391
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_fpsu, tvb, offset, 4, ENC_BIG_ENDIAN);
392
0
    offset += 4;
393
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_meanl, tvb, offset, 4, ENC_BIG_ENDIAN);
394
0
    offset += 4;
395
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_meanu, tvb, offset, 4, ENC_BIG_ENDIAN);
396
0
    offset += 4;
397
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_variancel, tvb, offset, 4, ENC_BIG_ENDIAN);
398
0
    offset += 4;
399
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_varianceu, tvb, offset, 4, ENC_BIG_ENDIAN);
400
0
    offset += 4;
401
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_burstipgl, tvb, offset, 4, ENC_BIG_ENDIAN);
402
0
    offset += 4;
403
0
    proto_tree_add_item(ext_isoch_tree, hf_iperf2_burstipg, tvb, offset, 4, ENC_BIG_ENDIAN);
404
0
    offset += 4;
405
406
0
    return offset - initial_offset;
407
0
}
408
409
static int
410
dissect_iperf2_isoch_payload_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
411
0
{
412
0
    proto_item *ti;
413
0
    uint32_t initial_offset = offset;
414
0
    proto_tree *isoch_tree;
415
0
    nstime_t isoch_timestamp;
416
0
    unsigned isoch_ts_sec = 0;
417
0
    unsigned isoch_ts_usec = 0;
418
419
0
    isoch_tree = proto_tree_add_subtree(tree, tvb, offset, 32, ett_isochhdr, NULL, "iPerf2 Isochronous Header");
420
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_burst_period, tvb, offset, 4, ENC_BIG_ENDIAN);
421
0
    offset += 4;
422
0
    proto_tree_add_item_ret_uint(isoch_tree, hf_iperf2_isoch_start_ts_s, tvb, offset, 4, ENC_BIG_ENDIAN, &isoch_ts_sec);
423
0
    offset += 4;
424
0
    proto_tree_add_item_ret_uint(isoch_tree, hf_iperf2_isoch_start_ts_us, tvb, offset, 4, ENC_BIG_ENDIAN, &isoch_ts_usec);
425
0
    offset += 4;
426
0
    isoch_timestamp.secs  = (time_t)isoch_ts_sec;
427
0
    isoch_timestamp.nsecs = (int)isoch_ts_usec * 1000;
428
0
    ti = proto_tree_add_time(isoch_tree, hf_iperf2_isoch_start_ts, tvb, offset - 8, 8, &isoch_timestamp);
429
0
    proto_item_set_generated(ti);
430
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_prev_frameid, tvb, offset, 4, ENC_BIG_ENDIAN);
431
0
    offset += 4;
432
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_frameid, tvb, offset, 4, ENC_BIG_ENDIAN);
433
0
    offset += 4;
434
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_burstsize, tvb, offset, 4, ENC_BIG_ENDIAN);
435
0
    offset += 4;
436
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_bytes_remaining, tvb, offset, 4, ENC_BIG_ENDIAN);
437
0
    offset += 4;
438
0
    proto_tree_add_item(isoch_tree, hf_iperf2_isoch_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
439
0
    offset += 4;
440
441
0
    return offset - initial_offset;
442
0
}
443
444
static int
445
dissect_iperf2_fq_start_time_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
446
0
{
447
0
    proto_item *ti;
448
0
    uint32_t initial_offset = offset;
449
0
    proto_tree *fq_tree;
450
0
    unsigned fq_ts_sec = 0;
451
0
    unsigned fq_ts_usec = 0;
452
0
    nstime_t fq_timestamp;
453
454
0
    fq_tree = proto_tree_add_subtree(tree, tvb, offset, 20, ett_fqhdr, NULL, "iPerf2 Fair Queue Start Time Header");
455
0
    proto_tree_add_item(fq_tree, hf_iperf2_reserved2, tvb, offset, 4, ENC_BIG_ENDIAN);
456
0
    offset += 4;
457
0
    proto_tree_add_item_ret_uint(fq_tree, hf_iperf2_start_tv_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &fq_ts_sec);
458
0
    offset += 4;
459
0
    proto_tree_add_item_ret_uint(fq_tree, hf_iperf2_start_tv_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &fq_ts_usec);
460
0
    offset += 4;
461
0
    fq_timestamp.secs  = (time_t)fq_ts_sec;
462
0
    fq_timestamp.nsecs = (int)fq_ts_usec * 1000;
463
0
    ti = proto_tree_add_time(fq_tree, hf_iperf2_start_tv, tvb, offset - 8, 8, &fq_timestamp);
464
0
    proto_item_set_generated(ti);
465
0
    proto_tree_add_item(fq_tree, hf_iperf2_fq_ratel, tvb, offset, 4, ENC_BIG_ENDIAN);
466
0
    offset += 4;
467
0
    proto_tree_add_item(fq_tree, hf_iperf2_fq_rateu, tvb, offset, 4, ENC_BIG_ENDIAN);
468
0
    offset += 4;
469
470
0
    return offset - initial_offset;
471
0
}
472
473
static int
474
dissect_iperf2_cca_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
475
0
{
476
0
    uint32_t initial_offset = offset;
477
0
    unsigned cca_payload_len;
478
0
    proto_tree *cca_tree;
479
480
0
    cca_payload_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
481
0
    cca_tree = proto_tree_add_subtree(tree, tvb, offset, cca_payload_len + 2, ett_cca_hdr, NULL, "iPerf2 CCA Header");
482
0
    proto_tree_add_item(cca_tree, hf_iperf2_cca_len, tvb, offset, 2, ENC_BIG_ENDIAN);
483
0
    offset += 2;
484
0
    proto_tree_add_item(cca_tree, hf_iperf2_cca_value, tvb, offset, cca_payload_len, ENC_ASCII);
485
0
    offset += cca_payload_len;
486
487
0
    return offset - initial_offset;
488
0
}
489
490
static int
491
dissect_iperf2_bounceback_header(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
492
0
{
493
0
    proto_tree *bb_tree, *bb_tree_clienttx_ts, *bb_tree_serverrx_ts, *bb_tree_servertx_ts, *bb_tree_read_ts;
494
0
    proto_item *ti;
495
0
    unsigned ts_sec = 0, ts_usec = 0;
496
0
    nstime_t clienttx_ts, serverrx_ts, servertx_ts, read_ts;
497
498
0
    bb_tree = proto_tree_add_subtree(tree, tvb, offset, 64, ett_bbhdr, NULL, "iPerf2 Bounceback Header");
499
0
    proto_tree_add_bitmask(bb_tree, tvb, offset, hf_iperf2_flags, ett_client_hdr_flags, iperf2_flags, ENC_BIG_ENDIAN);
500
0
    offset += 4;
501
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_size, tvb, offset, 4, ENC_BIG_ENDIAN);
502
0
    offset += 4;
503
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_id, tvb, offset, 4, ENC_BIG_ENDIAN);
504
0
    offset += 4;
505
0
    proto_tree_add_bitmask(bb_tree, tvb, offset, hf_iperf2_bb_flags, ett_bb_hdr_flags, iperf2_bb_flags, ENC_BIG_ENDIAN);
506
0
    offset += 2;
507
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_tos, tvb, offset, 2, ENC_BIG_ENDIAN);
508
0
    offset += 2;
509
0
    unsigned bb_run_time = 0;
510
0
    ti = proto_tree_add_item_ret_uint(bb_tree, hf_iperf2_bb_run_time, tvb, offset, 4, ENC_BIG_ENDIAN, &bb_run_time);
511
0
    proto_item_append_text(ti, "%d ms", bb_run_time * 10);
512
0
    offset += 4;
513
514
0
    bb_tree_clienttx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbclienttx_ts, NULL, "Client Tx Timestamp");
515
0
    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
0
    offset += 4;
517
0
    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
0
    offset += 4;
519
0
    clienttx_ts.secs  = (time_t)ts_sec;
520
0
    clienttx_ts.nsecs = (int)ts_usec * 1000;
521
0
    ti = proto_tree_add_time(bb_tree_clienttx_ts, hf_iperf2_bb_clienttx_ts, tvb, offset - 8, 8, &clienttx_ts);
522
0
    proto_item_set_generated(ti);
523
524
0
    bb_tree_serverrx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbserverrx_ts, NULL, "Server Rx Timestamp");
525
0
    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
0
    offset += 4;
527
0
    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
0
    offset += 4;
529
0
    serverrx_ts.secs  = (time_t)ts_sec;
530
0
    serverrx_ts.nsecs = (int)ts_usec * 1000;
531
0
    ti = proto_tree_add_time(bb_tree_serverrx_ts, hf_iperf2_bb_serverrx_ts, tvb, offset - 8, 8, &serverrx_ts);
532
0
    proto_item_set_generated(ti);
533
534
0
    bb_tree_servertx_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbservertx_ts, NULL, "Server Tx Timestamp");
535
0
    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
0
    offset += 4;
537
0
    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
0
    offset += 4;
539
0
    servertx_ts.secs  = (time_t)ts_sec;
540
0
    servertx_ts.nsecs = (int)ts_usec * 1000;
541
0
    ti = proto_tree_add_time(bb_tree_servertx_ts, hf_iperf2_bb_servertx_ts, tvb, offset - 8, 8, &servertx_ts);
542
0
    proto_item_set_generated(ti);
543
544
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_hold, tvb, offset, 4, ENC_BIG_ENDIAN);
545
0
    offset += 4;
546
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_rtt, tvb, offset, 4, ENC_BIG_ENDIAN);
547
0
    offset += 4;
548
549
0
    bb_tree_read_ts = proto_tree_add_subtree(bb_tree, tvb, offset, 8, ett_bbread_ts, NULL, "Read Timestamp");
550
0
    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
0
    offset += 4;
552
0
    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
0
    offset += 4;
554
0
    read_ts.secs  = (time_t)ts_sec;
555
0
    read_ts.nsecs = (int)ts_usec * 1000;
556
0
    ti = proto_tree_add_time(bb_tree_read_ts, hf_iperf2_bb_read_ts, tvb, offset - 8, 8, &read_ts);
557
0
    proto_item_set_generated(ti);
558
559
0
    proto_tree_add_item(bb_tree, hf_iperf2_bb_reply_size, tvb, offset, 4, ENC_BIG_ENDIAN);
560
0
    offset += 4;
561
0
    return offset;
562
0
}
563
564
static int
565
dissect_iperf2_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
566
0
{
567
0
    proto_item *ti = NULL;
568
0
    proto_tree *iperf2_tree = NULL;
569
0
    uint32_t offset = 0, flags = 0, upper_flags = 0, lower_flags = 0, pdu_len = 24;
570
0
    uint16_t cca_len;
571
0
    tvbparse_t *tt;
572
573
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "iPerf2");
574
0
    col_clear(pinfo->cinfo, COL_INFO);
575
576
    // Is it the TCP first write with test information
577
0
    if ((tvb_reported_length(tvb) - offset) < pdu_len) { // We don't have enough data to decode the header
578
0
        offset += tvb_reported_length(tvb);
579
0
        pinfo->desegment_offset = offset;
580
0
        pinfo->desegment_len = pdu_len - offset;
581
0
        return tvb_reported_length(tvb);
582
0
    }
583
584
0
    flags = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
585
0
    ti = proto_tree_add_item(tree, proto_iperf2, tvb, offset, pdu_len, ENC_NA);
586
0
    iperf2_tree = proto_item_add_subtree(ti, ett_iperf2_tcp);
587
588
    // Check if we got iPerf2 payload
589
    // First, check if the first 10 bytes look like payload
590
0
    tt = tvbparse_init(pinfo->pool, tvb, offset, 10, NULL, NULL);
591
0
    if (tvbparse_get(tt, want)) { // Okay, the first 10 bytes follow the pattern, continue...
592
0
        tvbparse_reset(tt, offset + 10, tvb_reported_length(tvb) - 10);
593
0
        while(tvbparse_curr_offset(tt) < tvb_reported_length(tvb)) {
594
0
            if(tvbparse_get(tt, want) == NULL)
595
0
                break;
596
0
      }
597
        // Special case for the trailing payload bytes less than 10 bytes of length
598
0
        if ((tvb_reported_length(tvb) - tvbparse_curr_offset(tt)) <= 10) {
599
0
            tvbparse_get(tt, want_trailing);
600
0
        }
601
0
        if (tvbparse_curr_offset(tt) == tvb_reported_length(tvb)) {
602
0
            col_set_str(pinfo->cinfo, COL_INFO, "Payload only");
603
0
            offset += dissect_iperf2_payload(tvb, iperf2_tree, offset);
604
0
            proto_item_set_len(ti, tvb_reported_length(tvb));
605
0
            return offset;
606
0
        }
607
0
    }
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)
616
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
0
    for (int pass = 1; pass <= 2; pass++) {
622
0
        if (flags & HEADER_BOUNCEBACK) {
623
0
            (pass == 1) ? (pdu_len = 64) : (offset += dissect_iperf2_bounceback_header(tvb, iperf2_tree, offset));
624
0
            col_set_str(pinfo->cinfo, COL_INFO, "Bounceback");
625
0
        } else {
626
0
            if (pass == 2)
627
0
                offset += dissect_iperf2_client_header(tvb, iperf2_tree, offset, false);
628
0
            if (flags & HEADER_EXTEND) {
629
0
                if (pass == 1)
630
0
                    pdu_len += 36;
631
0
                else {
632
0
                    upper_flags = tvb_get_uint16(tvb, offset + 8, ENC_BIG_ENDIAN);
633
0
                    lower_flags = tvb_get_uint16(tvb, offset + 10, ENC_BIG_ENDIAN);
634
0
                    offset += dissect_iperf2_extended_header(tvb, iperf2_tree, offset);
635
0
                }
636
0
            }
637
            // If CCA header is present, the the previous two headers are also present, though the flags may not be set
638
0
            if (lower_flags & HEADER_CCA) {
639
0
                if (pass == 1) {
640
0
                    cca_len = tvb_get_uint16(tvb, offset + 20 + 40, ENC_BIG_ENDIAN) + 2;
641
0
                    pdu_len += 20 + 40 + cca_len;
642
0
                }
643
0
                else {
644
0
                    offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset);
645
0
                    offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset);
646
0
                    offset += dissect_iperf2_cca_header(tvb, iperf2_tree, offset);
647
0
                }
648
0
            } else {
649
0
                if (upper_flags & HEADER_TRIPTIME || upper_flags & HEADER_FQRATESET ||
650
0
                    upper_flags & HEADER_ISOCH_SETTINGS || upper_flags & HEADER_EPOCH_START) {
651
0
                    (pass == 1) ? (pdu_len += 20) : (offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset));
652
0
                }
653
0
                if (upper_flags & HEADER_FULLDUPLEX || upper_flags & HEADER_REVERSE || upper_flags & HEADER_PERIODICBURST) {
654
0
                    (pass == 1) ? (pdu_len += 40) : (offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset));
655
0
                }
656
0
            }
657
0
        }
658
0
        if ((pass == 1) && (tvb_reported_length(tvb) - offset) < pdu_len) { // We don't have enough data to decode all headers
659
0
            offset += tvb_reported_length(tvb);
660
0
            pinfo->desegment_offset = offset;
661
0
            pinfo->desegment_len = pdu_len - offset;
662
0
            proto_item_set_len(ti, tvb_reported_length(tvb));
663
0
            return tvb_reported_length(tvb);
664
0
        }
665
0
    }
666
0
    if ((tvb_reported_length(tvb) - offset) > 0) {
667
0
        offset += dissect_iperf2_payload(tvb, iperf2_tree, offset);
668
0
    }
669
0
    proto_item_set_len(ti, offset);
670
0
    return offset;
671
0
}
672
673
static int
674
dissect_iperf2_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
675
0
{
676
0
    uint32_t offset = 0;
677
0
    uint32_t ext_header = 0;
678
0
    proto_item *ti;
679
0
    proto_tree *iperf2_tree, *udp_tree;
680
681
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "iPerf2");
682
    /* Clear out stuff in the info column */
683
0
    col_clear(pinfo->cinfo, COL_INFO);
684
685
0
    ti = proto_tree_add_item(tree, proto_iperf2, tvb, offset, IPERF2_UDP_HDR_SIZE, ENC_NA);
686
0
    iperf2_tree = proto_item_add_subtree(ti, ett_iperf2_udp);
687
688
0
    udp_tree = proto_tree_add_subtree(iperf2_tree, tvb, offset, 16, ett_udphdr, NULL, "iPerf2 UDP Header");
689
0
    proto_tree_add_item(udp_tree, hf_iperf2_sequence, tvb, offset, 4, ENC_BIG_ENDIAN);
690
0
    offset += 4;
691
0
    unsigned ts_sec = 0;
692
0
    proto_tree_add_item_ret_uint(udp_tree, hf_iperf2_sec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_sec);
693
0
    offset += 4;
694
0
    unsigned ts_usec = 0;
695
0
    proto_tree_add_item_ret_uint(udp_tree, hf_iperf2_usec, tvb, offset, 4, ENC_BIG_ENDIAN, &ts_usec);
696
0
    offset += 4;
697
0
    nstime_t timestamp;
698
0
    timestamp.secs  = (time_t)ts_sec;
699
0
    timestamp.nsecs = (int)ts_usec * 1000;
700
0
    ti = proto_tree_add_time(udp_tree, hf_iperf2_timestamp, tvb, offset - 8, 8, &timestamp);
701
0
    proto_item_set_generated(ti);
702
0
    proto_tree_add_item(udp_tree, hf_iperf2_sequence_upper, tvb, offset, 4, ENC_BIG_ENDIAN);
703
0
    offset += 4;
704
0
    ext_header = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
705
706
0
    offset += dissect_iperf2_client_header(tvb, iperf2_tree, offset, true);
707
708
0
    if (tvb_reported_length(tvb) == offset) {
709
0
        return offset;
710
0
    }
711
    //Check is Extended header flag is set, if it's not - do no add more subheaders
712
0
    if (!(ext_header & HEADER_EXTEND)) {
713
0
        return dissect_iperf2_payload(tvb, iperf2_tree, offset);
714
0
    }
715
716
0
    offset += dissect_iperf2_extended_header(tvb, iperf2_tree, offset);
717
718
0
    offset += dissect_iperf2_isoch_payload_header(tvb, iperf2_tree, offset);
719
720
0
    offset += dissect_iperf2_fq_start_time_header(tvb, iperf2_tree, offset);
721
722
0
    offset += dissect_iperf2_isoch_header(tvb, iperf2_tree, offset);
723
724
0
    if ((tvb_reported_length(tvb) - offset) > 0) {
725
0
        return dissect_iperf2_payload(tvb, iperf2_tree, offset);
726
0
    } else {
727
0
        return offset;
728
0
    }
729
0
}
730
731
void
732
proto_register_iperf2(void)
733
14
{
734
    /* Setup list of header fields */
735
14
    static hf_register_info hf[] = {
736
14
        { &hf_iperf2_sequence,
737
14
            { "Sequence Number", "iperf2.udp.sequence", FT_INT32, BASE_DEC,
738
14
            NULL, 0, NULL, HFILL }
739
14
        },
740
14
        { &hf_iperf2_sec,
741
14
            { "Start Time (sec)", "iperf2.udp.sec", FT_UINT32, BASE_DEC,
742
14
            NULL, 0, NULL, HFILL }
743
14
        },
744
14
        { &hf_iperf2_usec,
745
14
            { "Start Time (usec)", "iperf2.udp.usec", FT_UINT32, BASE_DEC,
746
14
            NULL, 0, NULL, HFILL }
747
14
        },
748
14
        { &hf_iperf2_timestamp,
749
14
            { "Start Time", "iperf2.udp.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
750
14
            NULL, 0, NULL, HFILL }
751
14
        },
752
14
        { &hf_iperf2_sequence_upper,
753
14
            { "Upper Sequence Number", "iperf2.udp.sequence_upper", FT_INT32, BASE_DEC,
754
14
            NULL, 0, NULL, HFILL }
755
14
        },
756
14
        { &hf_iperf2_flags,
757
14
            { "Flags", "iperf2.client.flags", FT_UINT32, BASE_HEX,
758
14
            NULL, 0, NULL, HFILL }
759
14
        },
760
14
        { &hf_iperf2_flag_header_version1,
761
14
            { "Header Valid", "iperf2.client.flags_version1", FT_BOOLEAN, 32,
762
14
            NULL, HEADER_VERSION1, NULL, HFILL }
763
14
        },
764
14
        { &hf_iperf2_flag_header_extend,
765
14
            { "Extended Version", "iperf2.client.flags_extend", FT_BOOLEAN, 32,
766
14
            NULL, HEADER_EXTEND, NULL, HFILL }
767
14
        },
768
14
        { &hf_iperf2_header_udptests,
769
14
            { "UDP Tests", "iperf2.client.flags_udp_tests", FT_BOOLEAN, 32,
770
14
            NULL, HEADER_UDPTESTS, NULL, HFILL }
771
14
        },
772
14
        { &hf_iperf2_header_seqno64b,
773
14
            { "64 Bit Seq Num", "iperf2.client.flags_seqno64b", FT_BOOLEAN, 32,
774
14
            NULL, HEADER_SEQNO64B, "64-bits sequence numbers are used", HFILL }
775
14
        },
776
14
        { &hf_iperf2_header_version2,
777
14
            { "Version 2", "iperf2.client.flags_version2", FT_BOOLEAN, 32,
778
14
            NULL, HEADER_VERSION2, NULL, HFILL }
779
14
        },
780
14
        { &hf_iperf2_header_v2peerdetect,
781
14
            { "Version 2 Peer Detect", "iperf2.client.flags_version2_peerdetect", FT_BOOLEAN, 32,
782
14
            NULL, HEADER_V2PEERDETECT, NULL, HFILL }
783
14
        },
784
14
        { &hf_iperf2_header_udpavoid,
785
14
            { "Don't use for UDP", "iperf2.client.flags_udpavoid", FT_BOOLEAN, 32,
786
14
            NULL, HEADER_UDPAVOID1, "Don't use these bits for UDP", HFILL }
787
14
        },
788
14
        { &hf_iperf2_header_bounceback,
789
14
            { "Bounceback", "iperf2.client.flags_bounceback", FT_BOOLEAN, 32,
790
14
            NULL, HEADER_BOUNCEBACK, NULL, HFILL }
791
14
        },
792
14
        { &hf_iperf2_header_len_bit,
793
14
            { "Length Bit", "iperf2.client.flags_len_bit", FT_BOOLEAN, 32,
794
14
            NULL, HEADER_LEN_BIT, NULL, HFILL }
795
14
        },
796
14
        { &hf_iperf2_header_len_mask,
797
14
            { "Length Mask", "iperf2.client.flags_len_mask", FT_UINT32, BASE_HEX,
798
14
            NULL, HEADER_LEN_MASK, NULL, HFILL }
799
14
        },
800
14
        { &hf_iperf2_run_now,
801
14
            { "Run Now", "iperf2.client.flags_run_now", FT_BOOLEAN, 32,
802
14
            NULL, RUN_NOW, NULL, HFILL }
803
14
        },
804
14
        { &hf_iperf2_header16_small_triptimes,
805
14
            { "Small Triptimes", "iperf2.client.flags_small_triptimes", FT_BOOLEAN, 32,
806
14
            NULL, HEADER16_SMALL_TRIPTIMES, "Don't decode other fields in this packet", HFILL }
807
14
        },
808
14
        { &hf_iperf2_num_threads,
809
14
            { "Number of Threads", "iperf2.client.numthreads", FT_UINT32, BASE_DEC,
810
14
            NULL, 0, NULL, HFILL }
811
14
        },
812
14
        { &hf_iperf2_mport,
813
14
            { "Port", "iperf2.client.port", FT_UINT32, BASE_DEC,
814
14
            NULL, 0, NULL, HFILL }
815
14
        },
816
14
        { &hf_iperf2_bufferlen,
817
14
            { "Buffer Length", "iperf2.client.bufferlen", FT_UINT32, BASE_DEC,
818
14
            NULL, 0, NULL, HFILL }
819
14
        },
820
14
        { &hf_iperf2_mwinband,
821
14
            { "Bandwidth", "iperf2.client.bandwidth", FT_UINT32, BASE_DEC,
822
14
            NULL, 0, NULL, HFILL }
823
14
        },
824
14
        { &hf_iperf2_mamount,
825
14
            { "Amount (Time or Bytes)", "iperf2.client.num_bytes", FT_INT32, BASE_DEC,
826
14
            NULL, 0, NULL, HFILL }
827
14
        },
828
14
        { &hf_iperf2_type,
829
14
            { "Type", "iperf2.client.type", FT_UINT32, BASE_DEC,
830
14
            NULL, 0, NULL, HFILL }
831
14
        },
832
14
        { &hf_iperf2_length,
833
14
            { "Length", "iperf2.client.length", FT_UINT32, BASE_DEC,
834
14
            NULL, 0, NULL, HFILL }
835
14
        },
836
14
        { &hf_iperf2_up_flags,
837
14
            { "Upper Flags", "iperf2.client.up_flags", FT_UINT16, BASE_HEX,
838
14
            NULL, 0, NULL, HFILL }
839
14
        },
840
14
        { &hf_iperf2_upper_header_isoch,
841
14
            { "Isochronous Header", "iperf2.client.upper_header_isoch", FT_BOOLEAN, 16,
842
14
            NULL, HEADER_ISOCH, NULL, HFILL }
843
14
        },
844
14
        { &hf_iperf2_upper_header_l2ethpipv6,
845
14
            { "L2 ETH IPv6", "iperf2.client.upper_header_l2ethpipv6", FT_BOOLEAN, 16,
846
14
            NULL, HEADER_L2ETHPIPV6, NULL, HFILL }
847
14
        },
848
14
        { &hf_iperf2_upper_header_l2lencheck,
849
14
            { "L2 Length Check", "iperf2.client.upper_header_l2lencheck", FT_BOOLEAN, 16,
850
14
            NULL, HEADER_L2LENCHECK, NULL, HFILL }
851
14
        },
852
14
        { &hf_iperf2_upper_header_noudpfin,
853
14
            { "No UDP Fin", "iperf2.client.upper_header_noudpfin", FT_BOOLEAN, 16,
854
14
            NULL, HEADER_NOUDPFIN, NULL, HFILL }
855
14
        },
856
14
        { &hf_iperf2_upper_header_triptime,
857
14
            { "Trip Time", "iperf2.client.upper_header_triptime", FT_BOOLEAN, 16,
858
14
            NULL, HEADER_TRIPTIME, NULL, HFILL }
859
14
        },
860
14
        { &hf_iperf2_upper_header_unused2,
861
14
            { "Unused", "iperf2.client.upper_header_unused2", FT_BOOLEAN, 16,
862
14
            NULL, HEADER_UNUSED2, NULL, HFILL }
863
14
        },
864
14
        { &hf_iperf2_upper_header_isoch_settings,
865
14
            { "Isochronous Settings", "iperf2.client.upper_header_isoch_settings", FT_BOOLEAN, 16,
866
14
            NULL, HEADER_ISOCH_SETTINGS, NULL, HFILL }
867
14
        },
868
14
        { &hf_iperf2_upper_header_units_pps,
869
14
            { "Units PPS", "iperf2.client.upper_header_units_pps", FT_BOOLEAN, 16,
870
14
            NULL, HEADER_UNITS_PPS, NULL, HFILL }
871
14
        },
872
14
        { &hf_iperf2_upper_header_bwset,
873
14
            { "Header BW Set", "iperf2.client.upper_header_bwset", FT_BOOLEAN, 16,
874
14
            NULL, HEADER_BWSET, NULL, HFILL }
875
14
        },
876
14
        { &hf_iperf2_upper_header_fqrateset,
877
14
            { "Fair Queue Rate Set", "iperf2.client.upper_header_fqrateset", FT_BOOLEAN, 16,
878
14
            NULL, HEADER_FQRATESET, NULL, HFILL }
879
14
        },
880
14
        { &hf_iperf2_upper_header_reverse,
881
14
            { "Reverse", "iperf2.client.upper_header_reverse", FT_BOOLEAN, 16,
882
14
            NULL, HEADER_REVERSE, NULL, HFILL }
883
14
        },
884
14
        { &hf_iperf2_upper_header_fullduplex,
885
14
            { "Full Duplex", "iperf2.client.upper_header_fullduplex", FT_BOOLEAN, 16,
886
14
            NULL, HEADER_FULLDUPLEX, NULL, HFILL }
887
14
        },
888
14
        { &hf_iperf2_upper_header_epoch_start,
889
14
            { "Epoch Start", "iperf2.client.upper_header_epoch_start", FT_BOOLEAN, 16,
890
14
            NULL, HEADER_EPOCH_START, NULL, HFILL }
891
14
        },
892
14
        { &hf_iperf2_upper_header_periodicburst,
893
14
            { "Periodic Burst", "iperf2.client.upper_header_periodicburst", FT_BOOLEAN, 16,
894
14
            NULL, HEADER_PERIODICBURST, NULL, HFILL }
895
14
        },
896
14
        { &hf_iperf2_upper_header_writeprefetch,
897
14
            { "Write Prefetch", "iperf2.client.upper_header_writeprefetch", FT_BOOLEAN, 16,
898
14
            NULL, HEADER_WRITEPREFETCH, NULL, HFILL }
899
14
        },
900
14
        { &hf_iperf2_upper_header_tcpquickack,
901
14
            { "TCP Quick Ack", "iperf2.client.upper_header_tcpquickack", FT_BOOLEAN, 16,
902
14
            NULL, HEADER_TCPQUICKACK, NULL, HFILL }
903
14
        },
904
14
        { &hf_iperf2_low_flags,
905
14
            { "Lower Flags", "iperf2.client.low_flags", FT_UINT16, BASE_HEX,
906
14
            NULL, 0, NULL, HFILL }
907
14
        },
908
14
        { &hf_iperf2_lower_header_cca,
909
14
            { "CCA", "iperf2.client.lower_header_cca", FT_BOOLEAN, 16,
910
14
            NULL, HEADER_CCA, NULL, HFILL }
911
14
        },
912
14
        { &hf_iperf2_version_major,
913
14
            { "Major Version", "iperf2.client.version_major", FT_UINT32, BASE_CUSTOM,
914
14
            CF_FUNC(format_version), 0, NULL, HFILL }
915
14
        },
916
14
        { &hf_iperf2_version_minor,
917
14
            { "Minor Version", "iperf2.client.version_minor", FT_UINT32, BASE_CUSTOM,
918
14
            CF_FUNC(format_version), 0, NULL, HFILL }
919
14
        },
920
14
        { &hf_iperf2_version,
921
14
            { "Iperf2 Version", "iperf2.client.version", FT_UINT64, BASE_CUSTOM,
922
14
            CF_FUNC(format_version_long), 0, NULL, HFILL }
923
14
        },
924
14
        { &hf_iperf2_reserved,
925
14
            { "Reserved", "iperf2.client.reserved", FT_UINT16, BASE_HEX,
926
14
            NULL, 0, NULL, HFILL }
927
14
        },
928
14
        { &hf_iperf2_tos,
929
14
            { "TOS", "iperf2.client.tos", FT_UINT16, BASE_HEX,
930
14
            NULL, 0, NULL, HFILL }
931
14
        },
932
14
        { &hf_iperf2_rate,
933
14
            { "Rate", "iperf2.client.rate", FT_UINT32, BASE_DEC,
934
14
            NULL, 0, NULL, HFILL }
935
14
        },
936
14
        { &hf_iperf2_rate_units,
937
14
            { "Rate Units", "iperf2.client.rate_units", FT_UINT32, BASE_DEC,
938
14
            NULL, 0, NULL, HFILL }
939
14
        },
940
14
        { &hf_iperf2_realtime,
941
14
            { "TCP Realtime", "iperf2.client.realtime", FT_UINT32, BASE_DEC,
942
14
            NULL, 0, NULL, HFILL }
943
14
        },
944
14
        { &hf_iperf2_permit_key_len,
945
14
            { "Permit Key Length", "iperf2.client.permit_key_length", FT_UINT16, BASE_DEC,
946
14
            NULL, 0, NULL, HFILL }
947
14
        },
948
14
        { &hf_iperf2_permit_key,
949
14
            { "Permit Key", "iperf2.client.permit_key", FT_STRING, BASE_NONE,
950
14
            NULL, 0, NULL, HFILL }
951
14
        },
952
14
        { &hf_iperf2_isoch_burst_period,
953
14
            { "Burst Period", "iperf2.client.isoch_burst_period", FT_UINT32, BASE_DEC,
954
14
            NULL, 0, NULL, HFILL }
955
14
        },
956
14
        { &hf_iperf2_isoch_start_ts_s,
957
14
            { "Start Timestamp (s)", "iperf2.client.isoch_start_ts_s", FT_UINT32, BASE_DEC,
958
14
            NULL, 0, NULL, HFILL }
959
14
        },
960
14
        { &hf_iperf2_isoch_start_ts_us,
961
14
            { "Start Timestamp (us)", "iperf2.client.isoch_start_ts_us", FT_UINT32, BASE_DEC,
962
14
            NULL, 0, NULL, HFILL }
963
14
        },
964
14
        { &hf_iperf2_isoch_start_ts,
965
14
            { "Start Timestamp", "iperf2.client.isoch_start_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
966
14
            NULL, 0, NULL, HFILL }
967
14
        },
968
14
        { &hf_iperf2_isoch_prev_frameid,
969
14
            { "Previous Frame ID", "iperf2.client.isoch_prev_frameid", FT_UINT32, BASE_DEC,
970
14
            NULL, 0, NULL, HFILL }
971
14
        },
972
14
        { &hf_iperf2_isoch_frameid,
973
14
            { "Frame ID", "iperf2.client.isoch_frameid", FT_UINT32, BASE_DEC,
974
14
            NULL, 0, NULL, HFILL }
975
14
        },
976
14
        { &hf_iperf2_isoch_burstsize,
977
14
            { "Burst Size", "iperf2.client.isoch_burstsize", FT_UINT32, BASE_DEC,
978
14
            NULL, 0, NULL, HFILL }
979
14
        },
980
14
        { &hf_iperf2_isoch_bytes_remaining,
981
14
            { "Bytes Remaining", "iperf2.client.isoch_bytes_remaining", FT_UINT32, BASE_DEC,
982
14
            NULL, 0, NULL, HFILL }
983
14
        },
984
14
        { &hf_iperf2_isoch_reserved,
985
14
            { "Reserved", "iperf2.client.isoch_reserved", FT_UINT32, BASE_HEX,
986
14
            NULL, 0, NULL, HFILL }
987
14
        },
988
14
        { &hf_iperf2_reserved2,
989
14
            { "Reserved", "iperf2.client.reserved2", FT_UINT32, BASE_HEX,
990
14
            NULL, 0, NULL, HFILL }
991
14
        },
992
14
        { &hf_iperf2_start_tv_sec,
993
14
            { "Start TV (s)", "iperf2.client.start_tv_sec", FT_UINT32, BASE_DEC,
994
14
            NULL, 0, NULL, HFILL }
995
14
        },
996
14
        { &hf_iperf2_start_tv_usec,
997
14
            { "Start TV (us)", "iperf2.client.start_tv_usec", FT_UINT32, BASE_DEC,
998
14
            NULL, 0, NULL, HFILL }
999
14
        },
1000
14
        { &hf_iperf2_start_tv,
1001
14
            { "Start TV", "iperf2.client.start_tv", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1002
14
            NULL, 0, NULL, HFILL }
1003
14
        },
1004
14
        { &hf_iperf2_fq_ratel,
1005
14
            { "Fair-Queuing Rate Lower", "iperf2.client.fq_ratel", FT_UINT32, BASE_DEC,
1006
14
            NULL, 0, NULL, HFILL }
1007
14
        },
1008
14
        { &hf_iperf2_fq_rateu,
1009
14
            { "Fair-Queuing Rate Upper", "iperf2.client.fq_rateu", FT_UINT32, BASE_DEC,
1010
14
            NULL, 0, NULL, HFILL }
1011
14
        },
1012
14
        { &hf_iperf2_fpsl,
1013
14
            { "FPS Lower", "iperf2.client.fpsl", FT_UINT32, BASE_DEC,
1014
14
            NULL, 0, NULL, HFILL }
1015
14
        },
1016
14
        { &hf_iperf2_fpsu,
1017
14
            { "FPS Upper", "iperf2.client.fpsu", FT_UINT32, BASE_DEC,
1018
14
            NULL, 0, NULL, HFILL }
1019
14
        },
1020
14
        { &hf_iperf2_meanl,
1021
14
            { "Mean Lower", "iperf2.client.meanl", FT_UINT32, BASE_DEC,
1022
14
            NULL, 0, NULL, HFILL }
1023
14
        },
1024
14
        { &hf_iperf2_meanu,
1025
14
            { "Mean Upper", "iperf2.client.meanu", FT_UINT32, BASE_DEC,
1026
14
            NULL, 0, NULL, HFILL }
1027
14
        },
1028
14
        { &hf_iperf2_variancel,
1029
14
            { "Variance Lower", "iperf2.client.variancel", FT_UINT32, BASE_DEC,
1030
14
            NULL, 0, NULL, HFILL }
1031
14
        },
1032
14
        { &hf_iperf2_varianceu,
1033
14
            { "Variance Upper", "iperf2.client.varianceu", FT_UINT32, BASE_DEC,
1034
14
            NULL, 0, NULL, HFILL }
1035
14
        },
1036
14
        { &hf_iperf2_burstipgl,
1037
14
            { "Burst Inter-packet Gap Lower", "iperf2.client.burstipgl", FT_UINT32, BASE_DEC,
1038
14
            NULL, 0, NULL, HFILL }
1039
14
        },
1040
14
        { &hf_iperf2_burstipg,
1041
14
            { "Burst Inter-packet Gap", "iperf2.client.burstipg", FT_UINT32, BASE_DEC,
1042
14
            NULL, 0, NULL, HFILL }
1043
14
        },
1044
14
        { &hf_iperf2_cca_len,
1045
14
            { "CCA Length", "iperf2.client.cca_len", FT_UINT16, BASE_DEC,
1046
14
            NULL, 0, NULL, HFILL }
1047
14
        },
1048
14
        { &hf_iperf2_cca_value,
1049
14
            { "CCA Value", "iperf2.client.cca_value", FT_STRING, BASE_NONE,
1050
14
            NULL, 0, NULL, HFILL }
1051
14
        },
1052
14
        { &hf_iperf2_bb_size,
1053
14
            { "Bounceback Size", "iperf2.client.bb_size", FT_UINT32, BASE_DEC,
1054
14
            NULL, 0, NULL, HFILL }
1055
14
        },
1056
14
        { &hf_iperf2_bb_id,
1057
14
            { "Bounceback ID", "iperf2.client.bb_id", FT_UINT32, BASE_DEC,
1058
14
            NULL, 0, NULL, HFILL }
1059
14
        },
1060
14
        { &hf_iperf2_bb_flags,
1061
14
            { "Bounceback Flags", "iperf2.client.bb_flags", FT_UINT16, BASE_HEX,
1062
14
            NULL, 0, NULL, HFILL }
1063
14
        },
1064
14
        { &hf_iperf2_header_bbquickack,
1065
14
            { "Quick Ack", "iperf2.client.bb_flags_quickack", FT_BOOLEAN, 16,
1066
14
            NULL, HEADER_BBQUICKACK, NULL, HFILL }
1067
14
        },
1068
14
        { &hf_iperf2_header_bbclocksynced,
1069
14
            { "Clock Synced", "iperf2.client.bb_flags_clock_synced", FT_BOOLEAN, 16,
1070
14
            NULL, HEADER_BBCLOCKSYNCED, NULL, HFILL }
1071
14
        },
1072
14
        { &hf_iperf2_header_bbtos,
1073
14
            { "ToS", "iperf2.client.bb_flags_tos", FT_BOOLEAN, 16,
1074
14
            NULL, HEADER_BBTOS, NULL, HFILL }
1075
14
        },
1076
14
        { &hf_iperf2_header_bbstop,
1077
14
            { "Stop", "iperf2.client.bb_flags_stop", FT_BOOLEAN, 16,
1078
14
            NULL, HEADER_BBSTOP, NULL, HFILL }
1079
14
        },
1080
14
        { &hf_iperf2_header_bbreplysize,
1081
14
            { "Reply Size", "iperf2.client.bb_flags_reply_size", FT_BOOLEAN, 16,
1082
14
            NULL, HEADER_BBREPLYSIZE, NULL, HFILL }
1083
14
        },
1084
14
        { &hf_iperf2_bb_tos,
1085
14
            { "Bounceback ToS", "iperf2.client.bb_tos", FT_UINT16, BASE_HEX,
1086
14
            NULL, 0, NULL, HFILL }
1087
14
        },
1088
14
        { &hf_iperf2_bb_run_time,
1089
14
            { "Bounceback Run Time", "iperf2.client.bb_run_time", FT_UINT32, BASE_DEC,
1090
14
            NULL, 0, NULL, HFILL }
1091
14
        },
1092
14
        { &hf_iperf2_bb_clienttx_ts_sec,
1093
14
            { "Client TX Timestamp (s)", "iperf2.client.bb_clienttx_ts_sec", FT_UINT32, BASE_DEC,
1094
14
            NULL, 0, NULL, HFILL }
1095
14
        },
1096
14
        { &hf_iperf2_bb_clienttx_ts_usec,
1097
14
            { "Client TX Timestamp (us)", "iperf2.client.bb_clienttx_ts_usec", FT_UINT32, BASE_DEC,
1098
14
            NULL, 0, NULL, HFILL }
1099
14
        },
1100
14
        { &hf_iperf2_bb_clienttx_ts,
1101
14
            { "Client TX Timestamp", "iperf2.client.bb_clienttx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1102
14
            NULL, 0, NULL, HFILL }
1103
14
        },
1104
14
        { &hf_iperf2_bb_serverrx_ts_sec,
1105
14
            { "Server RX Timestamp (s)", "iperf2.client.bb_serverrx_ts_sec", FT_UINT32, BASE_DEC,
1106
14
            NULL, 0, NULL, HFILL }
1107
14
        },
1108
14
        { &hf_iperf2_bb_serverrx_ts_usec,
1109
14
            { "Server RX Timestamp (us)", "iperf2.client.bb_serverrx_ts_usec", FT_UINT32, BASE_DEC,
1110
14
            NULL, 0, NULL, HFILL }
1111
14
        },
1112
14
        { &hf_iperf2_bb_serverrx_ts,
1113
14
            { "Server RX Timestamp", "iperf2.client.bb_serverrx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1114
14
            NULL, 0, NULL, HFILL }
1115
14
        },
1116
14
        { &hf_iperf2_bb_servertx_ts_sec,
1117
14
            { "Server TX Timestamp (s)", "iperf2.client.bb_servertx_ts_sec", FT_UINT32, BASE_DEC,
1118
14
            NULL, 0, NULL, HFILL }
1119
14
        },
1120
14
        { &hf_iperf2_bb_servertx_ts_usec,
1121
14
            { "Server TX Timestamp (us)", "iperf2.client.bb_servertx_ts_usec", FT_UINT32, BASE_DEC,
1122
14
            NULL, 0, NULL, HFILL }
1123
14
        },
1124
14
        { &hf_iperf2_bb_servertx_ts,
1125
14
            { "Server TX Timestamp", "iperf2.client.bb_servertx_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1126
14
            NULL, 0, NULL, HFILL }
1127
14
        },
1128
14
        { &hf_iperf2_bb_hold,
1129
14
            { "Bounceback Hold", "iperf2.client.bb_hold", FT_UINT32, BASE_DEC,
1130
14
            NULL, 0, NULL, HFILL }
1131
14
        },
1132
14
        { &hf_iperf2_bb_rtt,
1133
14
            { "Bounceback RTT", "iperf2.client.bb_rtt", FT_UINT32, BASE_DEC,
1134
14
            NULL, 0, NULL, HFILL }
1135
14
        },
1136
14
        { &hf_iperf2_bb_read_ts_sec,
1137
14
            { "Read Timestamp (s)", "iperf2.client.bb_read_ts_sec", FT_UINT32, BASE_DEC,
1138
14
            NULL, 0, NULL, HFILL }
1139
14
        },
1140
14
        { &hf_iperf2_bb_read_ts_usec,
1141
14
            { "Read Timestamp (us)", "iperf2.client.bb_read_ts_usec", FT_UINT32, BASE_DEC,
1142
14
            NULL, 0, NULL, HFILL }
1143
14
        },
1144
14
        { &hf_iperf2_bb_read_ts,
1145
14
            { "Read Timestamp", "iperf2.client.bb_read_ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1146
14
            NULL, 0, NULL, HFILL }
1147
14
        },
1148
14
        { &hf_iperf2_bb_reply_size,
1149
14
            { "Bounceback Reply Size", "iperf2.client.bb_reply_size", FT_UINT32, BASE_DEC,
1150
14
            NULL, 0, NULL, HFILL }
1151
14
        },
1152
14
        { &hf_iperf2_payload,
1153
14
            { "Data", "iperf2.client.payload", FT_BYTES, BASE_NONE,
1154
14
            NULL, 0, NULL, HFILL }
1155
14
        },
1156
14
    };
1157
1158
    /* Setup protocol subtree array */
1159
14
    static int *ett[] = {
1160
14
        &ett_iperf2_udp,
1161
14
        &ett_iperf2_tcp,
1162
14
        &ett_udphdr,
1163
14
        &ett_clienthdr,
1164
14
        &ett_bbhdr,
1165
14
        &ett_extendedhdr,
1166
14
        &ett_permit_key,
1167
14
        &ett_client_upper_flags,
1168
14
        &ett_client_lower_flags,
1169
14
        &ett_isochhdr,
1170
14
        &ett_fqhdr,
1171
14
        &ett_ext_isochhdr,
1172
14
        &ett_client_hdr,
1173
14
        &ett_client_hdr_flags,
1174
14
        &ett_cca_hdr,
1175
14
        &ett_bb_hdr_flags,
1176
14
        &ett_bbclienttx_ts,
1177
14
        &ett_bbserverrx_ts,
1178
14
        &ett_bbservertx_ts,
1179
14
        &ett_bbread_ts,
1180
14
        &ett_data
1181
14
    };
1182
1183
    /* Register the protocol name and description */
1184
14
    proto_iperf2 = proto_register_protocol("iPerf2 Packet Data", "iPerf2", "iperf2");
1185
1186
14
    proto_register_field_array(proto_iperf2, hf, array_length(hf));
1187
14
    proto_register_subtree_array(ett, array_length(ett));
1188
1189
    /* Set up string templates for iperf2 payload */
1190
14
    want = tvbparse_set_oneof(0, NULL, NULL, NULL,
1191
14
                            tvbparse_string(-1,"0123456789",NULL,NULL,NULL),
1192
14
                            tvbparse_string(-1,"1234567890",NULL,NULL,NULL),
1193
14
                            tvbparse_string(-1,"2345678901",NULL,NULL,NULL),
1194
14
                            tvbparse_string(-1,"3456789012",NULL,NULL,NULL),
1195
14
                            tvbparse_string(-1,"4567890123",NULL,NULL,NULL),
1196
14
                            tvbparse_string(-1,"5678901234",NULL,NULL,NULL),
1197
14
                            tvbparse_string(-1,"6789012345",NULL,NULL,NULL),
1198
14
                            tvbparse_string(-1,"7890123456",NULL,NULL,NULL),
1199
14
                            tvbparse_string(-1,"8901234567",NULL,NULL,NULL),
1200
14
                            tvbparse_string(-1,"9012345678",NULL,NULL,NULL),
1201
14
                                NULL);
1202
14
    want_trailing = tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL);
1203
1204
14
    iperf2_handle_tcp = register_dissector("iperf2_tcp", dissect_iperf2_tcp, proto_iperf2);
1205
14
    iperf2_handle_udp = register_dissector("iperf2_udp", dissect_iperf2_udp, proto_iperf2);
1206
14
}
1207
1208
void
1209
proto_reg_handoff_iperf2(void)
1210
14
{
1211
14
    dissector_add_for_decode_as_with_preference("tcp.port", iperf2_handle_tcp);
1212
14
    dissector_add_for_decode_as_with_preference("udp.port", iperf2_handle_udp);
1213
14
}
1214
1215
/*
1216
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1217
 *
1218
 * Local variables:
1219
 * c-basic-offset: 4
1220
 * tab-width: 8
1221
 * indent-tabs-mode: nil
1222
 * End:
1223
 *
1224
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1225
 * :indentSize=4:tabSize=8:noTabs=true:
1226
 */