packet_ppi: C++98/STL parsing library

PPI is a standard for link layer packet encapsulation, proposed as generic extensible container to store both captured in-band data and out-of-band data. Originally it was developed to provide 802.11n radio information, but can be used for other purposes as well.

Sample capture: https://wiki.wireshark.org/uploads/27707187aeb30df68e70c8fb9d614981/http.cap

KS implementation details

License: CC0-1.0

This page hosts a formal specification of packet_ppi using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    packet_ppi_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.header() // => get header

C++98/STL source code to parse packet_ppi

packet_ppi.h

#ifndef PACKET_PPI_H_
#define PACKET_PPI_H_

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include "ethernet_frame.h"
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class ethernet_frame_t;

/**
 * PPI is a standard for link layer packet encapsulation, proposed as
 * generic extensible container to store both captured in-band data and
 * out-of-band data. Originally it was developed to provide 802.11n
 * radio information, but can be used for other purposes as well.
 * 
 * Sample capture:
 * <https://wiki.wireshark.org/uploads/27707187aeb30df68e70c8fb9d614981/http.cap>
 * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 3
 */

class packet_ppi_t : public kaitai::kstruct {

public:
    class packet_ppi_fields_t;
    class radio_802_11n_mac_ext_body_t;
    class mac_flags_t;
    class packet_ppi_header_t;
    class radio_802_11_common_body_t;
    class packet_ppi_field_t;
    class radio_802_11n_mac_phy_ext_body_t;

    enum pfh_type_t {
        PFH_TYPE_RADIO_802_11_COMMON = 2,
        PFH_TYPE_RADIO_802_11N_MAC_EXT = 3,
        PFH_TYPE_RADIO_802_11N_MAC_PHY_EXT = 4,
        PFH_TYPE_SPECTRUM_MAP = 5,
        PFH_TYPE_PROCESS_INFO = 6,
        PFH_TYPE_CAPTURE_INFO = 7
    };

