packet_ppi: Nim 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.

Nim source code to parse packet_ppi

packet_ppi.nim

import kaitai_struct_nim_runtime
import options
import /network/ethernet_frame

import "ethernet_frame"
type
  PacketPpi* = ref object of KaitaiStruct
    `header`*: PacketPpi_PacketPpiHeader
    `fields`*: PacketPpi_PacketPpiFields
    `body`*: KaitaiStruct
    `parent`*: KaitaiStruct
    `rawFields`*: seq[byte]
    `rawBody`*: seq[byte]
  PacketPpi_PfhType* = enum
    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
  PacketPpi_Linktype* = enum
    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
  PacketPpi_PacketPpiFields* = ref object of KaitaiStruct
    `entries`*: seq[PacketPpi_PacketPpiField]
    `parent`*: PacketPpi
  PacketPpi_Radio80211nMacExtBody* = ref object of KaitaiStruct
    `flags`*: PacketPpi_MacFlags
    `aMpduId`*: uint32
    `numDelimiters`*: uint8
    `reserved`*: seq[byte]
    `parent`*: PacketPpi_PacketPpiField
  PacketPpi_MacFlags* = ref object of KaitaiStruct
    `unused1`*: bool
    `aggregateDelimiter`*: bool
    `moreAggregates`*: bool
    `aggregate`*: bool
    `dupRx`*: bool
    `rxShortGuard`*: bool
    `isHt40`*: bool
    `greenfield`*: bool
    `unused2`*: seq[byte]
    `parent`*: KaitaiStruct
  PacketPpi_PacketPpiHeader* = ref object of KaitaiStruct
    `pphVersion`*: uint8
    `pphFlags`*: uint8
    `pphLen`*: uint16
    `pphDlt`*: PacketPpi_Linktype
    `parent`*: PacketPpi
  PacketPpi_Radio80211CommonBody* = ref object of KaitaiStruct
    `tsfTimer`*: uint64
    `flags`*: uint16
    `rate`*: uint16
    `channelFreq`*: uint16
    `channelFlags`*: uint16
    `fhssHopset`*: uint8
    `fhssPattern`*: uint8
    `dbmAntsignal`*: int8
    `dbmAntnoise`*: int8
    `parent`*: PacketPpi_PacketPpiField
  PacketPpi_PacketPpiField* = ref object of KaitaiStruct
    `pfhType`*: PacketPpi_PfhType
    `pfhDatalen`*: uint16
    `body`*: KaitaiStruct
    `parent`*: PacketPpi_PacketPpiFields
    `rawBody`*: seq[byte]
  PacketPpi_Radio80211nMacPhyExtBody* = ref object of KaitaiStruct
    `flags`*: PacketPpi_MacFlags
    `aMpduId`*: uint32
    `numDelimiters`*: uint8
    `mcs`*: uint8
    `numStreams`*: uint8
    `rssiCombined`*: uint8
    `rssiAntCtl`*: seq[uint8]
    `rssiAntExt`*: seq[uint8]
    `extChannelFreq`*: uint16
    `extChannelFlags`*: PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags
    `rfSignalNoise`*: seq[PacketPpi_Radio80211nMacPhyExtBody_SignalNoise]
    `evm`*: seq[uint32]
    `parent`*: PacketPpi_PacketPpiField
  PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags* = ref object of KaitaiStruct
    `spectrum2ghz`*: bool
    `ofdm`*: bool
    `cck`*: bool
    `turbo`*: bool
    `unused`*: uint64
    `gfsk`*: bool
    `dynCckOfdm`*: bool
    `onlyPassiveScan`*: bool
    `spectrum5ghz`*: bool
    `parent`*: PacketPpi_Radio80211nMacPhyExtBody
  PacketPpi_Radio80211nMacPhyExtBody_SignalNoise* = ref object of KaitaiStruct
    `signal`*: int8
    `noise`*: int8
    `parent`*: PacketPpi_Radio80211nMacPhyExtBody

