packet-ppi.c 69.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 * packet-ppi.c
 * Routines for PPI Packet Header dissection
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 2007 Gerald Combs
 *
 * Copyright (c) 2006 CACE Technologies, Davis (California)
 * All rights reserved.
 *
12
 * SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
13
14
15
16
 *
 *
 * Dustin Johnson - Dustin@Dustinj.us, Dustin.Johnson@cacetech.com
 *     May 7, 2008 - Added 'Aggregation Extension' and '802.3 Extension'
17
18
 */

Stephen Fisher's avatar
   
Stephen Fisher committed
19

20
#include "config.h"
21
22

#include <epan/packet.h>
23
#include <epan/capture_dissectors.h>
24
#include <epan/exceptions.h>
25
26
#include <epan/ptvcursor.h>
#include <epan/prefs.h>
27
#include <epan/expert.h>
28
#include <epan/reassemble.h>
29
#include <wsutil/802_11-utils.h>
30
#include <wsutil/pint.h>
31
#include <wsutil/str_util.h>
32
33
34

/*
 * Per-Packet Information (PPI) header.
35
36
37
38
 * See the PPI Packet Header documentation at
 *
 *     https://wayback.archive.org/web/20120525190041/https://www.cacetech.com/documents/PPI%20Header%20format%201.0.10.pdf
 *
39
40
41
42
43
44
45
46
47
48
49
50
51
 * for details.
 */

/*
 * PPI headers have the following format:
 *
 * ,---------------------------------------------------------.
 * | PPH | PFH 1 | Field data 1 | PFH 2 | Field data 2 | ... |
 * `---------------------------------------------------------'
 *
 * The PPH struct has the following format:
 *
 * typedef struct ppi_packetheader {
52
53
54
55
 *     guint8  pph_version;     // Version.  Currently 0
 *     guint8  pph_flags;       // Flags.
 *     guint16 pph_len; // Length of entire message, including this header and TLV payload.
 *     guint32 pph_dlt; // libpcap Data Link Type of the captured packet data.
56
57
58
59
60
 * } ppi_packetheader_t;
 *
 * The PFH struct has the following format:
 *
 * typedef struct ppi_fieldheader {
61
62
 *     guint16 pfh_type;        // Type
 *     guint16 pfh_datalen;     // Length of data
63
 * } ppi_fieldheader_t;
Stephen Fisher's avatar
   
Stephen Fisher committed
64
 *
Bill Meier's avatar
Bill Meier committed
65
66
67
 * Anyone looking to add their own PPI dissector would probably do well to imitate the GPS
 * ones separation into a distinct file.  Here is a step by step guide:
 * 1) add the number you received to the enum ppi_field_type declaration.
Stephen Fisher's avatar
   
Stephen Fisher committed
68
69
70
71
72
 * 2) Add a value string for your number into vs_ppi_field_type
 * 3) declare a dissector handle by the ppi_gps_handle, and initialize it inside proto_reg_handoff
 * 4) add  case inside dissect_ppi to call your new handle.
 * 5) Write your parser, and get it loaded.
 * Following these steps will result in less churn inside the ppi proper parser, and avoid namespace issues.
73
74
 */

Stephen Fisher's avatar
   
Stephen Fisher committed
75

76
77
78
79
80
81
82
#define PPI_PADDED (1 << 0)

#define PPI_V0_HEADER_LEN 8
#define PPI_80211_COMMON_LEN 20
#define PPI_80211N_MAC_LEN 12
#define PPI_80211N_MAC_PHY_OFF 9
#define PPI_80211N_MAC_PHY_LEN 48
83
84
#define PPI_AGGREGATION_EXTENSION_LEN 4
#define PPI_8023_EXTENSION_LEN 8
85
86
87
88

#define PPI_FLAG_ALIGN 0x01
#define IS_PPI_FLAG_ALIGN(x) ((x) & PPI_FLAG_ALIGN)

89
90
91
92
93
94
95
96
97
98
#define DOT11_FLAG_HAVE_FCS     0x0001
#define DOT11_FLAG_TSF_TIMER_MS 0x0002
#define DOT11_FLAG_FCS_INVALID  0x0004
#define DOT11_FLAG_PHY_ERROR    0x0008

#define DOT11N_FLAG_GREENFIELD      0x0001
#define DOT11N_FLAG_HT40            0x0002
#define DOT11N_FLAG_SHORT_GI        0x0004
#define DOT11N_FLAG_DUPLICATE_RX    0x0008
#define DOT11N_FLAG_IS_AGGREGATE    0x0010
99
#define DOT11N_FLAG_MORE_AGGREGATES 0x0020
100
#define DOT11N_FLAG_AGG_CRC_ERROR   0x0040
101

102
103
#define DOT11N_IS_AGGREGATE(flags)      (flags & DOT11N_FLAG_IS_AGGREGATE)
#define DOT11N_MORE_AGGREGATES(flags)   ( \
104
105
106
107
108
109
110
111
112
113
114
115
116
    (flags & DOT11N_FLAG_MORE_AGGREGATES) && \
    !(flags & DOT11N_FLAG_AGG_CRC_ERROR))
#define AGGREGATE_MAX 65535
#define AMPDU_MAX 16383

/* XXX - Start - Copied from packet-radiotap.c */
/* Channel flags. */
#define IEEE80211_CHAN_TURBO    0x0010  /* Turbo channel */
#define IEEE80211_CHAN_CCK      0x0020  /* CCK channel */
#define IEEE80211_CHAN_OFDM     0x0040  /* OFDM channel */
#define IEEE80211_CHAN_2GHZ     0x0080  /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ     0x0100  /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE  0x0200  /* Only passive scan allowed */
117
118
#define IEEE80211_CHAN_DYN      0x0400  /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK     0x0800  /* GFSK channel (FHSS PHY) */
119

120
121
122
123
124
125
#define	IEEE80211_CHAN_ALL \
	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \
         IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)
#define	IEEE80211_CHAN_ALLTURBO \
	(IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO)

126
127
128
/*
 * Useful combinations of channel characteristics.
 */
129
130
#define IEEE80211_CHAN_FHSS \
        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
131
132
#define	IEEE80211_CHAN_DSSS \
	(IEEE80211_CHAN_2GHZ)
