packet_ppi: Java 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/SampleCaptures?action=AttachFile&do=get&target=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 Java generated by Kaitai Struct depends on the Java runtime library. You have to install it before you can parse data.

The Java runtime library is published in the Maven Central Repository. Refer to the artifact page for instructions how to add it into your project with the build tool that you use.

Code

Parse a local file and get structure in memory:

PacketPpi data = PacketPpi.fromFile("path/to/local/file.packet_ppi");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
PacketPpi data = new PacketPpi(new ByteBufferKaitaiStream(someArray));

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

data.header() // => get header

Java source code to parse packet_ppi

PacketPpi.java

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

import io.kaitai.struct.ByteBufferKaitaiStream;
import io.kaitai.struct.KaitaiStruct;
import io.kaitai.struct.KaitaiStream;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;


/**
 * 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/SampleCaptures?action=AttachFile&do=get&target=Http.cap
 * @see <a href="https://web.archive.org/web/20090206112419/https://www.cacetech.com/documents/PPI_Header_format_1.0.1.pdf">PPI header format spec, section 3</a>
 */
public class PacketPpi extends KaitaiStruct {
    public static PacketPpi fromFile(String fileName) throws IOException {
        return new PacketPpi(new ByteBufferKaitaiStream(fileName));
    }

    public enum PfhType {
        RADIO_802_11_COMMON(2),
        RADIO_802_11N_MAC_EXT(3),
        RADIO_802_11N_MAC_PHY_EXT(4),
        SPECTRUM_MAP(5),
        PROCESS_INFO(6),
        CAPTURE_INFO(7);

        private final long id;
        PfhType(long id) { this.id = id; }
        public long id() { return id; }
        private static final Map<Long, PfhType> byId = new HashMap<Long, PfhType>(6);
        static {
            for (PfhType e : PfhType.values())
                byId.put(e.id(), e);
        }
        public static PfhType byId(long id) { return byId.get(id); }
    }

    public enum Linktype {
        NULL_LINKTYPE(0),
        ETHERNET(1),
        AX25(3),
        IEEE802_5(6),
        ARCNET_BSD(7),
        SLIP(8),
        PPP(9),
        FDDI(10),
        PPP_HDLC(50),
        PPP_ETHER(51),
        ATM_RFC1483(100),
        RAW(101),
        C_HDLC(104),
        IEEE802_11(105),
        FRELAY(107),
        LOOP(108),
        LINUX_SLL(113),
        LTALK(114),
        PFLOG(117),
        IEEE802_11_PRISM(119),
        IP_OVER_FC(122),
        SUNATM(123),
        IEEE802_11_RADIOTAP(127),
        ARCNET_LINUX(129),
        APPLE_IP_OVER_IEEE1394(138),
        MTP2_WITH_PHDR(139),
        MTP2(140),
        MTP3(141),
        SCCP(142),
        DOCSIS(143),
        LINUX_IRDA(144),
        USER0(147),
        USER1(148),
        USER2(149),
        USER3(150),
        USER4(151),
        USER5(152),
        USER6(153),
        USER7(154),
        USER8(155),
        USER9(156),
        USER10(157),
        USER11(158),
        USER12(159),
        USER13(160),
        USER14(161),
        USER15(162),
        IEEE802_11_AVS(163),
        BACNET_MS_TP(165),
        PPP_PPPD(166),
        GPRS_LLC(169),
        GPF_T(170),
        GPF_F(171),
        LINUX_LAPD(177),
        BLUETOOTH_HCI_H4(187),
        USB_LINUX(189),
        PPI(192),
        IEEE802_15_4(195),
        SITA(196),
        ERF(197),
        BLUETOOTH_HCI_H4_WITH_PHDR(201),
        AX25_KISS(202),
        LAPD(203),
        PPP_WITH_DIR(204),
        C_HDLC_WITH_DIR(205),
        FRELAY_WITH_DIR(206),
        IPMB_LINUX(209),
        IEEE802_15_4_NONASK_PHY(215),
        USB_LINUX_MMAPPED(220),
        FC_2(224),
        FC_2_WITH_FRAME_DELIMS(225),
        IPNET(226),
        CAN_SOCKETCAN(227),
        IPV4(228),
        IPV6(229),
        IEEE802_15_4_NOFCS(230),
        DBUS(231),
        DVB_CI(235),
        MUX27010(236),
        STANAG_5066_D_PDU(237),
        NFLOG(239),
        NETANALYZER(240),
        NETANALYZER_TRANSPARENT(241),
        IPOIB(242),
        MPEG_2_TS(243),
        NG40(244),
        NFC_LLCP(245),
        INFINIBAND(247),
        SCTP(248),
        USBPCAP(249),
        RTAC_SERIAL(250),
        BLUETOOTH_LE_LL(251),
        NETLINK(253),
        BLUETOOTH_LINUX_MONITOR(254),
        BLUETOOTH_BREDR_BB(255),
        BLUETOOTH_LE_LL_WITH_PHDR(256),
        PROFIBUS_DL(257),
        PKTAP(258),
        EPON(259),
        IPMI_HPM_2(260),
        ZWAVE_R1_R2(261),
        ZWAVE_R3(262),
        WATTSTOPPER_DLM(263),
        ISO_14443(264);