proc read*(_: typedesc[PacketPpi], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): PacketPpi
proc read*(_: typedesc[PacketPpi_PacketPpiFields], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi): PacketPpi_PacketPpiFields
proc read*(_: typedesc[PacketPpi_Radio80211nMacExtBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211nMacExtBody
proc read*(_: typedesc[PacketPpi_MacFlags], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): PacketPpi_MacFlags
proc read*(_: typedesc[PacketPpi_PacketPpiHeader], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi): PacketPpi_PacketPpiHeader
proc read*(_: typedesc[PacketPpi_Radio80211CommonBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211CommonBody
proc read*(_: typedesc[PacketPpi_PacketPpiField], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiFields): PacketPpi_PacketPpiField
proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211nMacPhyExtBody
proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_Radio80211nMacPhyExtBody): PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags
proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_SignalNoise], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_Radio80211nMacPhyExtBody): PacketPpi_Radio80211nMacPhyExtBody_SignalNoise



##[
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>

@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>
]##
proc read*(_: typedesc[PacketPpi], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): PacketPpi =
  template this: untyped = result
  this = new(PacketPpi)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let headerExpr = PacketPpi_PacketPpiHeader.read(this.io, this.root, this)
  this.header = headerExpr
  let rawFieldsExpr = this.io.readBytes(int((this.header.pphLen - 8)))
  this.rawFields = rawFieldsExpr
  let rawFieldsIo = newKaitaiStream(rawFieldsExpr)
  let fieldsExpr = PacketPpi_PacketPpiFields.read(rawFieldsIo, this.root, this)
  this.fields = fieldsExpr
  block:
    let on = this.header.pphDlt
    if on == packet_ppi.ppi:
      let rawBodyExpr = this.io.readBytesFull()
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = PacketPpi.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    elif on == packet_ppi.ethernet:
      let rawBodyExpr = this.io.readBytesFull()
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = EthernetFrame.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    else:
      let bodyExpr = this.io.readBytesFull()
      this.body = bodyExpr

proc fromFile*(_: typedesc[PacketPpi], filename: string): PacketPpi =
  PacketPpi.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[PacketPpi_PacketPpiFields], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi): PacketPpi_PacketPpiFields =
  template this: untyped = result
  this = new(PacketPpi_PacketPpiFields)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  block:
    var i: int
    while not this.io.isEof:
      let it = PacketPpi_PacketPpiField.read(this.io, this.root, this)
      this.entries.add(it)
      inc i

proc fromFile*(_: typedesc[PacketPpi_PacketPpiFields], filename: string): PacketPpi_PacketPpiFields =
  PacketPpi_PacketPpiFields.read(newKaitaiFileStream(filename), nil, nil)


##[
@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>
]##
proc read*(_: typedesc[PacketPpi_Radio80211nMacExtBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211nMacExtBody =
  template this: untyped = result
  this = new(PacketPpi_Radio80211nMacExtBody)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let flagsExpr = PacketPpi_MacFlags.read(this.io, this.root, this)
  this.flags = flagsExpr
  let aMpduIdExpr = this.io.readU4le()
  this.aMpduId = aMpduIdExpr
  let numDelimitersExpr = this.io.readU1()
  this.numDelimiters = numDelimitersExpr
  let reservedExpr = this.io.readBytes(int(3))
  this.reserved = reservedExpr

proc fromFile*(_: typedesc[PacketPpi_Radio80211nMacExtBody], filename: string): PacketPpi_Radio80211nMacExtBody =
  PacketPpi_Radio80211nMacExtBody.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[PacketPpi_MacFlags], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): PacketPpi_MacFlags =
  template this: untyped = result
  this = new(PacketPpi_MacFlags)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let unused1Expr = this.io.readBitsIntBe(1) != 0
  this.unused1 = unused1Expr

  ##[
  Aggregate delimiter CRC error after this frame
  ]##
  let aggregateDelimiterExpr = this.io.readBitsIntBe(1) != 0
  this.aggregateDelimiter = aggregateDelimiterExpr

  ##[
  More aggregates
  ]##
  let moreAggregatesExpr = this.io.readBitsIntBe(1) != 0
  this.moreAggregates = moreAggregatesExpr

  ##[
  Aggregate
  ]##
  let aggregateExpr = this.io.readBitsIntBe(1) != 0
  this.aggregate = aggregateExpr

  ##[
  Duplicate RX
  ]##
  let dupRxExpr = this.io.readBitsIntBe(1) != 0
  this.dupRx = dupRxExpr

  ##[
  RX short guard interval (SGI)
  ]##
  let rxShortGuardExpr = this.io.readBitsIntBe(1) != 0
  this.rxShortGuard = rxShortGuardExpr

  ##[
  true = HT40, false = HT20
  ]##
  let isHt40Expr = this.io.readBitsIntBe(1) != 0
  this.isHt40 = isHt40Expr

  ##[
  Greenfield
  ]##
  let greenfieldExpr = this.io.readBitsIntBe(1) != 0
  this.greenfield = greenfieldExpr
  alignToByte(this.io)
  let unused2Expr = this.io.readBytes(int(3))
  this.unused2 = unused2Expr

proc fromFile*(_: typedesc[PacketPpi_MacFlags], filename: string): PacketPpi_MacFlags =
  PacketPpi_MacFlags.read(newKaitaiFileStream(filename), nil, nil)