133
134
135
136
137
138
139
140
#define IEEE80211_CHAN_A \
        (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
#define IEEE80211_CHAN_B \
        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
#define IEEE80211_CHAN_PUREG \
        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
#define IEEE80211_CHAN_G \
        (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
141
142
#define	IEEE80211_CHAN_108A \
	(IEEE80211_CHAN_A | IEEE80211_CHAN_TURBO)
143
144
145
146
#define IEEE80211_CHAN_108G \
        (IEEE80211_CHAN_G | IEEE80211_CHAN_TURBO)
#define IEEE80211_CHAN_108PUREG \
        (IEEE80211_CHAN_PUREG | IEEE80211_CHAN_TURBO)
147
148
/* XXX - End - Copied from packet-radiotap.c */

149
150
151
void proto_register_ppi(void);
void proto_reg_handoff_ppi(void);

152
153
typedef enum {
    /* 0 - 29999: Public types */
154
155
156
157
158
159
160
161
    PPI_80211_COMMON          =  2,
    PPI_80211N_MAC            =  3,
    PPI_80211N_MAC_PHY        =  4,
    PPI_SPECTRUM_MAP          =  5,
    PPI_PROCESS_INFO          =  6,
    PPI_CAPTURE_INFO          =  7,
    PPI_AGGREGATION_EXTENSION =  8,
    PPI_8023_EXTENSION        =  9,
162
163
164
    /* 11 - 29999: RESERVED */

    /* 30000 - 65535: Private types */
Stephen Fisher's avatar
   
Stephen Fisher committed
165
166
167
168
    INTEL_CORP_PRIVATE           = 30000,
    MOHAMED_THAGA_PRIVATE        = 30001,
    PPI_GPS_INFO                 = 30002, /* 30002 - 30005 described in PPI-GEOLOCATION specifcation */
    PPI_VECTOR_INFO              = 30003, /* currently available in draft from. jellch@harris.com */
169
    PPI_SENSOR_INFO              = 30004,
Stephen Fisher's avatar
   
Stephen Fisher committed
170
    PPI_ANTENNA_INFO             = 30005,
171
    FNET_PRIVATE                 = 0xC017,
Stephen Fisher's avatar
   
Stephen Fisher committed
172
    CACE_PRIVATE                 = 0xCACE
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    /* All others RESERVED.  Contact the WinPcap team for an assignment */
} ppi_field_type;

/* Protocol */
static int proto_ppi = -1;

/* Packet header */
static int hf_ppi_head_version = -1;
static int hf_ppi_head_flags = -1;
static int hf_ppi_head_flag_alignment = -1;
static int hf_ppi_head_flag_reserved = -1;
static int hf_ppi_head_len = -1;
static int hf_ppi_head_dlt = -1;

/* Field header */
static int hf_ppi_field_type = -1;
static int hf_ppi_field_len = -1;

/* 802.11 Common */
static int hf_80211_common_tsft = -1;
static int hf_80211_common_flags = -1;
static int hf_80211_common_flags_fcs = -1;
static int hf_80211_common_flags_tsft = -1;
static int hf_80211_common_flags_fcs_valid = -1;
static int hf_80211_common_flags_phy_err = -1;
static int hf_80211_common_rate = -1;
static int hf_80211_common_chan_freq = -1;
static int hf_80211_common_chan_flags = -1;

static int hf_80211_common_chan_flags_turbo = -1;
static int hf_80211_common_chan_flags_cck = -1;
static int hf_80211_common_chan_flags_ofdm = -1;
static int hf_80211_common_chan_flags_2ghz = -1;
static int hf_80211_common_chan_flags_5ghz = -1;
static int hf_80211_common_chan_flags_passive = -1;
static int hf_80211_common_chan_flags_dynamic = -1;
static int hf_80211_common_chan_flags_gfsk = -1;

static int hf_80211_common_fhss_hopset = -1;
static int hf_80211_common_fhss_pattern = -1;
static int hf_80211_common_dbm_antsignal = -1;
static int hf_80211_common_dbm_antnoise = -1;

/* 802.11n MAC */
static int hf_80211n_mac_flags = -1;
static int hf_80211n_mac_flags_greenfield = -1;
static int hf_80211n_mac_flags_ht20_40 = -1;
static int hf_80211n_mac_flags_rx_guard_interval = -1;
static int hf_80211n_mac_flags_duplicate_rx = -1;
static int hf_80211n_mac_flags_more_aggregates = -1;
static int hf_80211n_mac_flags_aggregate = -1;
static int hf_80211n_mac_flags_delimiter_crc_after = -1;
static int hf_80211n_mac_ampdu_id = -1;
static int hf_80211n_mac_num_delimiters = -1;
static int hf_80211n_mac_reserved = -1;

/* 802.11n MAC+PHY */
static int hf_80211n_mac_phy_mcs = -1;
static int hf_80211n_mac_phy_num_streams = -1;
static int hf_80211n_mac_phy_rssi_combined = -1;
static int hf_80211n_mac_phy_rssi_ant0_ctl = -1;
static int hf_80211n_mac_phy_rssi_ant1_ctl = -1;
static int hf_80211n_mac_phy_rssi_ant2_ctl = -1;
static int hf_80211n_mac_phy_rssi_ant3_ctl = -1;
static int hf_80211n_mac_phy_rssi_ant0_ext = -1;
static int hf_80211n_mac_phy_rssi_ant1_ext = -1;
static int hf_80211n_mac_phy_rssi_ant2_ext = -1;
static int hf_80211n_mac_phy_rssi_ant3_ext = -1;
static int hf_80211n_mac_phy_ext_chan_freq = -1;
static int hf_80211n_mac_phy_ext_chan_flags = -1;
static int hf_80211n_mac_phy_ext_chan_flags_turbo = -1;
244
static int hf_80211n_mac_phy_ext_chan_flags_cck = -1;
245
static int hf_80211n_mac_phy_ext_chan_flags_ofdm = -1;
246
static int hf_80211n_mac_phy_ext_chan_flags_2ghz = -1;
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
static int hf_80211n_mac_phy_ext_chan_flags_5ghz = -1;
static int hf_80211n_mac_phy_ext_chan_flags_passive = -1;
static int hf_80211n_mac_phy_ext_chan_flags_dynamic = -1;
static int hf_80211n_mac_phy_ext_chan_flags_gfsk = -1;
static int hf_80211n_mac_phy_dbm_ant0signal = -1;
static int hf_80211n_mac_phy_dbm_ant0noise = -1;
static int hf_80211n_mac_phy_dbm_ant1signal = -1;
static int hf_80211n_mac_phy_dbm_ant1noise = -1;
static int hf_80211n_mac_phy_dbm_ant2signal = -1;
static int hf_80211n_mac_phy_dbm_ant2noise = -1;
static int hf_80211n_mac_phy_dbm_ant3signal = -1;
static int hf_80211n_mac_phy_dbm_ant3noise = -1;
static int hf_80211n_mac_phy_evm0 = -1;
static int hf_80211n_mac_phy_evm1 = -1;
static int hf_80211n_mac_phy_evm2 = -1;
static int hf_80211n_mac_phy_evm3 = -1;

/* 802.11n-Extensions A-MPDU fragments */
static int hf_ampdu_reassembled_in = -1;
266
/* static int hf_ampdu_segments = -1; */
267
268
269
270
271
272
273
274
275
276
277
278
static int hf_ampdu_segment = -1;
static int hf_ampdu_count  = -1;

/* Spectrum-Map */
static int hf_spectrum_map = -1;

/* Process-Info */
static int hf_process_info = -1;

/* Capture-Info */
static int hf_capture_info = -1;

279
280
281
282
283
284
285
/* Aggregation Extension */
static int hf_aggregation_extension_interface_id = -1;

/* 802.3 Extension */
static int hf_8023_extension_flags = -1;
static int hf_8023_extension_flags_fcs_present = -1;
static int hf_8023_extension_errors = -1;
Gerald Combs's avatar
Gerald Combs committed
286
287
288
289
static int hf_8023_extension_errors_fcs = -1;
static int hf_8023_extension_errors_sequence = -1;
static int hf_8023_extension_errors_symbol = -1;
static int hf_8023_extension_errors_data = -1;
290

291
292
293
294
295
/* Generated from convert_proto_tree_add_text.pl */
static int hf_ppi_antenna = -1;
static int hf_ppi_harris = -1;
static int hf_ppi_reserved = -1;
static int hf_ppi_vector = -1;
296
static int hf_ppi_fnet = -1;
297
298
static int hf_ppi_gps = -1;

299
300
301
302
303
304
305
306
307
308
309
310
static gint ett_ppi_pph = -1;
static gint ett_ppi_flags = -1;
static gint ett_dot11_common = -1;
static gint ett_dot11_common_flags = -1;
static gint ett_dot11_common_channel_flags = -1;
static gint ett_dot11n_mac = -1;
static gint ett_dot11n_mac_flags = -1;
static gint ett_dot11n_mac_phy = -1;
static gint ett_dot11n_mac_phy_ext_channel_flags = -1;
static gint ett_ampdu_segments = -1;
static gint ett_ampdu = -1;
static gint ett_ampdu_segment  = -1;
311
312
313
314
static gint ett_aggregation_extension = -1;
static gint ett_8023_extension = -1;
static gint ett_8023_extension_flags = -1;
static gint ett_8023_extension_errors = -1;
315

316
317
318
/* Generated from convert_proto_tree_add_text.pl */
static expert_field ei_ppi_invalid_length = EI_INIT;

319
320
static dissector_handle_t ppi_handle;

321
static dissector_handle_t ieee80211_radio_handle;
322
static dissector_handle_t pcap_pktdata_handle;
Gerald Combs's avatar
Gerald Combs committed
323
static dissector_handle_t ppi_gps_handle, ppi_vector_handle, ppi_sensor_handle, ppi_antenna_handle;
324
static dissector_handle_t ppi_fnet_handle;
Stephen Fisher's avatar
   
Stephen Fisher committed
325

326
327
328
329
330
331
static const true_false_string tfs_ppi_head_flag_alignment = { "32-bit aligned", "Not aligned" };
static const true_false_string tfs_tsft_ms = { "milliseconds", "microseconds" };
static const true_false_string tfs_ht20_40 = { "HT40", "HT20" };
static const true_false_string tfs_phy_error = { "PHY error", "No errors"};

static const value_string vs_ppi_field_type[] = {
332
333
334
335
336
337
    {PPI_80211_COMMON,          "802.11-Common"},
    {PPI_80211N_MAC,            "802.11n MAC Extensions"},
    {PPI_80211N_MAC_PHY,        "802.11n MAC+PHY Extensions"},
    {PPI_SPECTRUM_MAP,          "Spectrum-Map"},
    {PPI_PROCESS_INFO,          "Process-Info"},
    {PPI_CAPTURE_INFO,          "Capture-Info"},
338
    {PPI_AGGREGATION_EXTENSION, "Aggregation Extension"},
339
340
341
342
343
344
345
346
    {PPI_8023_EXTENSION,        "802.3 Extension"},

    {INTEL_CORP_PRIVATE,        "Intel Corporation (private)"},
    {MOHAMED_THAGA_PRIVATE,     "Mohamed Thaga (private)"},
    {PPI_GPS_INFO,              "GPS Tagging"},
    {PPI_VECTOR_INFO,           "Vector Tagging"},
    {PPI_SENSOR_INFO,           "Sensor tagging"},
    {PPI_ANTENNA_INFO,          "Antenna Tagging"},
347
    {FNET_PRIVATE,              "FlukeNetworks (private)"},
348
    {CACE_PRIVATE,              "CACE Technologies (private)"},
349
350
351
    {0, NULL}
};

352
353
/* Table for A-MPDU reassembly */
static reassembly_table ampdu_reassembly_table;
354
355
356
357
358

/* Reassemble A-MPDUs? */
static gboolean ppi_ampdu_reassemble = TRUE;


mmann78's avatar
mmann78 committed
359
static gboolean
360
capture_ppi(const guchar *pd, int offset _U_, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_)
361
{
362
    guint32  dlt;
363
    guint    ppi_len;
Gerald Combs's avatar
Gerald Combs committed
364

365
    ppi_len = pletoh16(pd+2);
mmann78's avatar
mmann78 committed
366
367
    if(ppi_len < PPI_V0_HEADER_LEN || !BYTES_ARE_IN_FRAME(0, len, ppi_len))
        return FALSE;
368

369
    dlt = pletoh32(pd+4);
Gerald Combs's avatar
Gerald Combs committed
370

371
    return try_capture_dissector("ppi", dlt, pd, ppi_len, len, cpinfo, pseudo_header);
372
373
}

374
375
static void
ptvcursor_add_invalid_check(ptvcursor_t *csr, int hf, gint len, guint64 invalid_val) {
376
    proto_item *ti;
377
    guint64     val = invalid_val;
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399

    switch (len) {
        case 8:
            val = tvb_get_letoh64(ptvcursor_tvbuff(csr),
                ptvcursor_current_offset(csr));
            break;
        case 4:
            val = tvb_get_letohl(ptvcursor_tvbuff(csr),
                ptvcursor_current_offset(csr));
            break;
        case 2:
            val = tvb_get_letohs(ptvcursor_tvbuff(csr),
                ptvcursor_current_offset(csr));
            break;
        case 1:
            val = tvb_get_guint8(ptvcursor_tvbuff(csr),
                ptvcursor_current_offset(csr));
            break;
        default:
            DISSECTOR_ASSERT_NOT_REACHED();
    }

Bill Meier's avatar
Bill Meier committed
400
    ti = ptvcursor_add(csr, hf, len, ENC_LITTLE_ENDIAN);
401
402
403
404
405
406
407
    if (val == invalid_val)
        proto_item_append_text(ti, " [invalid]");
}

static void
add_ppi_field_header(tvbuff_t *tvb, proto_tree *tree, int *offset)
{
408
    ptvcursor_t *csr;
409

410
    csr = ptvcursor_new(wmem_packet_scope(), tree, tvb, *offset);
411
412
    ptvcursor_add(csr, hf_ppi_field_type, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_ppi_field_len, 2, ENC_LITTLE_ENDIAN);
413
414
415
416
417
418
    ptvcursor_free(csr);
    *offset=ptvcursor_current_offset(csr);
}

/* XXX - The main dissection function in the 802.11 dissector has the same name. */
static void
419
dissect_80211_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int data_len, struct ieee_802_11_phdr *phdr)
420
{
421
422
    proto_tree  *ftree;
    proto_item  *ti;
423
    ptvcursor_t *csr;
424
425
426
    guint64      tsft_raw;
    guint        rate_raw;
    guint        rate_kbps;
427
428
    guint32      common_flags;
    guint16      common_frequency;
429
    guint16      chan_flags;
430
    gint8        dbm_value;
431
    gchar       *chan_str;
432

433
    ftree = proto_tree_add_subtree(tree, tvb, offset, data_len, ett_dot11_common, NULL, "802.11-Common");
434
435
436
437
    add_ppi_field_header(tvb, ftree, &offset);
    data_len -= 4; /* Subtract field header length */

    if (data_len != PPI_80211_COMMON_LEN) {
438
        proto_tree_add_expert_format(ftree, pinfo, &ei_ppi_invalid_length, tvb, offset, data_len, "Invalid length: %u", data_len);
439
        return;
440
441
442
443
    }

    common_flags = tvb_get_letohs(tvb, offset + 8);
    if (common_flags & DOT11_FLAG_HAVE_FCS)
444
        phdr->fcs_len = 4;
445
    else
446
        phdr->fcs_len = 0;
447

448
    csr = ptvcursor_new(pinfo->pool, ftree, tvb, offset);
449

450
451
    tsft_raw = tvb_get_letoh64(tvb, offset);
    if (tsft_raw != 0) {
Simon Barber's avatar
Simon Barber committed
452
        phdr->has_tsf_timestamp = TRUE;
453
454
455
456
457
458
        if (common_flags & DOT11_FLAG_TSF_TIMER_MS)
            phdr->tsf_timestamp = tsft_raw * 1000;
        else
            phdr->tsf_timestamp = tsft_raw;
    }

459
460
    ptvcursor_add_invalid_check(csr, hf_80211_common_tsft, 8, 0);

461
    ptvcursor_add_with_subtree(csr, hf_80211_common_flags, 2, ENC_LITTLE_ENDIAN,
462
                               ett_dot11_common_flags);
463
464
465
466
    ptvcursor_add_no_advance(csr, hf_80211_common_flags_fcs, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_flags_tsft, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_flags_fcs_valid, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_80211_common_flags_phy_err, 2, ENC_LITTLE_ENDIAN);
467
468
    ptvcursor_pop_subtree(csr);

469
470
    rate_raw = tvb_get_letohs(tvb, ptvcursor_current_offset(csr));
    if (rate_raw != 0) {
Simon Barber's avatar
Simon Barber committed
471
        phdr->has_data_rate = TRUE;
472
473
474
        phdr->data_rate = rate_raw;
    }
    rate_kbps = rate_raw * 500;
475
    ti = proto_tree_add_uint_format(ftree, hf_80211_common_rate, tvb,
476
477
                                    ptvcursor_current_offset(csr), 2, rate_kbps, "Rate: %.1f Mbps",
                                    rate_kbps / 1000.0);
478
479
    if (rate_kbps == 0)
        proto_item_append_text(ti, " [invalid]");
480
    col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%.1f Mbps", rate_kbps / 1000.0);
481
482
483
    ptvcursor_advance(csr, 2);

    common_frequency = tvb_get_letohs(ptvcursor_tvbuff(csr), ptvcursor_current_offset(csr));
484
    if (common_frequency != 0) {
485
486
        gint calc_channel;

Simon Barber's avatar
Simon Barber committed
487
        phdr->has_frequency = TRUE;
488
        phdr->frequency = common_frequency;
489
490
        calc_channel = ieee80211_mhz_to_chan(common_frequency);
        if (calc_channel != -1) {
Simon Barber's avatar
Simon Barber committed
491
            phdr->has_channel = TRUE;
492
493
            phdr->channel = calc_channel;
        }
494
    }
495
    chan_str = ieee80211_mhz_to_str(common_frequency);
496
497
    proto_tree_add_uint_format_value(ptvcursor_tree(csr), hf_80211_common_chan_freq, ptvcursor_tvbuff(csr),
                               ptvcursor_current_offset(csr), 2, common_frequency, "%s", chan_str);
498
    col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%s", chan_str);
499
    g_free(chan_str);
500
501
    ptvcursor_advance(csr, 2);

Simon Barber's avatar
Simon Barber committed
502
    memset(&phdr->phy_info, 0, sizeof(phdr->phy_info));
503
504
505
506
    chan_flags = tvb_get_letohs(ptvcursor_tvbuff(csr), ptvcursor_current_offset(csr));
    switch (chan_flags & IEEE80211_CHAN_ALLTURBO) {

    case IEEE80211_CHAN_FHSS:
507
508
509
510
511
        phdr->phy = PHDR_802_11_PHY_11_FHSS;
        break;

    case IEEE80211_CHAN_DSSS:
        phdr->phy = PHDR_802_11_PHY_11_DSSS;
512
513
514
        break;

    case IEEE80211_CHAN_A:
515
        phdr->phy = PHDR_802_11_PHY_11A;
Simon Barber's avatar
Simon Barber committed
516
        phdr->phy_info.info_11a.has_turbo_type = TRUE;
517
        phdr->phy_info.info_11a.turbo_type = PHDR_802_11A_TURBO_TYPE_NORMAL;
518
519
520
        break;

    case IEEE80211_CHAN_B:
521
        phdr->phy = PHDR_802_11_PHY_11B;
522
523
524
        break;

    case IEEE80211_CHAN_PUREG:
525
        phdr->phy = PHDR_802_11_PHY_11G;
Simon Barber's avatar
Simon Barber committed
526
        phdr->phy_info.info_11g.has_mode = TRUE;
527
        phdr->phy_info.info_11g.mode = PHDR_802_11G_MODE_NORMAL;
528
529
530
        break;

    case IEEE80211_CHAN_G:
531
        phdr->phy = PHDR_802_11_PHY_11G;
Simon Barber's avatar
Simon Barber committed
532
        phdr->phy_info.info_11g.has_mode = TRUE;
533
        phdr->phy_info.info_11g.mode = PHDR_802_11G_MODE_NORMAL;
534
535
536
        break;

    case IEEE80211_CHAN_108A:
537
        phdr->phy = PHDR_802_11_PHY_11A;
Simon Barber's avatar
Simon Barber committed
538
        phdr->phy_info.info_11a.has_turbo_type = TRUE;
539
540
        /* We assume non-STURBO is dynamic turbo */
        phdr->phy_info.info_11a.turbo_type = PHDR_802_11A_TURBO_TYPE_DYNAMIC_TURBO;
541
542
543
        break;

    case IEEE80211_CHAN_108PUREG:
544
        phdr->phy = PHDR_802_11_PHY_11G;
Simon Barber's avatar
Simon Barber committed
545
        phdr->phy_info.info_11g.has_mode = TRUE;
546
        phdr->phy_info.info_11g.mode = PHDR_802_11G_MODE_SUPER_G;
547
548
        break;
    }
549
    ptvcursor_add_with_subtree(csr, hf_80211_common_chan_flags, 2, ENC_LITTLE_ENDIAN,
550
                               ett_dot11_common_channel_flags);
551
552
553
554
555
556
557
558
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_turbo, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_cck, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_ofdm, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_2ghz, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_5ghz, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_passive, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211_common_chan_flags_dynamic, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_80211_common_chan_flags_gfsk, 2, ENC_LITTLE_ENDIAN);
559
560
561
    ptvcursor_pop_subtree(csr);


Simon Barber's avatar
Simon Barber committed
562
563
    if (phdr->phy == PHDR_802_11_PHY_11_FHSS) {
        phdr->phy_info.info_11_fhss.has_hop_set = TRUE;
564
        phdr->phy_info.info_11_fhss.hop_set = tvb_get_guint8(ptvcursor_tvbuff(csr), ptvcursor_current_offset(csr));
Simon Barber's avatar
Simon Barber committed
565
    }
566
    ptvcursor_add(csr, hf_80211_common_fhss_hopset, 1, ENC_LITTLE_ENDIAN);
Simon Barber's avatar
Simon Barber committed
567
568
    if (phdr->phy == PHDR_802_11_PHY_11_FHSS) {
        phdr->phy_info.info_11_fhss.has_hop_pattern = TRUE;
569
        phdr->phy_info.info_11_fhss.hop_pattern = tvb_get_guint8(ptvcursor_tvbuff(csr), ptvcursor_current_offset(csr));
Simon Barber's avatar
Simon Barber committed
570
    }
571
    ptvcursor_add(csr, hf_80211_common_fhss_pattern, 1, ENC_LITTLE_ENDIAN);
572

573
    dbm_value = tvb_get_gint8(tvb, ptvcursor_current_offset(csr));
574
575
576
577
578
579
580
581
    if (dbm_value != -128 && dbm_value != 0) {
        /*
         * XXX - the spec says -128 is invalid, presumably meaning "use
         * -128 if you don't have the signal strength", but some captures
         * have 0 for noise, presumably meaning it's incorrectly being
         * used for "don't have it", so we check for it as well.
         */
        col_add_fstr(pinfo->cinfo, COL_RSSI, "%d dBm", dbm_value);
Simon Barber's avatar
Simon Barber committed
582
        phdr->has_signal_dbm = TRUE;
583
584
        phdr->signal_dbm = dbm_value;
    }
585
    ptvcursor_add_invalid_check(csr, hf_80211_common_dbm_antsignal, 1, 0x80); /* -128 */
586

587
    dbm_value = tvb_get_gint8(tvb, ptvcursor_current_offset(csr));
588
589
590
591
592
593
594
    if (dbm_value != -128 && dbm_value != 0) {
        /*
         * XXX - the spec says -128 is invalid, presumably meaning "use
         * -128 if you don't have the noise level", but some captures
         * have 0, presumably meaning it's incorrectly being used for
         * "don't have it", so we check for it as well.
         */
Simon Barber's avatar
Simon Barber committed
595
        phdr->has_noise_dbm = TRUE;
596
597
        phdr->noise_dbm = dbm_value;
    }
598
599
600
601
602
603
    ptvcursor_add_invalid_check(csr, hf_80211_common_dbm_antnoise, 1, 0x80);

    ptvcursor_free(csr);
}