    enum linktype_t {
        LINKTYPE_NULL_LINKTYPE = 0,
        LINKTYPE_ETHERNET = 1,
        LINKTYPE_AX25 = 3,
        LINKTYPE_IEEE802_5 = 6,
        LINKTYPE_ARCNET_BSD = 7,
        LINKTYPE_SLIP = 8,
        LINKTYPE_PPP = 9,
        LINKTYPE_FDDI = 10,
        LINKTYPE_PPP_HDLC = 50,
        LINKTYPE_PPP_ETHER = 51,
        LINKTYPE_ATM_RFC1483 = 100,
        LINKTYPE_RAW = 101,
        LINKTYPE_C_HDLC = 104,
        LINKTYPE_IEEE802_11 = 105,
        LINKTYPE_FRELAY = 107,
        LINKTYPE_LOOP = 108,
        LINKTYPE_LINUX_SLL = 113,
        LINKTYPE_LTALK = 114,
        LINKTYPE_PFLOG = 117,
        LINKTYPE_IEEE802_11_PRISM = 119,
        LINKTYPE_IP_OVER_FC = 122,
        LINKTYPE_SUNATM = 123,
        LINKTYPE_IEEE802_11_RADIOTAP = 127,
        LINKTYPE_ARCNET_LINUX = 129,
        LINKTYPE_APPLE_IP_OVER_IEEE1394 = 138,
        LINKTYPE_MTP2_WITH_PHDR = 139,
        LINKTYPE_MTP2 = 140,
        LINKTYPE_MTP3 = 141,
        LINKTYPE_SCCP = 142,
        LINKTYPE_DOCSIS = 143,
        LINKTYPE_LINUX_IRDA = 144,
        LINKTYPE_USER0 = 147,
        LINKTYPE_USER1 = 148,
        LINKTYPE_USER2 = 149,
        LINKTYPE_USER3 = 150,
        LINKTYPE_USER4 = 151,
        LINKTYPE_USER5 = 152,
        LINKTYPE_USER6 = 153,
        LINKTYPE_USER7 = 154,
        LINKTYPE_USER8 = 155,
        LINKTYPE_USER9 = 156,
        LINKTYPE_USER10 = 157,
        LINKTYPE_USER11 = 158,
        LINKTYPE_USER12 = 159,
        LINKTYPE_USER13 = 160,
        LINKTYPE_USER14 = 161,
        LINKTYPE_USER15 = 162,
        LINKTYPE_IEEE802_11_AVS = 163,
        LINKTYPE_BACNET_MS_TP = 165,
        LINKTYPE_PPP_PPPD = 166,
        LINKTYPE_GPRS_LLC = 169,
        LINKTYPE_GPF_T = 170,
        LINKTYPE_GPF_F = 171,
        LINKTYPE_LINUX_LAPD = 177,
        LINKTYPE_BLUETOOTH_HCI_H4 = 187,
        LINKTYPE_USB_LINUX = 189,
        LINKTYPE_PPI = 192,
        LINKTYPE_IEEE802_15_4 = 195,
        LINKTYPE_SITA = 196,
        LINKTYPE_ERF = 197,
        LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR = 201,
        LINKTYPE_AX25_KISS = 202,
        LINKTYPE_LAPD = 203,
        LINKTYPE_PPP_WITH_DIR = 204,
        LINKTYPE_C_HDLC_WITH_DIR = 205,
        LINKTYPE_FRELAY_WITH_DIR = 206,
        LINKTYPE_IPMB_LINUX = 209,
        LINKTYPE_IEEE802_15_4_NONASK_PHY = 215,
        LINKTYPE_USB_LINUX_MMAPPED = 220,
        LINKTYPE_FC_2 = 224,
        LINKTYPE_FC_2_WITH_FRAME_DELIMS = 225,
        LINKTYPE_IPNET = 226,
        LINKTYPE_CAN_SOCKETCAN = 227,
        LINKTYPE_IPV4 = 228,
        LINKTYPE_IPV6 = 229,
        LINKTYPE_IEEE802_15_4_NOFCS = 230,
        LINKTYPE_DBUS = 231,
        LINKTYPE_DVB_CI = 235,
        LINKTYPE_MUX27010 = 236,
        LINKTYPE_STANAG_5066_D_PDU = 237,
        LINKTYPE_NFLOG = 239,
        LINKTYPE_NETANALYZER = 240,
        LINKTYPE_NETANALYZER_TRANSPARENT = 241,
        LINKTYPE_IPOIB = 242,
        LINKTYPE_MPEG_2_TS = 243,
        LINKTYPE_NG40 = 244,
        LINKTYPE_NFC_LLCP = 245,
        LINKTYPE_INFINIBAND = 247,
        LINKTYPE_SCTP = 248,
        LINKTYPE_USBPCAP = 249,
        LINKTYPE_RTAC_SERIAL = 250,
        LINKTYPE_BLUETOOTH_LE_LL = 251,
        LINKTYPE_NETLINK = 253,
        LINKTYPE_BLUETOOTH_LINUX_MONITOR = 254,
        LINKTYPE_BLUETOOTH_BREDR_BB = 255,
        LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR = 256,
        LINKTYPE_PROFIBUS_DL = 257,
        LINKTYPE_PKTAP = 258,
        LINKTYPE_EPON = 259,
        LINKTYPE_IPMI_HPM_2 = 260,
        LINKTYPE_ZWAVE_R1_R2 = 261,
        LINKTYPE_ZWAVE_R3 = 262,
        LINKTYPE_WATTSTOPPER_DLM = 263,
        LINKTYPE_ISO_14443 = 264
    };

    packet_ppi_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, packet_ppi_t* p__root = 0);

private:
    void _read();
    void _clean_up();