##[
@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>
]##
proc read*(_: typedesc[PacketPpi_PacketPpiHeader], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi): PacketPpi_PacketPpiHeader =
  template this: untyped = result
  this = new(PacketPpi_PacketPpiHeader)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let pphVersionExpr = this.io.readU1()
  this.pphVersion = pphVersionExpr
  let pphFlagsExpr = this.io.readU1()
  this.pphFlags = pphFlagsExpr
  let pphLenExpr = this.io.readU2le()
  this.pphLen = pphLenExpr
  let pphDltExpr = PacketPpi_Linktype(this.io.readU4le())
  this.pphDlt = pphDltExpr

proc fromFile*(_: typedesc[PacketPpi_PacketPpiHeader], filename: string): PacketPpi_PacketPpiHeader =
  PacketPpi_PacketPpiHeader.read(newKaitaiFileStream(filename), nil, nil)


##[
@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>
]##
proc read*(_: typedesc[PacketPpi_Radio80211CommonBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211CommonBody =
  template this: untyped = result
  this = new(PacketPpi_Radio80211CommonBody)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let tsfTimerExpr = this.io.readU8le()
  this.tsfTimer = tsfTimerExpr
  let flagsExpr = this.io.readU2le()
  this.flags = flagsExpr
  let rateExpr = this.io.readU2le()
  this.rate = rateExpr
  let channelFreqExpr = this.io.readU2le()
  this.channelFreq = channelFreqExpr
  let channelFlagsExpr = this.io.readU2le()
  this.channelFlags = channelFlagsExpr
  let fhssHopsetExpr = this.io.readU1()
  this.fhssHopset = fhssHopsetExpr
  let fhssPatternExpr = this.io.readU1()
  this.fhssPattern = fhssPatternExpr
  let dbmAntsignalExpr = this.io.readS1()
  this.dbmAntsignal = dbmAntsignalExpr
  let dbmAntnoiseExpr = this.io.readS1()
  this.dbmAntnoise = dbmAntnoiseExpr

proc fromFile*(_: typedesc[PacketPpi_Radio80211CommonBody], filename: string): PacketPpi_Radio80211CommonBody =
  PacketPpi_Radio80211CommonBody.read(newKaitaiFileStream(filename), nil, nil)


##[
@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>
]##
proc read*(_: typedesc[PacketPpi_PacketPpiField], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiFields): PacketPpi_PacketPpiField =
  template this: untyped = result
  this = new(PacketPpi_PacketPpiField)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let pfhTypeExpr = PacketPpi_PfhType(this.io.readU2le())
  this.pfhType = pfhTypeExpr
  let pfhDatalenExpr = this.io.readU2le()
  this.pfhDatalen = pfhDatalenExpr
  block:
    let on = this.pfhType
    if on == packet_ppi.radio_802_11_common:
      let rawBodyExpr = this.io.readBytes(int(this.pfhDatalen))
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = PacketPpi_Radio80211CommonBody.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    elif on == packet_ppi.radio_802_11n_mac_ext:
      let rawBodyExpr = this.io.readBytes(int(this.pfhDatalen))
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = PacketPpi_Radio80211nMacExtBody.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    elif on == packet_ppi.radio_802_11n_mac_phy_ext:
      let rawBodyExpr = this.io.readBytes(int(this.pfhDatalen))
      this.rawBody = rawBodyExpr
      let rawBodyIo = newKaitaiStream(rawBodyExpr)
      let bodyExpr = PacketPpi_Radio80211nMacPhyExtBody.read(rawBodyIo, this.root, this)
      this.body = bodyExpr
    else:
      let bodyExpr = this.io.readBytes(int(this.pfhDatalen))
      this.body = bodyExpr

proc fromFile*(_: typedesc[PacketPpi_PacketPpiField], filename: string): PacketPpi_PacketPpiField =
  PacketPpi_PacketPpiField.read(newKaitaiFileStream(filename), nil, nil)


##[
@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>
]##
proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_PacketPpiField): PacketPpi_Radio80211nMacPhyExtBody =
  template this: untyped = result
  this = new(PacketPpi_Radio80211nMacPhyExtBody)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent

  let flagsExpr = PacketPpi_MacFlags.read(this.io, this.root, this)
  this.flags = flagsExpr
  let aMpduIdExpr = this.io.readU4le()
  this.aMpduId = aMpduIdExpr
  let numDelimitersExpr = this.io.readU1()
  this.numDelimiters = numDelimitersExpr

  ##[
  Modulation Coding Scheme (MCS)
  ]##
  let mcsExpr = this.io.readU1()
  this.mcs = mcsExpr

  ##[
  Number of spatial streams (0 = unknown)
  ]##
  let numStreamsExpr = this.io.readU1()
  this.numStreams = numStreamsExpr

  ##[
  RSSI (Received Signal Strength Indication), combined from all active antennas / channels
  ]##
  let rssiCombinedExpr = this.io.readU1()
  this.rssiCombined = rssiCombinedExpr

  ##[
  RSSI (Received Signal Strength Indication) for antennas 0-3, control channel
  ]##
  for i in 0 ..< int(4):
    let it = this.io.readU1()
    this.rssiAntCtl.add(it)

  ##[
  RSSI (Received Signal Strength Indication) for antennas 0-3, extension channel
  ]##
  for i in 0 ..< int(4):
    let it = this.io.readU1()
    this.rssiAntExt.add(it)

  ##[
  Extension channel frequency (MHz)
  ]##
  let extChannelFreqExpr = this.io.readU2le()
  this.extChannelFreq = extChannelFreqExpr

  ##[
  Extension channel flags
  ]##
  let extChannelFlagsExpr = PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags.read(this.io, this.root, this)
  this.extChannelFlags = extChannelFlagsExpr

  ##[
  Signal + noise values for antennas 0-3
  ]##
  for i in 0 ..< int(4):
    let it = PacketPpi_Radio80211nMacPhyExtBody_SignalNoise.read(this.io, this.root, this)
    this.rfSignalNoise.add(it)

  ##[
  EVM (Error Vector Magnitude) for chains 0-3
  ]##
  for i in 0 ..< int(4):
    let it = this.io.readU4le()
    this.evm.add(it)