static void
604
dissect_80211n_mac(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, int data_len, gboolean add_subtree, guint32 *n_mac_flags, guint32 *ampdu_id, struct ieee_802_11_phdr *phdr)
605
{
606
607
    proto_tree  *ftree       = tree;
    ptvcursor_t *csr;
608
    guint32      flags;
609

610
    phdr->phy = PHDR_802_11_PHY_11N;
611

612
    if (add_subtree) {
613
        ftree = proto_tree_add_subtree(tree, tvb, offset, data_len, ett_dot11n_mac, NULL, "802.11n MAC");
614
615
        add_ppi_field_header(tvb, ftree, &offset);
        data_len -= 4; /* Subtract field header length */
616
617
618
    }

    if (data_len != PPI_80211N_MAC_LEN) {
619
        proto_tree_add_expert_format(ftree, pinfo, &ei_ppi_invalid_length, tvb, offset, data_len, "Invalid length: %u", data_len);
620
        return;
621
622
    }

623
    csr = ptvcursor_new(pinfo->pool, ftree, tvb, offset);
624

625
    flags = tvb_get_letohl(tvb, ptvcursor_current_offset(csr));
626
    *n_mac_flags = flags;
627
    phdr->phy_info.info_11n.has_bandwidth = TRUE;
Simon Barber's avatar
Simon Barber committed
628
629
    phdr->phy_info.info_11n.has_short_gi = TRUE;
    phdr->phy_info.info_11n.has_greenfield = TRUE;
630
    phdr->phy_info.info_11n.bandwidth = ((flags & DOT11N_FLAG_HT40) != 0);
631
632
    phdr->phy_info.info_11n.short_gi = ((flags & DOT11N_FLAG_SHORT_GI) != 0);
    phdr->phy_info.info_11n.greenfield = ((flags & DOT11N_FLAG_GREENFIELD) != 0);
633
634
635
636
637
638
639
640
    if (DOT11N_IS_AGGREGATE(flags)) {
        phdr->has_aggregate_info = 1;
        phdr->aggregate_flags = 0;
        if (!(flags & DOT11N_FLAG_MORE_AGGREGATES))
            phdr->aggregate_flags |= PHDR_802_11_LAST_PART_OF_A_MPDU;
        if (flags & DOT11N_FLAG_AGG_CRC_ERROR)
            phdr->aggregate_flags |= PHDR_802_11_A_MPDU_DELIM_CRC_ERROR;
    }
641
    ptvcursor_add_with_subtree(csr, hf_80211n_mac_flags, 4, ENC_LITTLE_ENDIAN,
642
                               ett_dot11n_mac_flags);
643
644
645
646
647
648
649
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_greenfield, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_ht20_40, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_rx_guard_interval, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_duplicate_rx, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_aggregate, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_flags_more_aggregates, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_80211n_mac_flags_delimiter_crc_after, 4, ENC_LITTLE_ENDIAN); /* Last */
650
651
    ptvcursor_pop_subtree(csr);