        private final long id;
        Linktype(long id) { this.id = id; }
        public long id() { return id; }
        private static final Map<Long, Linktype> byId = new HashMap<Long, Linktype>(104);
        static {
            for (Linktype e : Linktype.values())
                byId.put(e.id(), e);
        }
        public static Linktype byId(long id) { return byId.get(id); }
    }

    public PacketPpi(KaitaiStream _io) {
        this(_io, null, null);
    }

    public PacketPpi(KaitaiStream _io, KaitaiStruct _parent) {
        this(_io, _parent, null);
    }

    public PacketPpi(KaitaiStream _io, KaitaiStruct _parent, PacketPpi _root) {
        super(_io);
        this._parent = _parent;
        this._root = _root == null ? this : _root;
        _read();
    }
    private void _read() {
        this.header = new PacketPpiHeader(this._io, this, _root);
        this._raw_fields = this._io.readBytes((header().pphLen() - 8));
        KaitaiStream _io__raw_fields = new ByteBufferKaitaiStream(_raw_fields);
        this.fields = new PacketPpiFields(_io__raw_fields, this, _root);
        {
            Linktype on = header().pphDlt();
            if (on != null) {
                switch (header().pphDlt()) {
                case PPI: {
                    this._raw_body = this._io.readBytesFull();
                    KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                    this.body = new PacketPpi(_io__raw_body);
                    break;
                }
                case ETHERNET: {
                    this._raw_body = this._io.readBytesFull();
                    KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                    this.body = new EthernetFrame(_io__raw_body);
                    break;
                }
                default: {
                    this.body = this._io.readBytesFull();
                    break;
                }
                }
            } else {
                this.body = this._io.readBytesFull();
            }
        }
    }
    public static class PacketPpiFields extends KaitaiStruct {
        public static PacketPpiFields fromFile(String fileName) throws IOException {
            return new PacketPpiFields(new ByteBufferKaitaiStream(fileName));
        }

        public PacketPpiFields(KaitaiStream _io) {
            this(_io, null, null);
        }

        public PacketPpiFields(KaitaiStream _io, PacketPpi _parent) {
            this(_io, _parent, null);
        }

        public PacketPpiFields(KaitaiStream _io, PacketPpi _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.entries = new ArrayList<PacketPpiField>();
            {
                int i = 0;
                while (!this._io.isEof()) {
                    this.entries.add(new PacketPpiField(this._io, this, _root));
                    i++;
                }
            }
        }
        private ArrayList<PacketPpiField> entries;
        private PacketPpi _root;
        private PacketPpi _parent;
        public ArrayList<PacketPpiField> entries() { return entries; }
        public PacketPpi _root() { return _root; }
        public PacketPpi _parent() { return _parent; }
    }

    /**
     * @see <a href="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</a>
     */
    public static class Radio80211nMacExtBody extends KaitaiStruct {
        public static Radio80211nMacExtBody fromFile(String fileName) throws IOException {
            return new Radio80211nMacExtBody(new ByteBufferKaitaiStream(fileName));
        }

        public Radio80211nMacExtBody(KaitaiStream _io) {
            this(_io, null, null);
        }

        public Radio80211nMacExtBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent) {
            this(_io, _parent, null);
        }