proc fromFile*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody], filename: string): PacketPpi_Radio80211nMacPhyExtBody =
  PacketPpi_Radio80211nMacPhyExtBody.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_Radio80211nMacPhyExtBody): PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags =
  template this: untyped = result
  this = new(PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent


  ##[
  2 GHz spectrum
  ]##
  let spectrum2ghzExpr = this.io.readBitsIntBe(1) != 0
  this.spectrum2ghz = spectrum2ghzExpr

  ##[
  OFDM (Orthogonal Frequency-Division Multiplexing)
  ]##
  let ofdmExpr = this.io.readBitsIntBe(1) != 0
  this.ofdm = ofdmExpr

  ##[
  CCK (Complementary Code Keying)
  ]##
  let cckExpr = this.io.readBitsIntBe(1) != 0
  this.cck = cckExpr
  let turboExpr = this.io.readBitsIntBe(1) != 0
  this.turbo = turboExpr
  let unusedExpr = this.io.readBitsIntBe(8)
  this.unused = unusedExpr

  ##[
  Gaussian Frequency Shift Keying
  ]##
  let gfskExpr = this.io.readBitsIntBe(1) != 0
  this.gfsk = gfskExpr

  ##[
  Dynamic CCK-OFDM
  ]##
  let dynCckOfdmExpr = this.io.readBitsIntBe(1) != 0
  this.dynCckOfdm = dynCckOfdmExpr

  ##[
  Only passive scan allowed
  ]##
  let onlyPassiveScanExpr = this.io.readBitsIntBe(1) != 0
  this.onlyPassiveScan = onlyPassiveScanExpr

  ##[
  5 GHz spectrum
  ]##
  let spectrum5ghzExpr = this.io.readBitsIntBe(1) != 0
  this.spectrum5ghz = spectrum5ghzExpr

proc fromFile*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags], filename: string): PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags =
  PacketPpi_Radio80211nMacPhyExtBody_ChannelFlags.read(newKaitaiFileStream(filename), nil, nil)


##[
RF signal + noise pair at a single antenna
]##
proc read*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_SignalNoise], io: KaitaiStream, root: KaitaiStruct, parent: PacketPpi_Radio80211nMacPhyExtBody): PacketPpi_Radio80211nMacPhyExtBody_SignalNoise =
  template this: untyped = result
  this = new(PacketPpi_Radio80211nMacPhyExtBody_SignalNoise)
  let root = if root == nil: cast[PacketPpi](this) else: cast[PacketPpi](root)
  this.io = io
  this.root = root
  this.parent = parent


  ##[
  RF signal, dBm
  ]##
  let signalExpr = this.io.readS1()
  this.signal = signalExpr

  ##[
  RF noise, dBm
  ]##
  let noiseExpr = this.io.readS1()
  this.noise = noiseExpr

proc fromFile*(_: typedesc[PacketPpi_Radio80211nMacPhyExtBody_SignalNoise], filename: string): PacketPpi_Radio80211nMacPhyExtBody_SignalNoise =
  PacketPpi_Radio80211nMacPhyExtBody_SignalNoise.read(newKaitaiFileStream(filename), nil, nil)