652
653
654
655
    if (DOT11N_IS_AGGREGATE(flags)) {
        *ampdu_id = tvb_get_letohl(tvb, ptvcursor_current_offset(csr));
        phdr->aggregate_id = *ampdu_id;
    }
656
657
    ptvcursor_add(csr, hf_80211n_mac_ampdu_id, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_80211n_mac_num_delimiters, 1, ENC_LITTLE_ENDIAN);
658
659

    if (add_subtree) {
660
        ptvcursor_add(csr, hf_80211n_mac_reserved, 3, ENC_LITTLE_ENDIAN);
661
662
663
664
665
    }

    ptvcursor_free(csr);
}

666
static void
667
dissect_80211n_mac_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int data_len, guint32 *n_mac_flags, guint32 *ampdu_id, struct ieee_802_11_phdr *phdr)
668
{
669
670
    proto_tree  *ftree;
    proto_item  *ti;
671
    ptvcursor_t *csr;
672
673
    guint8       mcs;
    guint8       ness;
674
675
    guint16      ext_frequency;
    gchar       *chan_str;
676

677
    ftree = proto_tree_add_subtree(tree, tvb, offset, data_len, ett_dot11n_mac_phy, NULL, "802.11n MAC+PHY");
678
679
680
681
    add_ppi_field_header(tvb, ftree, &offset);
    data_len -= 4; /* Subtract field header length */

    if (data_len != PPI_80211N_MAC_PHY_LEN) {
682
        proto_tree_add_expert_format(ftree, pinfo, &ei_ppi_invalid_length, tvb, offset, data_len, "Invalid length: %u", data_len);
683
        return;
684
685
686
    }

    dissect_80211n_mac(tvb, pinfo, ftree, offset, PPI_80211N_MAC_LEN,
687
                       FALSE, n_mac_flags, ampdu_id, phdr);
688
689
    offset += PPI_80211N_MAC_PHY_OFF;

690
    csr = ptvcursor_new(pinfo->pool, ftree, tvb, offset);
691

692
693
    mcs = tvb_get_guint8(tvb, ptvcursor_current_offset(csr));
    if (mcs != 255) {
Simon Barber's avatar
Simon Barber committed
694
        phdr->phy_info.info_11n.has_mcs_index = TRUE;
695
        phdr->phy_info.info_11n.mcs_index = mcs;
696
    }
697
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_mcs, 1, 255);
698
699

    ness = tvb_get_guint8(tvb, ptvcursor_current_offset(csr));