public:
    ~packet_ppi_t();

    class packet_ppi_fields_t : public kaitai::kstruct {

    public:

        packet_ppi_fields_t(kaitai::kstream* p__io, packet_ppi_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~packet_ppi_fields_t();

    private:
        std::vector<packet_ppi_field_t*>* m_entries;
        packet_ppi_t* m__root;
        packet_ppi_t* m__parent;

    public:
        std::vector<packet_ppi_field_t*>* entries() const { return m_entries; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 4.1.3
     */

    class radio_802_11n_mac_ext_body_t : public kaitai::kstruct {

    public:

        radio_802_11n_mac_ext_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~radio_802_11n_mac_ext_body_t();

    private:
        mac_flags_t* m_flags;
        uint32_t m_a_mpdu_id;
        uint8_t m_num_delimiters;
        std::string m_reserved;
        packet_ppi_t* m__root;
        packet_ppi_t::packet_ppi_field_t* m__parent;

    public:
        mac_flags_t* flags() const { return m_flags; }
        uint32_t a_mpdu_id() const { return m_a_mpdu_id; }
        uint8_t num_delimiters() const { return m_num_delimiters; }
        std::string reserved() const { return m_reserved; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t::packet_ppi_field_t* _parent() const { return m__parent; }
    };

    class mac_flags_t : public kaitai::kstruct {

    public:

        mac_flags_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~mac_flags_t();

    private:
        bool m_unused1;
        bool m_aggregate_delimiter;
        bool m_more_aggregates;
        bool m_aggregate;
        bool m_dup_rx;
        bool m_rx_short_guard;
        bool m_is_ht_40;
        bool m_greenfield;
        std::string m_unused2;
        packet_ppi_t* m__root;
        kaitai::kstruct* m__parent;

    public:
        bool unused1() const { return m_unused1; }

        /**
         * Aggregate delimiter CRC error after this frame
         */
        bool aggregate_delimiter() const { return m_aggregate_delimiter; }

        /**
         * More aggregates
         */
        bool more_aggregates() const { return m_more_aggregates; }

        /**
         * Aggregate
         */
        bool aggregate() const { return m_aggregate; }

        /**
         * Duplicate RX
         */
        bool dup_rx() const { return m_dup_rx; }

        /**
         * RX short guard interval (SGI)
         */
        bool rx_short_guard() const { return m_rx_short_guard; }

        /**
         * true = HT40, false = HT20
         */
        bool is_ht_40() const { return m_is_ht_40; }

        /**
         * Greenfield
         */
        bool greenfield() const { return m_greenfield; }
        std::string unused2() const { return m_unused2; }
        packet_ppi_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };

    /**
     * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 3.1
     */

    class packet_ppi_header_t : public kaitai::kstruct {

    public:

        packet_ppi_header_t(kaitai::kstream* p__io, packet_ppi_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~packet_ppi_header_t();

    private:
        uint8_t m_pph_version;
        uint8_t m_pph_flags;
        uint16_t m_pph_len;
        linktype_t m_pph_dlt;
        packet_ppi_t* m__root;
        packet_ppi_t* m__parent;

    public:
        uint8_t pph_version() const { return m_pph_version; }
        uint8_t pph_flags() const { return m_pph_flags; }
        uint16_t pph_len() const { return m_pph_len; }
        linktype_t pph_dlt() const { return m_pph_dlt; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 4.1.2
     */

    class radio_802_11_common_body_t : public kaitai::kstruct {

    public:

        radio_802_11_common_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~radio_802_11_common_body_t();

    private:
        uint64_t m_tsf_timer;
        uint16_t m_flags;
        uint16_t m_rate;
        uint16_t m_channel_freq;
        uint16_t m_channel_flags;
        uint8_t m_fhss_hopset;
        uint8_t m_fhss_pattern;
        int8_t m_dbm_antsignal;
        int8_t m_dbm_antnoise;
        packet_ppi_t* m__root;
        packet_ppi_t::packet_ppi_field_t* m__parent;

    public:
        uint64_t tsf_timer() const { return m_tsf_timer; }
        uint16_t flags() const { return m_flags; }
        uint16_t rate() const { return m_rate; }
        uint16_t channel_freq() const { return m_channel_freq; }
        uint16_t channel_flags() const { return m_channel_flags; }
        uint8_t fhss_hopset() const { return m_fhss_hopset; }
        uint8_t fhss_pattern() const { return m_fhss_pattern; }
        int8_t dbm_antsignal() const { return m_dbm_antsignal; }
        int8_t dbm_antnoise() const { return m_dbm_antnoise; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t::packet_ppi_field_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 3.1
     */

    class packet_ppi_field_t : public kaitai::kstruct {

    public:

        packet_ppi_field_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_fields_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~packet_ppi_field_t();

    private:
        pfh_type_t m_pfh_type;
        uint16_t m_pfh_datalen;
        kaitai::kstruct* m_body;
        bool n_body;

    public:
        bool _is_null_body() { body(); return n_body; };

    private:
        packet_ppi_t* m__root;
        packet_ppi_t::packet_ppi_fields_t* m__parent;
        std::string m__raw_body;
        kaitai::kstream* m__io__raw_body;

    public:
        pfh_type_t pfh_type() const { return m_pfh_type; }
        uint16_t pfh_datalen() const { return m_pfh_datalen; }
        kaitai::kstruct* body() const { return m_body; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t::packet_ppi_fields_t* _parent() const { return m__parent; }
        std::string _raw_body() const { return m__raw_body; }
        kaitai::kstream* _io__raw_body() const { return m__io__raw_body; }
    };

    /**
     * \sa https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf PPI header format spec, section 4.1.4
     */

    class radio_802_11n_mac_phy_ext_body_t : public kaitai::kstruct {

    public:
        class channel_flags_t;
        class signal_noise_t;

        radio_802_11n_mac_phy_ext_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent = 0, packet_ppi_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~radio_802_11n_mac_phy_ext_body_t();

        class channel_flags_t : public kaitai::kstruct {

        public:

            channel_flags_t(kaitai::kstream* p__io, packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* p__parent = 0, packet_ppi_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~channel_flags_t();

        private:
            bool m_spectrum_2ghz;
            bool m_ofdm;
            bool m_cck;
            bool m_turbo;
            uint64_t m_unused;
            bool m_gfsk;
            bool m_dyn_cck_ofdm;
            bool m_only_passive_scan;
            bool m_spectrum_5ghz;
            packet_ppi_t* m__root;
            packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* m__parent;

        public:

            /**
             * 2 GHz spectrum
             */
            bool spectrum_2ghz() const { return m_spectrum_2ghz; }

            /**
             * OFDM (Orthogonal Frequency-Division Multiplexing)
             */
            bool ofdm() const { return m_ofdm; }

            /**
             * CCK (Complementary Code Keying)
             */
            bool cck() const { return m_cck; }
            bool turbo() const { return m_turbo; }
            uint64_t unused() const { return m_unused; }

            /**
             * Gaussian Frequency Shift Keying
             */
            bool gfsk() const { return m_gfsk; }

            /**
             * Dynamic CCK-OFDM
             */
            bool dyn_cck_ofdm() const { return m_dyn_cck_ofdm; }

            /**
             * Only passive scan allowed
             */
            bool only_passive_scan() const { return m_only_passive_scan; }

            /**
             * 5 GHz spectrum
             */
            bool spectrum_5ghz() const { return m_spectrum_5ghz; }
            packet_ppi_t* _root() const { return m__root; }
            packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* _parent() const { return m__parent; }
        };

        /**
         * RF signal + noise pair at a single antenna
         */

        class signal_noise_t : public kaitai::kstruct {

        public:

            signal_noise_t(kaitai::kstream* p__io, packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* p__parent = 0, packet_ppi_t* p__root = 0);

        private:
            void _read();
            void _clean_up();

        public:
            ~signal_noise_t();

        private:
            int8_t m_signal;
            int8_t m_noise;
            packet_ppi_t* m__root;
            packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* m__parent;

        public:

            /**
             * RF signal, dBm
             */
            int8_t signal() const { return m_signal; }

            /**
             * RF noise, dBm
             */
            int8_t noise() const { return m_noise; }
            packet_ppi_t* _root() const { return m__root; }
            packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* _parent() const { return m__parent; }
        };

    private:
        mac_flags_t* m_flags;
        uint32_t m_a_mpdu_id;
        uint8_t m_num_delimiters;
        uint8_t m_mcs;
        uint8_t m_num_streams;
        uint8_t m_rssi_combined;
        std::vector<uint8_t>* m_rssi_ant_ctl;
        std::vector<uint8_t>* m_rssi_ant_ext;
        uint16_t m_ext_channel_freq;
        channel_flags_t* m_ext_channel_flags;
        std::vector<signal_noise_t*>* m_rf_signal_noise;
        std::vector<uint32_t>* m_evm;
        packet_ppi_t* m__root;
        packet_ppi_t::packet_ppi_field_t* m__parent;

    public:
        mac_flags_t* flags() const { return m_flags; }
        uint32_t a_mpdu_id() const { return m_a_mpdu_id; }
        uint8_t num_delimiters() const { return m_num_delimiters; }

        /**
         * Modulation Coding Scheme (MCS)
         */
        uint8_t mcs() const { return m_mcs; }

        /**
         * Number of spatial streams (0 = unknown)
         */
        uint8_t num_streams() const { return m_num_streams; }

        /**
         * RSSI (Received Signal Strength Indication), combined from all active antennas / channels
         */
        uint8_t rssi_combined() const { return m_rssi_combined; }

        /**
         * RSSI (Received Signal Strength Indication) for antennas 0-3, control channel
         */
        std::vector<uint8_t>* rssi_ant_ctl() const { return m_rssi_ant_ctl; }

        /**
         * RSSI (Received Signal Strength Indication) for antennas 0-3, extension channel
         */
        std::vector<uint8_t>* rssi_ant_ext() const { return m_rssi_ant_ext; }

        /**
         * Extension channel frequency (MHz)
         */
        uint16_t ext_channel_freq() const { return m_ext_channel_freq; }

        /**
         * Extension channel flags
         */
        channel_flags_t* ext_channel_flags() const { return m_ext_channel_flags; }

        /**
         * Signal + noise values for antennas 0-3
         */
        std::vector<signal_noise_t*>* rf_signal_noise() const { return m_rf_signal_noise; }

        /**
         * EVM (Error Vector Magnitude) for chains 0-3
         */
        std::vector<uint32_t>* evm() const { return m_evm; }
        packet_ppi_t* _root() const { return m__root; }
        packet_ppi_t::packet_ppi_field_t* _parent() const { return m__parent; }
    };

private:
    packet_ppi_header_t* m_header;
    packet_ppi_fields_t* m_fields;
    kaitai::kstruct* m_body;
    bool n_body;

public:
    bool _is_null_body() { body(); return n_body; };

private:
    packet_ppi_t* m__root;
    kaitai::kstruct* m__parent;
    std::string m__raw_fields;
    kaitai::kstream* m__io__raw_fields;
    std::string m__raw_body;
    kaitai::kstream* m__io__raw_body;

public:
    packet_ppi_header_t* header() const { return m_header; }
    packet_ppi_fields_t* fields() const { return m_fields; }
    kaitai::kstruct* body() const { return m_body; }
    packet_ppi_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::string _raw_fields() const { return m__raw_fields; }
    kaitai::kstream* _io__raw_fields() const { return m__io__raw_fields; }
    std::string _raw_body() const { return m__raw_body; }
    kaitai::kstream* _io__raw_body() const { return m__io__raw_body; }
};

#endif  // PACKET_PPI_H_

packet_ppi.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "packet_ppi.h"

packet_ppi_t::packet_ppi_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_header = 0;
    m_fields = 0;
    m__io__raw_fields = 0;
    m__io__raw_body = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::_read() {
    m_header = new packet_ppi_header_t(m__io, this, m__root);
    m__raw_fields = m__io->read_bytes((header()->pph_len() - 8));
    m__io__raw_fields = new kaitai::kstream(m__raw_fields);
    m_fields = new packet_ppi_fields_t(m__io__raw_fields, this, m__root);
    n_body = true;
    switch (header()->pph_dlt()) {
    case packet_ppi_t::LINKTYPE_PPI: {
        n_body = false;
        m__raw_body = m__io->read_bytes_full();
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new packet_ppi_t(m__io__raw_body);
        break;
    }
    case packet_ppi_t::LINKTYPE_ETHERNET: {
        n_body = false;
        m__raw_body = m__io->read_bytes_full();
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new ethernet_frame_t(m__io__raw_body);
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes_full();
        break;
    }
    }
}

packet_ppi_t::~packet_ppi_t() {
    _clean_up();
}

void packet_ppi_t::_clean_up() {
    if (m_header) {
        delete m_header; m_header = 0;
    }
    if (m__io__raw_fields) {
        delete m__io__raw_fields; m__io__raw_fields = 0;
    }
    if (m_fields) {
        delete m_fields; m_fields = 0;
    }
    if (!n_body) {
        if (m__io__raw_body) {
            delete m__io__raw_body; m__io__raw_body = 0;
        }
        if (m_body) {
            delete m_body; m_body = 0;
        }
    }
}

packet_ppi_t::packet_ppi_fields_t::packet_ppi_fields_t(kaitai::kstream* p__io, packet_ppi_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::packet_ppi_fields_t::_read() {
    m_entries = new std::vector<packet_ppi_field_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(new packet_ppi_field_t(m__io, this, m__root));
            i++;
        }
    }
}

packet_ppi_t::packet_ppi_fields_t::~packet_ppi_fields_t() {
    _clean_up();
}

void packet_ppi_t::packet_ppi_fields_t::_clean_up() {
    if (m_entries) {
        for (std::vector<packet_ppi_field_t*>::iterator it = m_entries->begin(); it != m_entries->end(); ++it) {
            delete *it;
        }
        delete m_entries; m_entries = 0;
    }
}

packet_ppi_t::radio_802_11n_mac_ext_body_t::radio_802_11n_mac_ext_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::radio_802_11n_mac_ext_body_t::_read() {
    m_flags = new mac_flags_t(m__io, this, m__root);
    m_a_mpdu_id = m__io->read_u4le();
    m_num_delimiters = m__io->read_u1();
    m_reserved = m__io->read_bytes(3);
}

packet_ppi_t::radio_802_11n_mac_ext_body_t::~radio_802_11n_mac_ext_body_t() {
    _clean_up();
}

void packet_ppi_t::radio_802_11n_mac_ext_body_t::_clean_up() {
    if (m_flags) {
        delete m_flags; m_flags = 0;
    }
}

packet_ppi_t::mac_flags_t::mac_flags_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::mac_flags_t::_read() {
    m_unused1 = m__io->read_bits_int_be(1);
    m_aggregate_delimiter = m__io->read_bits_int_be(1);
    m_more_aggregates = m__io->read_bits_int_be(1);
    m_aggregate = m__io->read_bits_int_be(1);
    m_dup_rx = m__io->read_bits_int_be(1);
    m_rx_short_guard = m__io->read_bits_int_be(1);
    m_is_ht_40 = m__io->read_bits_int_be(1);
    m_greenfield = m__io->read_bits_int_be(1);
    m__io->align_to_byte();
    m_unused2 = m__io->read_bytes(3);
}

packet_ppi_t::mac_flags_t::~mac_flags_t() {
    _clean_up();
}

void packet_ppi_t::mac_flags_t::_clean_up() {
}

packet_ppi_t::packet_ppi_header_t::packet_ppi_header_t(kaitai::kstream* p__io, packet_ppi_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::packet_ppi_header_t::_read() {
    m_pph_version = m__io->read_u1();
    m_pph_flags = m__io->read_u1();
    m_pph_len = m__io->read_u2le();
    m_pph_dlt = static_cast<packet_ppi_t::linktype_t>(m__io->read_u4le());
}

packet_ppi_t::packet_ppi_header_t::~packet_ppi_header_t() {
    _clean_up();
}

void packet_ppi_t::packet_ppi_header_t::_clean_up() {
}

packet_ppi_t::radio_802_11_common_body_t::radio_802_11_common_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::radio_802_11_common_body_t::_read() {
    m_tsf_timer = m__io->read_u8le();
    m_flags = m__io->read_u2le();
    m_rate = m__io->read_u2le();
    m_channel_freq = m__io->read_u2le();
    m_channel_flags = m__io->read_u2le();
    m_fhss_hopset = m__io->read_u1();
    m_fhss_pattern = m__io->read_u1();
    m_dbm_antsignal = m__io->read_s1();
    m_dbm_antnoise = m__io->read_s1();
}

packet_ppi_t::radio_802_11_common_body_t::~radio_802_11_common_body_t() {
    _clean_up();
}

void packet_ppi_t::radio_802_11_common_body_t::_clean_up() {
}

packet_ppi_t::packet_ppi_field_t::packet_ppi_field_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_fields_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_body = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::packet_ppi_field_t::_read() {
    m_pfh_type = static_cast<packet_ppi_t::pfh_type_t>(m__io->read_u2le());
    m_pfh_datalen = m__io->read_u2le();
    n_body = true;
    switch (pfh_type()) {
    case packet_ppi_t::PFH_TYPE_RADIO_802_11_COMMON: {
        n_body = false;
        m__raw_body = m__io->read_bytes(pfh_datalen());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new radio_802_11_common_body_t(m__io__raw_body, this, m__root);
        break;
    }
    case packet_ppi_t::PFH_TYPE_RADIO_802_11N_MAC_EXT: {
        n_body = false;
        m__raw_body = m__io->read_bytes(pfh_datalen());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new radio_802_11n_mac_ext_body_t(m__io__raw_body, this, m__root);
        break;
    }
    case packet_ppi_t::PFH_TYPE_RADIO_802_11N_MAC_PHY_EXT: {
        n_body = false;
        m__raw_body = m__io->read_bytes(pfh_datalen());
        m__io__raw_body = new kaitai::kstream(m__raw_body);
        m_body = new radio_802_11n_mac_phy_ext_body_t(m__io__raw_body, this, m__root);
        break;
    }
    default: {
        m__raw_body = m__io->read_bytes(pfh_datalen());
        break;
    }
    }
}

packet_ppi_t::packet_ppi_field_t::~packet_ppi_field_t() {
    _clean_up();
}

void packet_ppi_t::packet_ppi_field_t::_clean_up() {
    if (!n_body) {
        if (m__io__raw_body) {
            delete m__io__raw_body; m__io__raw_body = 0;
        }
        if (m_body) {
            delete m_body; m_body = 0;
        }
    }
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::radio_802_11n_mac_phy_ext_body_t(kaitai::kstream* p__io, packet_ppi_t::packet_ppi_field_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = 0;
    m_rssi_ant_ctl = 0;
    m_rssi_ant_ext = 0;
    m_ext_channel_flags = 0;
    m_rf_signal_noise = 0;
    m_evm = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::_read() {
    m_flags = new mac_flags_t(m__io, this, m__root);
    m_a_mpdu_id = m__io->read_u4le();
    m_num_delimiters = m__io->read_u1();
    m_mcs = m__io->read_u1();
    m_num_streams = m__io->read_u1();
    m_rssi_combined = m__io->read_u1();
    m_rssi_ant_ctl = new std::vector<uint8_t>();
    const int l_rssi_ant_ctl = 4;
    for (int i = 0; i < l_rssi_ant_ctl; i++) {
        m_rssi_ant_ctl->push_back(m__io->read_u1());
    }
    m_rssi_ant_ext = new std::vector<uint8_t>();
    const int l_rssi_ant_ext = 4;
    for (int i = 0; i < l_rssi_ant_ext; i++) {
        m_rssi_ant_ext->push_back(m__io->read_u1());
    }
    m_ext_channel_freq = m__io->read_u2le();
    m_ext_channel_flags = new channel_flags_t(m__io, this, m__root);
    m_rf_signal_noise = new std::vector<signal_noise_t*>();
    const int l_rf_signal_noise = 4;
    for (int i = 0; i < l_rf_signal_noise; i++) {
        m_rf_signal_noise->push_back(new signal_noise_t(m__io, this, m__root));
    }
    m_evm = new std::vector<uint32_t>();
    const int l_evm = 4;
    for (int i = 0; i < l_evm; i++) {
        m_evm->push_back(m__io->read_u4le());
    }
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::~radio_802_11n_mac_phy_ext_body_t() {
    _clean_up();
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::_clean_up() {
    if (m_flags) {
        delete m_flags; m_flags = 0;
    }
    if (m_rssi_ant_ctl) {
        delete m_rssi_ant_ctl; m_rssi_ant_ctl = 0;
    }
    if (m_rssi_ant_ext) {
        delete m_rssi_ant_ext; m_rssi_ant_ext = 0;
    }
    if (m_ext_channel_flags) {
        delete m_ext_channel_flags; m_ext_channel_flags = 0;
    }
    if (m_rf_signal_noise) {
        for (std::vector<signal_noise_t*>::iterator it = m_rf_signal_noise->begin(); it != m_rf_signal_noise->end(); ++it) {
            delete *it;
        }
        delete m_rf_signal_noise; m_rf_signal_noise = 0;
    }
    if (m_evm) {
        delete m_evm; m_evm = 0;
    }
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::channel_flags_t::channel_flags_t(kaitai::kstream* p__io, packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::channel_flags_t::_read() {
    m_spectrum_2ghz = m__io->read_bits_int_be(1);
    m_ofdm = m__io->read_bits_int_be(1);
    m_cck = m__io->read_bits_int_be(1);
    m_turbo = m__io->read_bits_int_be(1);
    m_unused = m__io->read_bits_int_be(8);
    m_gfsk = m__io->read_bits_int_be(1);
    m_dyn_cck_ofdm = m__io->read_bits_int_be(1);
    m_only_passive_scan = m__io->read_bits_int_be(1);
    m_spectrum_5ghz = m__io->read_bits_int_be(1);
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::channel_flags_t::~channel_flags_t() {
    _clean_up();
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::channel_flags_t::_clean_up() {
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::signal_noise_t::signal_noise_t(kaitai::kstream* p__io, packet_ppi_t::radio_802_11n_mac_phy_ext_body_t* p__parent, packet_ppi_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::signal_noise_t::_read() {
    m_signal = m__io->read_s1();
    m_noise = m__io->read_s1();
}

packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::signal_noise_t::~signal_noise_t() {
    _clean_up();
}

void packet_ppi_t::radio_802_11n_mac_phy_ext_body_t::signal_noise_t::_clean_up() {
}