        public Radio80211nMacExtBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.flags = new MacFlags(this._io, this, _root);
            this.aMpduId = this._io.readU4le();
            this.numDelimiters = this._io.readU1();
            this.reserved = this._io.readBytes(3);
        }
        private MacFlags flags;
        private long aMpduId;
        private int numDelimiters;
        private byte[] reserved;
        private PacketPpi _root;
        private PacketPpi.PacketPpiField _parent;
        public MacFlags flags() { return flags; }
        public long aMpduId() { return aMpduId; }
        public int numDelimiters() { return numDelimiters; }
        public byte[] reserved() { return reserved; }
        public PacketPpi _root() { return _root; }
        public PacketPpi.PacketPpiField _parent() { return _parent; }
    }
    public static class MacFlags extends KaitaiStruct {
        public static MacFlags fromFile(String fileName) throws IOException {
            return new MacFlags(new ByteBufferKaitaiStream(fileName));
        }

        public MacFlags(KaitaiStream _io) {
            this(_io, null, null);
        }

        public MacFlags(KaitaiStream _io, KaitaiStruct _parent) {
            this(_io, _parent, null);
        }

        public MacFlags(KaitaiStream _io, KaitaiStruct _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.unused1 = this._io.readBitsIntBe(1) != 0;
            this.aggregateDelimiter = this._io.readBitsIntBe(1) != 0;
            this.moreAggregates = this._io.readBitsIntBe(1) != 0;
            this.aggregate = this._io.readBitsIntBe(1) != 0;
            this.dupRx = this._io.readBitsIntBe(1) != 0;
            this.rxShortGuard = this._io.readBitsIntBe(1) != 0;
            this.isHt40 = this._io.readBitsIntBe(1) != 0;
            this.greenfield = this._io.readBitsIntBe(1) != 0;
            this._io.alignToByte();
            this.unused2 = this._io.readBytes(3);
        }
        private boolean unused1;
        private boolean aggregateDelimiter;
        private boolean moreAggregates;
        private boolean aggregate;
        private boolean dupRx;
        private boolean rxShortGuard;
        private boolean isHt40;
        private boolean greenfield;
        private byte[] unused2;
        private PacketPpi _root;
        private KaitaiStruct _parent;
        public boolean unused1() { return unused1; }

        /**
         * Aggregate delimiter CRC error after this frame
         */
        public boolean aggregateDelimiter() { return aggregateDelimiter; }

        /**
         * More aggregates
         */
        public boolean moreAggregates() { return moreAggregates; }

        /**
         * Aggregate
         */
        public boolean aggregate() { return aggregate; }

        /**
         * Duplicate RX
         */
        public boolean dupRx() { return dupRx; }

        /**
         * RX short guard interval (SGI)
         */
        public boolean rxShortGuard() { return rxShortGuard; }

        /**
         * true = HT40, false = HT20
         */
        public boolean isHt40() { return isHt40; }

        /**
         * Greenfield
         */
        public boolean greenfield() { return greenfield; }
        public byte[] unused2() { return unused2; }
        public PacketPpi _root() { return _root; }
        public KaitaiStruct _parent() { return _parent; }
    }

    /**
     * @see <a href="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</a>
     */
    public static class PacketPpiHeader extends KaitaiStruct {
        public static PacketPpiHeader fromFile(String fileName) throws IOException {
            return new PacketPpiHeader(new ByteBufferKaitaiStream(fileName));
        }

        public PacketPpiHeader(KaitaiStream _io) {
            this(_io, null, null);
        }

        public PacketPpiHeader(KaitaiStream _io, PacketPpi _parent) {
            this(_io, _parent, null);
        }

        public PacketPpiHeader(KaitaiStream _io, PacketPpi _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.pphVersion = this._io.readU1();
            this.pphFlags = this._io.readU1();
            this.pphLen = this._io.readU2le();
            this.pphDlt = PacketPpi.Linktype.byId(this._io.readU4le());
        }
        private int pphVersion;
        private int pphFlags;
        private int pphLen;
        private Linktype pphDlt;
        private PacketPpi _root;
        private PacketPpi _parent;
        public int pphVersion() { return pphVersion; }
        public int pphFlags() { return pphFlags; }
        public int pphLen() { return pphLen; }
        public Linktype pphDlt() { return pphDlt; }
        public PacketPpi _root() { return _root; }
        public PacketPpi _parent() { return _parent; }
    }

    /**
     * @see <a href="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</a>
     */
    public static class Radio80211CommonBody extends KaitaiStruct {
        public static Radio80211CommonBody fromFile(String fileName) throws IOException {
            return new Radio80211CommonBody(new ByteBufferKaitaiStream(fileName));
        }

        public Radio80211CommonBody(KaitaiStream _io) {
            this(_io, null, null);
        }

        public Radio80211CommonBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent) {
            this(_io, _parent, null);
        }

        public Radio80211CommonBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.tsfTimer = this._io.readU8le();
            this.flags = this._io.readU2le();
            this.rate = this._io.readU2le();
            this.channelFreq = this._io.readU2le();
            this.channelFlags = this._io.readU2le();
            this.fhssHopset = this._io.readU1();
            this.fhssPattern = this._io.readU1();
            this.dbmAntsignal = this._io.readS1();
            this.dbmAntnoise = this._io.readS1();
        }
        private long tsfTimer;
        private int flags;
        private int rate;
        private int channelFreq;
        private int channelFlags;
        private int fhssHopset;
        private int fhssPattern;
        private byte dbmAntsignal;
        private byte dbmAntnoise;
        private PacketPpi _root;
        private PacketPpi.PacketPpiField _parent;
        public long tsfTimer() { return tsfTimer; }
        public int flags() { return flags; }
        public int rate() { return rate; }
        public int channelFreq() { return channelFreq; }
        public int channelFlags() { return channelFlags; }
        public int fhssHopset() { return fhssHopset; }
        public int fhssPattern() { return fhssPattern; }
        public byte dbmAntsignal() { return dbmAntsignal; }
        public byte dbmAntnoise() { return dbmAntnoise; }
        public PacketPpi _root() { return _root; }
        public PacketPpi.PacketPpiField _parent() { return _parent; }
    }

    /**
     * @see <a href="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</a>
     */
    public static class PacketPpiField extends KaitaiStruct {
        public static PacketPpiField fromFile(String fileName) throws IOException {
            return new PacketPpiField(new ByteBufferKaitaiStream(fileName));
        }

        public PacketPpiField(KaitaiStream _io) {
            this(_io, null, null);
        }

        public PacketPpiField(KaitaiStream _io, PacketPpi.PacketPpiFields _parent) {
            this(_io, _parent, null);
        }

        public PacketPpiField(KaitaiStream _io, PacketPpi.PacketPpiFields _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.pfhType = PacketPpi.PfhType.byId(this._io.readU2le());
            this.pfhDatalen = this._io.readU2le();
            {
                PfhType on = pfhType();
                if (on != null) {
                    switch (pfhType()) {
                    case RADIO_802_11_COMMON: {
                        this._raw_body = this._io.readBytes(pfhDatalen());
                        KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                        this.body = new Radio80211CommonBody(_io__raw_body, this, _root);
                        break;
                    }
                    case RADIO_802_11N_MAC_EXT: {
                        this._raw_body = this._io.readBytes(pfhDatalen());
                        KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                        this.body = new Radio80211nMacExtBody(_io__raw_body, this, _root);
                        break;
                    }
                    case RADIO_802_11N_MAC_PHY_EXT: {
                        this._raw_body = this._io.readBytes(pfhDatalen());
                        KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                        this.body = new Radio80211nMacPhyExtBody(_io__raw_body, this, _root);
                        break;
                    }
                    default: {
                        this.body = this._io.readBytes(pfhDatalen());
                        break;
                    }
                    }
                } else {
                    this.body = this._io.readBytes(pfhDatalen());
                }
            }
        }
        private PfhType pfhType;
        private int pfhDatalen;
        private Object body;
        private PacketPpi _root;
        private PacketPpi.PacketPpiFields _parent;
        private byte[] _raw_body;
        public PfhType pfhType() { return pfhType; }
        public int pfhDatalen() { return pfhDatalen; }
        public Object body() { return body; }
        public PacketPpi _root() { return _root; }
        public PacketPpi.PacketPpiFields _parent() { return _parent; }
        public byte[] _raw_body() { return _raw_body; }
    }

    /**
     * @see <a href="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</a>
     */
    public static class Radio80211nMacPhyExtBody extends KaitaiStruct {
        public static Radio80211nMacPhyExtBody fromFile(String fileName) throws IOException {
            return new Radio80211nMacPhyExtBody(new ByteBufferKaitaiStream(fileName));
        }

        public Radio80211nMacPhyExtBody(KaitaiStream _io) {
            this(_io, null, null);
        }

        public Radio80211nMacPhyExtBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent) {
            this(_io, _parent, null);
        }

        public Radio80211nMacPhyExtBody(KaitaiStream _io, PacketPpi.PacketPpiField _parent, PacketPpi _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.flags = new MacFlags(this._io, this, _root);
            this.aMpduId = this._io.readU4le();
            this.numDelimiters = this._io.readU1();
            this.mcs = this._io.readU1();
            this.numStreams = this._io.readU1();
            this.rssiCombined = this._io.readU1();
            rssiAntCtl = new ArrayList<Integer>(((Number) (4)).intValue());
            for (int i = 0; i < 4; i++) {
                this.rssiAntCtl.add(this._io.readU1());
            }
            rssiAntExt = new ArrayList<Integer>(((Number) (4)).intValue());
            for (int i = 0; i < 4; i++) {
                this.rssiAntExt.add(this._io.readU1());
            }
            this.extChannelFreq = this._io.readU2le();
            this.extChannelFlags = new ChannelFlags(this._io, this, _root);
            rfSignalNoise = new ArrayList<SignalNoise>(((Number) (4)).intValue());
            for (int i = 0; i < 4; i++) {
                this.rfSignalNoise.add(new SignalNoise(this._io, this, _root));
            }
            evm = new ArrayList<Long>(((Number) (4)).intValue());
            for (int i = 0; i < 4; i++) {
                this.evm.add(this._io.readU4le());
            }
        }
        public static class ChannelFlags extends KaitaiStruct {
            public static ChannelFlags fromFile(String fileName) throws IOException {
                return new ChannelFlags(new ByteBufferKaitaiStream(fileName));
            }

            public ChannelFlags(KaitaiStream _io) {
                this(_io, null, null);
            }

            public ChannelFlags(KaitaiStream _io, PacketPpi.Radio80211nMacPhyExtBody _parent) {
                this(_io, _parent, null);
            }

            public ChannelFlags(KaitaiStream _io, PacketPpi.Radio80211nMacPhyExtBody _parent, PacketPpi _root) {
                super(_io);
                this._parent = _parent;
                this._root = _root;
                _read();
            }
            private void _read() {
                this.spectrum2ghz = this._io.readBitsIntBe(1) != 0;
                this.ofdm = this._io.readBitsIntBe(1) != 0;
                this.cck = this._io.readBitsIntBe(1) != 0;
                this.turbo = this._io.readBitsIntBe(1) != 0;
                this.unused = this._io.readBitsIntBe(8);
                this.gfsk = this._io.readBitsIntBe(1) != 0;
                this.dynCckOfdm = this._io.readBitsIntBe(1) != 0;
                this.onlyPassiveScan = this._io.readBitsIntBe(1) != 0;
                this.spectrum5ghz = this._io.readBitsIntBe(1) != 0;
            }
            private boolean spectrum2ghz;
            private boolean ofdm;
            private boolean cck;
            private boolean turbo;
            private long unused;
            private boolean gfsk;
            private boolean dynCckOfdm;
            private boolean onlyPassiveScan;
            private boolean spectrum5ghz;
            private PacketPpi _root;
            private PacketPpi.Radio80211nMacPhyExtBody _parent;

            /**
             * 2 GHz spectrum
             */
            public boolean spectrum2ghz() { return spectrum2ghz; }

            /**
             * OFDM (Orthogonal Frequency-Division Multiplexing)
             */
            public boolean ofdm() { return ofdm; }

            /**
             * CCK (Complementary Code Keying)
             */
            public boolean cck() { return cck; }
            public boolean turbo() { return turbo; }
            public long unused() { return unused; }

            /**
             * Gaussian Frequency Shift Keying
             */
            public boolean gfsk() { return gfsk; }

            /**
             * Dynamic CCK-OFDM
             */
            public boolean dynCckOfdm() { return dynCckOfdm; }

            /**
             * Only passive scan allowed
             */
            public boolean onlyPassiveScan() { return onlyPassiveScan; }

            /**
             * 5 GHz spectrum
             */
            public boolean spectrum5ghz() { return spectrum5ghz; }
            public PacketPpi _root() { return _root; }
            public PacketPpi.Radio80211nMacPhyExtBody _parent() { return _parent; }
        }

        /**
         * RF signal + noise pair at a single antenna
         */
        public static class SignalNoise extends KaitaiStruct {
            public static SignalNoise fromFile(String fileName) throws IOException {
                return new SignalNoise(new ByteBufferKaitaiStream(fileName));
            }

            public SignalNoise(KaitaiStream _io) {
                this(_io, null, null);
            }

            public SignalNoise(KaitaiStream _io, PacketPpi.Radio80211nMacPhyExtBody _parent) {
                this(_io, _parent, null);
            }

            public SignalNoise(KaitaiStream _io, PacketPpi.Radio80211nMacPhyExtBody _parent, PacketPpi _root) {
                super(_io);
                this._parent = _parent;
                this._root = _root;
                _read();
            }
            private void _read() {
                this.signal = this._io.readS1();
                this.noise = this._io.readS1();
            }
            private byte signal;
            private byte noise;
            private PacketPpi _root;
            private PacketPpi.Radio80211nMacPhyExtBody _parent;

            /**
             * RF signal, dBm
             */
            public byte signal() { return signal; }

            /**
             * RF noise, dBm
             */
            public byte noise() { return noise; }
            public PacketPpi _root() { return _root; }
            public PacketPpi.Radio80211nMacPhyExtBody _parent() { return _parent; }
        }
        private MacFlags flags;
        private long aMpduId;
        private int numDelimiters;
        private int mcs;
        private int numStreams;
        private int rssiCombined;
        private ArrayList<Integer> rssiAntCtl;
        private ArrayList<Integer> rssiAntExt;
        private int extChannelFreq;
        private ChannelFlags extChannelFlags;
        private ArrayList<SignalNoise> rfSignalNoise;
        private ArrayList<Long> evm;
        private PacketPpi _root;
        private PacketPpi.PacketPpiField _parent;
        public MacFlags flags() { return flags; }
        public long aMpduId() { return aMpduId; }
        public int numDelimiters() { return numDelimiters; }

        /**
         * Modulation Coding Scheme (MCS)
         */
        public int mcs() { return mcs; }

        /**
         * Number of spatial streams (0 = unknown)
         */
        public int numStreams() { return numStreams; }

        /**
         * RSSI (Received Signal Strength Indication), combined from all active antennas / channels
         */
        public int rssiCombined() { return rssiCombined; }

        /**
         * RSSI (Received Signal Strength Indication) for antennas 0-3, control channel
         */
        public ArrayList<Integer> rssiAntCtl() { return rssiAntCtl; }

        /**
         * RSSI (Received Signal Strength Indication) for antennas 0-3, extension channel
         */
        public ArrayList<Integer> rssiAntExt() { return rssiAntExt; }

        /**
         * Extension channel frequency (MHz)
         */
        public int extChannelFreq() { return extChannelFreq; }

        /**
         * Extension channel flags
         */
        public ChannelFlags extChannelFlags() { return extChannelFlags; }

        /**
         * Signal + noise values for antennas 0-3
         */
        public ArrayList<SignalNoise> rfSignalNoise() { return rfSignalNoise; }

        /**
         * EVM (Error Vector Magnitude) for chains 0-3
         */
        public ArrayList<Long> evm() { return evm; }
        public PacketPpi _root() { return _root; }
        public PacketPpi.PacketPpiField _parent() { return _parent; }
    }
    private PacketPpiHeader header;
    private PacketPpiFields fields;
    private Object body;
    private PacketPpi _root;
    private KaitaiStruct _parent;
    private byte[] _raw_fields;
    private byte[] _raw_body;
    public PacketPpiHeader header() { return header; }
    public PacketPpiFields fields() { return fields; }
    public Object body() { return body; }
    public PacketPpi _root() { return _root; }
    public KaitaiStruct _parent() { return _parent; }
    public byte[] _raw_fields() { return _raw_fields; }
    public byte[] _raw_body() { return _raw_body; }
}