Simon Barber's avatar
Simon Barber committed
700
    phdr->phy_info.info_11n.has_ness = TRUE;
701
    phdr->phy_info.info_11n.ness = ness;
702
    ti = ptvcursor_add(csr, hf_80211n_mac_phy_num_streams, 1, ENC_LITTLE_ENDIAN);
703
704
705
706
707
708
709
710
711
712
713
714
715
    if (tvb_get_guint8(tvb, ptvcursor_current_offset(csr) - 1) == 0)
        proto_item_append_text(ti, " (unknown)");
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_combined, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant0_ctl, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant1_ctl, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant2_ctl, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant3_ctl, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant0_ext, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant1_ext, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant2_ext, 1, 255);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_rssi_ant3_ext, 1, 255);

    ext_frequency = tvb_get_letohs(ptvcursor_tvbuff(csr), ptvcursor_current_offset(csr));
716
    chan_str = ieee80211_mhz_to_str(ext_frequency);
717
    proto_tree_add_uint_format(ptvcursor_tree(csr), hf_80211n_mac_phy_ext_chan_freq, ptvcursor_tvbuff(csr),
718
                               ptvcursor_current_offset(csr), 2, ext_frequency, "Ext. Channel frequency: %s", chan_str);
719
    g_free(chan_str);
720
721
    ptvcursor_advance(csr, 2);

722
    ptvcursor_add_with_subtree(csr, hf_80211n_mac_phy_ext_chan_flags, 2, ENC_LITTLE_ENDIAN,
723
                               ett_dot11n_mac_phy_ext_channel_flags);
724
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_turbo, 2, ENC_LITTLE_ENDIAN);
725
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_cck, 2, ENC_LITTLE_ENDIAN);
726
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_ofdm, 2, ENC_LITTLE_ENDIAN);
727
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_2ghz, 2, ENC_LITTLE_ENDIAN);
728
729
730
731
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_5ghz, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_passive, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_80211n_mac_phy_ext_chan_flags_dynamic, 2, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_80211n_mac_phy_ext_chan_flags_gfsk, 2, ENC_LITTLE_ENDIAN);
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
    ptvcursor_pop_subtree(csr);

    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant0signal, 1, 0x80); /* -128 */
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant0noise, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant1signal, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant1noise, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant2signal, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant2noise, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant3signal, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_dbm_ant3noise, 1, 0x80);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_evm0, 4, 0);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_evm1, 4, 0);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_evm2, 4, 0);
    ptvcursor_add_invalid_check(csr, hf_80211n_mac_phy_evm3, 4, 0);

    ptvcursor_free(csr);
}

750
751
static void
dissect_aggregation_extension(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, int data_len)
752
{
753
    proto_tree *ftree;
754
    ptvcursor_t *csr;
755

756
    ftree = proto_tree_add_subtree(tree, tvb, offset, data_len, ett_aggregation_extension, NULL, "Aggregation Extension");
757
758
    add_ppi_field_header(tvb, ftree, &offset);
    data_len -= 4; /* Subtract field header length */
759
760

    if (data_len != PPI_AGGREGATION_EXTENSION_LEN) {
761
        proto_tree_add_expert_format(ftree, pinfo, &ei_ppi_invalid_length, tvb, offset, data_len, "Invalid length: %u", data_len);
762
        return;
763
764
    }

765
    csr = ptvcursor_new(pinfo->pool, ftree, tvb, offset);
766

767
    ptvcursor_add(csr, hf_aggregation_extension_interface_id, 4, ENC_LITTLE_ENDIAN); /* Last */
768
769
770
    ptvcursor_free(csr);
}

771
772
static void
dissect_8023_extension(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, int data_len)
773
{
774
    proto_tree  *ftree;
775
    ptvcursor_t *csr;
776

777
    ftree = proto_tree_add_subtree(tree, tvb, offset, data_len, ett_8023_extension, NULL, "802.3 Extension");
778
779
    add_ppi_field_header(tvb, ftree, &offset);
    data_len -= 4; /* Subtract field header length */
780
781

    if (data_len != PPI_8023_EXTENSION_LEN) {
782
        proto_tree_add_expert_format(ftree, pinfo, &ei_ppi_invalid_length, tvb, offset, data_len, "Invalid length: %u", data_len);
783
        return;
784
785
    }

786
    csr = ptvcursor_new(pinfo->pool, ftree, tvb, offset);
787

788
    ptvcursor_add_with_subtree(csr, hf_8023_extension_flags, 4, ENC_LITTLE_ENDIAN, ett_8023_extension_flags);
789
    ptvcursor_add(csr, hf_8023_extension_flags_fcs_present, 4, ENC_LITTLE_ENDIAN);
790
    ptvcursor_pop_subtree(csr);
791

792
    ptvcursor_add_with_subtree(csr, hf_8023_extension_errors, 4, ENC_LITTLE_ENDIAN, ett_8023_extension_errors);
793
794
795
796
    ptvcursor_add_no_advance(csr, hf_8023_extension_errors_fcs, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_8023_extension_errors_sequence, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add_no_advance(csr, hf_8023_extension_errors_symbol, 4, ENC_LITTLE_ENDIAN);
    ptvcursor_add(csr, hf_8023_extension_errors_data, 4, ENC_LITTLE_ENDIAN);
797
    ptvcursor_pop_subtree(csr);
798

799
800
801
802
    ptvcursor_free(csr);
}


803
804
805
#define PADDING4(x) ((((x + 3) >> 2) << 2) - x)
#define ADD_BASIC_TAG(hf_tag) \
    if (tree)   \
806
        proto_tree_add_item(ppi_tree, hf_tag, tvb, offset, data_len, ENC_NA)
807

808
809
static int
dissect_ppi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
810
{
811
812
813
814
815
816
817
818
819
820
821
    proto_tree    *ppi_tree    = NULL, *ppi_flags_tree = NULL, *seg_tree = NULL, *ampdu_tree = NULL;
    proto_tree    *agg_tree    = NULL;
    proto_item    *ti          = NULL;
    tvbuff_t      *next_tvb;
    int            offset      = 0;
    guint          version, flags;
    gint           tot_len, data_len;
    guint          data_type;
    guint32        dlt;
    guint32        n_ext_flags = 0;
    guint32        ampdu_id    = 0;
822
823
    fragment_head *fd_head     = NULL;
    fragment_item *ft_fdh      = NULL;
824
825
826
827
    gint           mpdu_count  = 0;
    gchar         *mpdu_str;
    gboolean       first_mpdu  = TRUE;
    guint          last_frame  = 0;
828
    gint len_remain, /*pad_len = 0,*/ ampdu_len = 0;
829
    struct ieee_802_11_phdr phdr;
830

831
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPI");
832
    col_clear(pinfo->cinfo, COL_INFO);
833
834
835
836
837
838
839

    version = tvb_get_guint8(tvb, offset);
    flags = tvb_get_guint8(tvb, offset + 1);

    tot_len = tvb_get_letohs(tvb, offset+2);
    dlt = tvb_get_letohl(tvb, offset+4);

Bill Meier's avatar
Bill Meier committed
840
841
    col_add_fstr(pinfo->cinfo, COL_INFO, "PPI version %u, %u bytes",
                 version, tot_len);
842
843
844

    /* Dissect the packet */
    if (tree) {
845
846
847
848
        ti = proto_tree_add_protocol_format(tree, proto_ppi,
                                            tvb, 0, tot_len, "PPI version %u, %u bytes", version, tot_len);
        ppi_tree = proto_item_add_subtree(ti, ett_ppi_pph);
        proto_tree_add_item(ppi_tree, hf_ppi_head_version,
849
                            tvb, offset, 1, ENC_LITTLE_ENDIAN);
850
851

        ti = proto_tree_add_item(ppi_tree, hf_ppi_head_flags,
852
                                 tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
853
854
        ppi_flags_tree = proto_item_add_subtree(ti, ett_ppi_flags);
        proto_tree_add_item(ppi_flags_tree, hf_ppi_head_flag_alignment,
855
                            tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
856
        proto_tree_add_item(ppi_flags_tree, hf_ppi_head_flag_reserved,
857
                            tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
858

859
        proto_tree_add_item(ppi_tree, hf_ppi_head_len,
860
                                 tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
861
862
        proto_tree_add_item(ppi_tree, hf_ppi_head_dlt,
                                 tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
863
864
865
866
867
    }

    tot_len -= PPI_V0_HEADER_LEN;
    offset += 8;

868
    /* We don't have any 802.11 metadata yet. */
Martin Kaiser's avatar
Martin Kaiser committed
869
    memset(&phdr, 0, sizeof(phdr));
870
871
    phdr.fcs_len = -1;
    phdr.decrypted = FALSE;
872
    phdr.datapad = FALSE;
873
    phdr.phy = PHDR_802_11_PHY_UNKNOWN;
874

875
876
877
878
879
880
    while (tot_len > 0) {
        data_type = tvb_get_letohs(tvb, offset);
        data_len = tvb_get_letohs(tvb, offset + 2) + 4;
        tot_len -= data_len;

        switch (data_type) {
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910

        case PPI_80211_COMMON:
            dissect_80211_common(tvb, pinfo, ppi_tree, offset, data_len, &phdr);
            break;

        case PPI_80211N_MAC:
            dissect_80211n_mac(tvb, pinfo, ppi_tree, offset, data_len,
                TRUE, &n_ext_flags, &ampdu_id, &phdr);
            break;

        case PPI_80211N_MAC_PHY:
            dissect_80211n_mac_phy(tvb, pinfo, ppi_tree, offset,
                data_len, &n_ext_flags, &ampdu_id, &phdr);
            break;

        case PPI_SPECTRUM_MAP:
            ADD_BASIC_TAG(hf_spectrum_map);
            break;

        case PPI_PROCESS_INFO:
            ADD_BASIC_TAG(hf_process_info);
            break;

        case PPI_CAPTURE_INFO:
            ADD_BASIC_TAG(hf_capture_info);
            break;

        case PPI_AGGREGATION_EXTENSION:
            dissect_aggregation_extension(tvb, pinfo, ppi_tree, offset, data_len);
            break;
911

Bill Meier's avatar
Bill Meier committed
912
913
914
        case PPI_8023_EXTENSION:
            dissect_8023_extension(tvb, pinfo, ppi_tree, offset, data_len);
            break;
915

Bill Meier's avatar
Bill Meier committed
916
917
918
        case PPI_GPS_INFO:
            if (ppi_gps_handle == NULL)
            {
919
                proto_tree_add_item(ppi_tree, hf_ppi_gps, tvb, offset, data_len, ENC_NA);
Bill Meier's avatar
Bill Meier committed
920
921
922
923
            }
            else /* we found a suitable dissector */
            {
                /* skip over the ppi_fieldheader, and pass it off to the dedicated GPS dissetor */
924
                next_tvb = tvb_new_subset_length_caplen(tvb, offset + 4, data_len - 4 , -1);
Bill Meier's avatar
Bill Meier committed
925
926
927
                call_dissector(ppi_gps_handle, next_tvb, pinfo, ppi_tree);
            }
            break;
928

Bill Meier's avatar
Bill Meier committed
929
930
931
        case PPI_VECTOR_INFO:
            if (ppi_vector_handle == NULL)
            {
932
                proto_tree_add_item(ppi_tree, hf_ppi_vector, tvb, offset, data_len, ENC_NA);
Bill Meier's avatar
Bill Meier committed
933
934
935
936
            }
            else /* we found a suitable dissector */
            {
                /* skip over the ppi_fieldheader, and pass it off to the dedicated VECTOR dissetor */
937
                next_tvb = tvb_new_subset_length_caplen(tvb, offset + 4, data_len - 4 , -1);
Bill Meier's avatar
Bill Meier committed
938
939
940
                call_dissector(ppi_vector_handle, next_tvb, pinfo, ppi_tree);
            }
            break;
941

Gerald Combs's avatar
Gerald Combs committed
942
943
        case PPI_SENSOR_INFO:
            if (ppi_sensor_handle == NULL)
Bill Meier's avatar
Bill Meier committed
944
            {
945
                proto_tree_add_item(ppi_tree, hf_ppi_harris, tvb, offset, data_len, ENC_NA);
Bill Meier's avatar
Bill Meier committed
946
947
948
            }
            else /* we found a suitable dissector */
            {
Gerald Combs's avatar
Gerald Combs committed
949
                /* skip over the ppi_fieldheader, and pass it off to the dedicated SENSOR dissetor */
950
                next_tvb = tvb_new_subset_length_caplen(tvb, offset + 4, data_len - 4 , -1);
Gerald Combs's avatar
Gerald Combs committed
951
                call_dissector(ppi_sensor_handle, next_tvb, pinfo, ppi_tree);
Bill Meier's avatar
Bill Meier committed
952
953
            }
            break;
954

Bill Meier's avatar
Bill Meier committed
955
956
957
        case PPI_ANTENNA_INFO:
            if (ppi_antenna_handle == NULL)
            {
958
                proto_tree_add_item(ppi_tree, hf_ppi_antenna, tvb, offset, data_len, ENC_NA);
Bill Meier's avatar
Bill Meier committed
959
960
961
962
            }
            else /* we found a suitable dissector */
            {
                /* skip over the ppi_fieldheader, and pass it off to the dedicated ANTENNA dissetor */
963
                next_tvb = tvb_new_subset_length_caplen(tvb, offset + 4, data_len - 4 , -1);
Bill Meier's avatar
Bill Meier committed
964
965
966
                call_dissector(ppi_antenna_handle, next_tvb, pinfo, ppi_tree);
            }
            break;
967

968
969
970
971
972
973
974
975
        case FNET_PRIVATE:
            if (ppi_fnet_handle == NULL)
            {
                proto_tree_add_item(ppi_tree, hf_ppi_fnet, tvb, offset, data_len, ENC_NA);
            }
            else /* we found a suitable dissector */
            {
                /* skip over the ppi_fieldheader, and pass it off to the dedicated FNET dissetor */
976
                next_tvb = tvb_new_subset_length_caplen(tvb, offset + 4, data_len - 4 , -1);
977
978
979
                call_dissector(ppi_fnet_handle, next_tvb, pinfo, ppi_tree);
            }
            break;
Bill Meier's avatar
Bill Meier committed
980
981

        default:
982
            proto_tree_add_item(ppi_tree, hf_ppi_reserved, tvb, offset, data_len, ENC_NA);
983
984
985
        }

        offset += data_len;
986
987
988
        if (IS_PPI_FLAG_ALIGN(flags)){
            offset += PADDING4(offset);
        }
989
990
    }

991
992
993
994
995
996
997
998
999
1000
    /*
     * The Channel-Flags field is described as "Radiotap-formatted
     * channel flags".  The comment in the radiotap.org page about
     * the suggested xchannel field says:
     *
     *  As used, this field conflates channel properties (which
     *  need not be stored per packet but are more or less fixed)
     *  with packet properties (like the modulation).
     *
     * The radiotap channel field, in practice, seems to be used,