aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/layers/radiotap.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/layers/radiotap.go')
-rw-r--r--vendor/github.com/google/gopacket/layers/radiotap.go1045
1 files changed, 1045 insertions, 0 deletions
diff --git a/vendor/github.com/google/gopacket/layers/radiotap.go b/vendor/github.com/google/gopacket/layers/radiotap.go
new file mode 100644
index 0000000..4304e75
--- /dev/null
+++ b/vendor/github.com/google/gopacket/layers/radiotap.go
@@ -0,0 +1,1045 @@
+// Copyright 2014 Google, Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+package layers
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "hash/crc32"
+ "strings"
+
+ "github.com/google/gopacket"
+)
+
+// align calculates the number of bytes needed to align with the width
+// on the offset, returning the number of bytes we need to skip to
+// align to the offset (width).
+func align(offset uint16, width uint16) uint16 {
+ return ((((offset) + ((width) - 1)) & (^((width) - 1))) - offset)
+}
+
+type RadioTapPresent uint32
+
+const (
+ RadioTapPresentTSFT RadioTapPresent = 1 << iota
+ RadioTapPresentFlags
+ RadioTapPresentRate
+ RadioTapPresentChannel
+ RadioTapPresentFHSS
+ RadioTapPresentDBMAntennaSignal
+ RadioTapPresentDBMAntennaNoise
+ RadioTapPresentLockQuality
+ RadioTapPresentTxAttenuation
+ RadioTapPresentDBTxAttenuation
+ RadioTapPresentDBMTxPower
+ RadioTapPresentAntenna
+ RadioTapPresentDBAntennaSignal
+ RadioTapPresentDBAntennaNoise
+ RadioTapPresentRxFlags
+ RadioTapPresentTxFlags
+ RadioTapPresentRtsRetries
+ RadioTapPresentDataRetries
+ _
+ RadioTapPresentMCS
+ RadioTapPresentAMPDUStatus
+ RadioTapPresentVHT
+ RadioTapPresentEXT RadioTapPresent = 1 << 31
+)
+
+func (r RadioTapPresent) TSFT() bool {
+ return r&RadioTapPresentTSFT != 0
+}
+func (r RadioTapPresent) Flags() bool {
+ return r&RadioTapPresentFlags != 0
+}
+func (r RadioTapPresent) Rate() bool {
+ return r&RadioTapPresentRate != 0
+}
+func (r RadioTapPresent) Channel() bool {
+ return r&RadioTapPresentChannel != 0
+}
+func (r RadioTapPresent) FHSS() bool {
+ return r&RadioTapPresentFHSS != 0
+}
+func (r RadioTapPresent) DBMAntennaSignal() bool {
+ return r&RadioTapPresentDBMAntennaSignal != 0
+}
+func (r RadioTapPresent) DBMAntennaNoise() bool {
+ return r&RadioTapPresentDBMAntennaNoise != 0
+}
+func (r RadioTapPresent) LockQuality() bool {
+ return r&RadioTapPresentLockQuality != 0
+}
+func (r RadioTapPresent) TxAttenuation() bool {
+ return r&RadioTapPresentTxAttenuation != 0
+}
+func (r RadioTapPresent) DBTxAttenuation() bool {
+ return r&RadioTapPresentDBTxAttenuation != 0
+}
+func (r RadioTapPresent) DBMTxPower() bool {
+ return r&RadioTapPresentDBMTxPower != 0
+}
+func (r RadioTapPresent) Antenna() bool {
+ return r&RadioTapPresentAntenna != 0
+}
+func (r RadioTapPresent) DBAntennaSignal() bool {
+ return r&RadioTapPresentDBAntennaSignal != 0
+}
+func (r RadioTapPresent) DBAntennaNoise() bool {
+ return r&RadioTapPresentDBAntennaNoise != 0
+}
+func (r RadioTapPresent) RxFlags() bool {
+ return r&RadioTapPresentRxFlags != 0
+}
+func (r RadioTapPresent) TxFlags() bool {
+ return r&RadioTapPresentTxFlags != 0
+}
+func (r RadioTapPresent) RtsRetries() bool {
+ return r&RadioTapPresentRtsRetries != 0
+}
+func (r RadioTapPresent) DataRetries() bool {
+ return r&RadioTapPresentDataRetries != 0
+}
+func (r RadioTapPresent) MCS() bool {
+ return r&RadioTapPresentMCS != 0
+}
+func (r RadioTapPresent) AMPDUStatus() bool {
+ return r&RadioTapPresentAMPDUStatus != 0
+}
+func (r RadioTapPresent) VHT() bool {
+ return r&RadioTapPresentVHT != 0
+}
+func (r RadioTapPresent) EXT() bool {
+ return r&RadioTapPresentEXT != 0
+}
+
+type RadioTapChannelFlags uint16
+
+const (
+ RadioTapChannelFlagsTurbo RadioTapChannelFlags = 0x0010 // Turbo channel
+ RadioTapChannelFlagsCCK RadioTapChannelFlags = 0x0020 // CCK channel
+ RadioTapChannelFlagsOFDM RadioTapChannelFlags = 0x0040 // OFDM channel
+ RadioTapChannelFlagsGhz2 RadioTapChannelFlags = 0x0080 // 2 GHz spectrum channel.
+ RadioTapChannelFlagsGhz5 RadioTapChannelFlags = 0x0100 // 5 GHz spectrum channel
+ RadioTapChannelFlagsPassive RadioTapChannelFlags = 0x0200 // Only passive scan allowed
+ RadioTapChannelFlagsDynamic RadioTapChannelFlags = 0x0400 // Dynamic CCK-OFDM channel
+ RadioTapChannelFlagsGFSK RadioTapChannelFlags = 0x0800 // GFSK channel (FHSS PHY)
+)
+
+func (r RadioTapChannelFlags) Turbo() bool {
+ return r&RadioTapChannelFlagsTurbo != 0
+}
+func (r RadioTapChannelFlags) CCK() bool {
+ return r&RadioTapChannelFlagsCCK != 0
+}
+func (r RadioTapChannelFlags) OFDM() bool {
+ return r&RadioTapChannelFlagsOFDM != 0
+}
+func (r RadioTapChannelFlags) Ghz2() bool {
+ return r&RadioTapChannelFlagsGhz2 != 0
+}
+func (r RadioTapChannelFlags) Ghz5() bool {
+ return r&RadioTapChannelFlagsGhz5 != 0
+}
+func (r RadioTapChannelFlags) Passive() bool {
+ return r&RadioTapChannelFlagsPassive != 0
+}
+func (r RadioTapChannelFlags) Dynamic() bool {
+ return r&RadioTapChannelFlagsDynamic != 0
+}
+func (r RadioTapChannelFlags) GFSK() bool {
+ return r&RadioTapChannelFlagsGFSK != 0
+}
+
+// String provides a human readable string for RadioTapChannelFlags.
+// This string is possibly subject to change over time; if you're storing this
+// persistently, you should probably store the RadioTapChannelFlags value, not its string.
+func (a RadioTapChannelFlags) String() string {
+ var out bytes.Buffer
+ if a.Turbo() {
+ out.WriteString("Turbo,")
+ }
+ if a.CCK() {
+ out.WriteString("CCK,")
+ }
+ if a.OFDM() {
+ out.WriteString("OFDM,")
+ }
+ if a.Ghz2() {
+ out.WriteString("Ghz2,")
+ }
+ if a.Ghz5() {
+ out.WriteString("Ghz5,")
+ }
+ if a.Passive() {
+ out.WriteString("Passive,")
+ }
+ if a.Dynamic() {
+ out.WriteString("Dynamic,")
+ }
+ if a.GFSK() {
+ out.WriteString("GFSK,")
+ }
+
+ if length := out.Len(); length > 0 {
+ return string(out.Bytes()[:length-1]) // strip final comma
+ }
+ return ""
+}
+
+type RadioTapFlags uint8
+
+const (
+ RadioTapFlagsCFP RadioTapFlags = 1 << iota // sent/received during CFP
+ RadioTapFlagsShortPreamble // sent/received * with short * preamble
+ RadioTapFlagsWEP // sent/received * with WEP encryption
+ RadioTapFlagsFrag // sent/received * with fragmentation
+ RadioTapFlagsFCS // frame includes FCS
+ RadioTapFlagsDatapad // frame has padding between * 802.11 header and payload * (to 32-bit boundary)
+ RadioTapFlagsBadFCS // does not pass FCS check
+ RadioTapFlagsShortGI // HT short GI
+)
+
+func (r RadioTapFlags) CFP() bool {
+ return r&RadioTapFlagsCFP != 0
+}
+func (r RadioTapFlags) ShortPreamble() bool {
+ return r&RadioTapFlagsShortPreamble != 0
+}
+func (r RadioTapFlags) WEP() bool {
+ return r&RadioTapFlagsWEP != 0
+}
+func (r RadioTapFlags) Frag() bool {
+ return r&RadioTapFlagsFrag != 0
+}
+func (r RadioTapFlags) FCS() bool {
+ return r&RadioTapFlagsFCS != 0
+}
+func (r RadioTapFlags) Datapad() bool {
+ return r&RadioTapFlagsDatapad != 0
+}
+func (r RadioTapFlags) BadFCS() bool {
+ return r&RadioTapFlagsBadFCS != 0
+}
+func (r RadioTapFlags) ShortGI() bool {
+ return r&RadioTapFlagsShortGI != 0
+}
+
+// String provides a human readable string for RadioTapFlags.
+// This string is possibly subject to change over time; if you're storing this
+// persistently, you should probably store the RadioTapFlags value, not its string.
+func (a RadioTapFlags) String() string {
+ var out bytes.Buffer
+ if a.CFP() {
+ out.WriteString("CFP,")
+ }
+ if a.ShortPreamble() {
+ out.WriteString("SHORT-PREAMBLE,")
+ }
+ if a.WEP() {
+ out.WriteString("WEP,")
+ }
+ if a.Frag() {
+ out.WriteString("FRAG,")
+ }
+ if a.FCS() {
+ out.WriteString("FCS,")
+ }
+ if a.Datapad() {
+ out.WriteString("DATAPAD,")
+ }
+ if a.ShortGI() {
+ out.WriteString("SHORT-GI,")
+ }
+
+ if length := out.Len(); length > 0 {
+ return string(out.Bytes()[:length-1]) // strip final comma
+ }
+ return ""
+}
+
+type RadioTapRate uint8
+
+func (a RadioTapRate) String() string {
+ return fmt.Sprintf("%v Mb/s", 0.5*float32(a))
+}
+
+type RadioTapChannelFrequency uint16
+
+func (a RadioTapChannelFrequency) String() string {
+ return fmt.Sprintf("%d MHz", a)
+}
+
+type RadioTapRxFlags uint16
+
+const (
+ RadioTapRxFlagsBadPlcp RadioTapRxFlags = 0x0002
+)
+
+func (self RadioTapRxFlags) BadPlcp() bool {
+ return self&RadioTapRxFlagsBadPlcp != 0
+}
+
+func (self RadioTapRxFlags) String() string {
+ if self.BadPlcp() {
+ return "BADPLCP"
+ }
+ return ""
+}
+
+type RadioTapTxFlags uint16
+
+const (
+ RadioTapTxFlagsFail RadioTapTxFlags = 1 << iota
+ RadioTapTxFlagsCTS
+ RadioTapTxFlagsRTS
+ RadioTapTxFlagsNoACK
+)
+
+func (self RadioTapTxFlags) Fail() bool { return self&RadioTapTxFlagsFail != 0 }
+func (self RadioTapTxFlags) CTS() bool { return self&RadioTapTxFlagsCTS != 0 }
+func (self RadioTapTxFlags) RTS() bool { return self&RadioTapTxFlagsRTS != 0 }
+func (self RadioTapTxFlags) NoACK() bool { return self&RadioTapTxFlagsNoACK != 0 }
+
+func (self RadioTapTxFlags) String() string {
+ var tokens []string
+ if self.Fail() {
+ tokens = append(tokens, "Fail")
+ }
+ if self.CTS() {
+ tokens = append(tokens, "CTS")
+ }
+ if self.RTS() {
+ tokens = append(tokens, "RTS")
+ }
+ if self.NoACK() {
+ tokens = append(tokens, "NoACK")
+ }
+ return strings.Join(tokens, ",")
+}
+
+type RadioTapMCS struct {
+ Known RadioTapMCSKnown
+ Flags RadioTapMCSFlags
+ MCS uint8
+}
+
+func (self RadioTapMCS) String() string {
+ var tokens []string
+ if self.Known.Bandwidth() {
+ token := "?"
+ switch self.Flags.Bandwidth() {
+ case 0:
+ token = "20"
+ case 1:
+ token = "40"
+ case 2:
+ token = "40(20L)"
+ case 3:
+ token = "40(20U)"
+ }
+ tokens = append(tokens, token)
+ }
+ if self.Known.MCSIndex() {
+ tokens = append(tokens, fmt.Sprintf("MCSIndex#%d", self.MCS))
+ }
+ if self.Known.GuardInterval() {
+ if self.Flags.ShortGI() {
+ tokens = append(tokens, fmt.Sprintf("shortGI"))
+ } else {
+ tokens = append(tokens, fmt.Sprintf("longGI"))
+ }
+ }
+ if self.Known.HTFormat() {
+ if self.Flags.Greenfield() {
+ tokens = append(tokens, fmt.Sprintf("HT-greenfield"))
+ } else {
+ tokens = append(tokens, fmt.Sprintf("HT-mixed"))
+ }
+ }
+ if self.Known.FECType() {
+ if self.Flags.FECLDPC() {
+ tokens = append(tokens, fmt.Sprintf("LDPC"))
+ } else {
+ tokens = append(tokens, fmt.Sprintf("BCC"))
+ }
+ }
+ if self.Known.STBC() {
+ tokens = append(tokens, fmt.Sprintf("STBC#%d", self.Flags.STBC()))
+ }
+ if self.Known.NESS() {
+ num := 0
+ if self.Known.NESS1() {
+ num |= 0x02
+ }
+ if self.Flags.NESS0() {
+ num |= 0x01
+ }
+ tokens = append(tokens, fmt.Sprintf("num-of-ESS#%d", num))
+ }
+ return strings.Join(tokens, ",")
+}
+
+type RadioTapMCSKnown uint8
+
+const (
+ RadioTapMCSKnownBandwidth RadioTapMCSKnown = 1 << iota
+ RadioTapMCSKnownMCSIndex
+ RadioTapMCSKnownGuardInterval
+ RadioTapMCSKnownHTFormat
+ RadioTapMCSKnownFECType
+ RadioTapMCSKnownSTBC
+ RadioTapMCSKnownNESS
+ RadioTapMCSKnownNESS1
+)
+
+func (self RadioTapMCSKnown) Bandwidth() bool { return self&RadioTapMCSKnownBandwidth != 0 }
+func (self RadioTapMCSKnown) MCSIndex() bool { return self&RadioTapMCSKnownMCSIndex != 0 }
+func (self RadioTapMCSKnown) GuardInterval() bool { return self&RadioTapMCSKnownGuardInterval != 0 }
+func (self RadioTapMCSKnown) HTFormat() bool { return self&RadioTapMCSKnownHTFormat != 0 }
+func (self RadioTapMCSKnown) FECType() bool { return self&RadioTapMCSKnownFECType != 0 }
+func (self RadioTapMCSKnown) STBC() bool { return self&RadioTapMCSKnownSTBC != 0 }
+func (self RadioTapMCSKnown) NESS() bool { return self&RadioTapMCSKnownNESS != 0 }
+func (self RadioTapMCSKnown) NESS1() bool { return self&RadioTapMCSKnownNESS1 != 0 }
+
+type RadioTapMCSFlags uint8
+
+const (
+ RadioTapMCSFlagsBandwidthMask RadioTapMCSFlags = 0x03
+ RadioTapMCSFlagsShortGI = 0x04
+ RadioTapMCSFlagsGreenfield = 0x08
+ RadioTapMCSFlagsFECLDPC = 0x10
+ RadioTapMCSFlagsSTBCMask = 0x60
+ RadioTapMCSFlagsNESS0 = 0x80
+)
+
+func (self RadioTapMCSFlags) Bandwidth() int {
+ return int(self & RadioTapMCSFlagsBandwidthMask)
+}
+func (self RadioTapMCSFlags) ShortGI() bool { return self&RadioTapMCSFlagsShortGI != 0 }
+func (self RadioTapMCSFlags) Greenfield() bool { return self&RadioTapMCSFlagsGreenfield != 0 }
+func (self RadioTapMCSFlags) FECLDPC() bool { return self&RadioTapMCSFlagsFECLDPC != 0 }
+func (self RadioTapMCSFlags) STBC() int {
+ return int(self&RadioTapMCSFlagsSTBCMask) >> 5
+}
+func (self RadioTapMCSFlags) NESS0() bool { return self&RadioTapMCSFlagsNESS0 != 0 }
+
+type RadioTapAMPDUStatus struct {
+ Reference uint32
+ Flags RadioTapAMPDUStatusFlags
+ CRC uint8
+}
+
+func (self RadioTapAMPDUStatus) String() string {
+ tokens := []string{
+ fmt.Sprintf("ref#%x", self.Reference),
+ }
+ if self.Flags.ReportZerolen() && self.Flags.IsZerolen() {
+ tokens = append(tokens, fmt.Sprintf("zero-length"))
+ }
+ if self.Flags.LastKnown() && self.Flags.IsLast() {
+ tokens = append(tokens, "last")
+ }
+ if self.Flags.DelimCRCErr() {
+ tokens = append(tokens, "delimiter CRC error")
+ }
+ if self.Flags.DelimCRCKnown() {
+ tokens = append(tokens, fmt.Sprintf("delimiter-CRC=%02x", self.CRC))
+ }
+ return strings.Join(tokens, ",")
+}
+
+type RadioTapAMPDUStatusFlags uint16
+
+const (
+ RadioTapAMPDUStatusFlagsReportZerolen RadioTapAMPDUStatusFlags = 1 << iota
+ RadioTapAMPDUIsZerolen
+ RadioTapAMPDULastKnown
+ RadioTapAMPDUIsLast
+ RadioTapAMPDUDelimCRCErr
+ RadioTapAMPDUDelimCRCKnown
+)
+
+func (self RadioTapAMPDUStatusFlags) ReportZerolen() bool {
+ return self&RadioTapAMPDUStatusFlagsReportZerolen != 0
+}
+func (self RadioTapAMPDUStatusFlags) IsZerolen() bool { return self&RadioTapAMPDUIsZerolen != 0 }
+func (self RadioTapAMPDUStatusFlags) LastKnown() bool { return self&RadioTapAMPDULastKnown != 0 }
+func (self RadioTapAMPDUStatusFlags) IsLast() bool { return self&RadioTapAMPDUIsLast != 0 }
+func (self RadioTapAMPDUStatusFlags) DelimCRCErr() bool { return self&RadioTapAMPDUDelimCRCErr != 0 }
+func (self RadioTapAMPDUStatusFlags) DelimCRCKnown() bool { return self&RadioTapAMPDUDelimCRCKnown != 0 }
+
+type RadioTapVHT struct {
+ Known RadioTapVHTKnown
+ Flags RadioTapVHTFlags
+ Bandwidth uint8
+ MCSNSS [4]RadioTapVHTMCSNSS
+ Coding uint8
+ GroupId uint8
+ PartialAID uint16
+}
+
+func (self RadioTapVHT) String() string {
+ var tokens []string
+ if self.Known.STBC() {
+ if self.Flags.STBC() {
+ tokens = append(tokens, "STBC")
+ } else {
+ tokens = append(tokens, "no STBC")
+ }
+ }
+ if self.Known.TXOPPSNotAllowed() {
+ if self.Flags.TXOPPSNotAllowed() {
+ tokens = append(tokens, "TXOP doze not allowed")
+ } else {
+ tokens = append(tokens, "TXOP doze allowed")
+ }
+ }
+ if self.Known.GI() {
+ if self.Flags.SGI() {
+ tokens = append(tokens, "short GI")
+ } else {
+ tokens = append(tokens, "long GI")
+ }
+ }
+ if self.Known.SGINSYMDisambiguation() {
+ if self.Flags.SGINSYMMod() {
+ tokens = append(tokens, "NSYM mod 10=9")
+ } else {
+ tokens = append(tokens, "NSYM mod 10!=9 or no short GI")
+ }
+ }
+ if self.Known.LDPCExtraOFDMSymbol() {
+ if self.Flags.LDPCExtraOFDMSymbol() {
+ tokens = append(tokens, "LDPC extra OFDM symbols")
+ } else {
+ tokens = append(tokens, "no LDPC extra OFDM symbols")
+ }
+ }
+ if self.Known.Beamformed() {
+ if self.Flags.Beamformed() {
+ tokens = append(tokens, "beamformed")
+ } else {
+ tokens = append(tokens, "no beamformed")
+ }
+ }
+ if self.Known.Bandwidth() {
+ token := "?"
+ switch self.Bandwidth & 0x1f {
+ case 0:
+ token = "20"
+ case 1:
+ token = "40"
+ case 2:
+ token = "40(20L)"
+ case 3:
+ token = "40(20U)"
+ case 4:
+ token = "80"
+ case 5:
+ token = "80(40L)"
+ case 6:
+ token = "80(40U)"
+ case 7:
+ token = "80(20LL)"
+ case 8:
+ token = "80(20LU)"
+ case 9:
+ token = "80(20UL)"
+ case 10:
+ token = "80(20UU)"
+ case 11:
+ token = "160"
+ case 12:
+ token = "160(80L)"
+ case 13:
+ token = "160(80U)"
+ case 14:
+ token = "160(40LL)"
+ case 15:
+ token = "160(40LU)"
+ case 16:
+ token = "160(40UL)"
+ case 17:
+ token = "160(40UU)"
+ case 18:
+ token = "160(20LLL)"
+ case 19:
+ token = "160(20LLU)"
+ case 20:
+ token = "160(20LUL)"
+ case 21:
+ token = "160(20LUU)"
+ case 22:
+ token = "160(20ULL)"
+ case 23:
+ token = "160(20ULU)"
+ case 24:
+ token = "160(20UUL)"
+ case 25:
+ token = "160(20UUU)"
+ }
+ tokens = append(tokens, token)
+ }
+ for i, MCSNSS := range self.MCSNSS {
+ if MCSNSS.Present() {
+ fec := "?"
+ switch self.Coding & (1 << uint8(i)) {
+ case 0:
+ fec = "BCC"
+ case 1:
+ fec = "LDPC"
+ }
+ tokens = append(tokens, fmt.Sprintf("user%d(%s,%s)", i, MCSNSS.String(), fec))
+ }
+ }
+ if self.Known.GroupId() {
+ tokens = append(tokens,
+ fmt.Sprintf("group=%d", self.GroupId))
+ }
+ if self.Known.PartialAID() {
+ tokens = append(tokens,
+ fmt.Sprintf("partial-AID=%d", self.PartialAID))
+ }
+ return strings.Join(tokens, ",")
+}
+
+type RadioTapVHTKnown uint16
+
+const (
+ RadioTapVHTKnownSTBC RadioTapVHTKnown = 1 << iota
+ RadioTapVHTKnownTXOPPSNotAllowed
+ RadioTapVHTKnownGI
+ RadioTapVHTKnownSGINSYMDisambiguation
+ RadioTapVHTKnownLDPCExtraOFDMSymbol
+ RadioTapVHTKnownBeamformed
+ RadioTapVHTKnownBandwidth
+ RadioTapVHTKnownGroupId
+ RadioTapVHTKnownPartialAID
+)
+
+func (self RadioTapVHTKnown) STBC() bool { return self&RadioTapVHTKnownSTBC != 0 }
+func (self RadioTapVHTKnown) TXOPPSNotAllowed() bool {
+ return self&RadioTapVHTKnownTXOPPSNotAllowed != 0
+}
+func (self RadioTapVHTKnown) GI() bool { return self&RadioTapVHTKnownGI != 0 }
+func (self RadioTapVHTKnown) SGINSYMDisambiguation() bool {
+ return self&RadioTapVHTKnownSGINSYMDisambiguation != 0
+}
+func (self RadioTapVHTKnown) LDPCExtraOFDMSymbol() bool {
+ return self&RadioTapVHTKnownLDPCExtraOFDMSymbol != 0
+}
+func (self RadioTapVHTKnown) Beamformed() bool { return self&RadioTapVHTKnownBeamformed != 0 }
+func (self RadioTapVHTKnown) Bandwidth() bool { return self&RadioTapVHTKnownBandwidth != 0 }
+func (self RadioTapVHTKnown) GroupId() bool { return self&RadioTapVHTKnownGroupId != 0 }
+func (self RadioTapVHTKnown) PartialAID() bool { return self&RadioTapVHTKnownPartialAID != 0 }
+
+type RadioTapVHTFlags uint8
+
+const (
+ RadioTapVHTFlagsSTBC RadioTapVHTFlags = 1 << iota
+ RadioTapVHTFlagsTXOPPSNotAllowed
+ RadioTapVHTFlagsSGI
+ RadioTapVHTFlagsSGINSYMMod
+ RadioTapVHTFlagsLDPCExtraOFDMSymbol
+ RadioTapVHTFlagsBeamformed
+)
+
+func (self RadioTapVHTFlags) STBC() bool { return self&RadioTapVHTFlagsSTBC != 0 }
+func (self RadioTapVHTFlags) TXOPPSNotAllowed() bool {
+ return self&RadioTapVHTFlagsTXOPPSNotAllowed != 0
+}
+func (self RadioTapVHTFlags) SGI() bool { return self&RadioTapVHTFlagsSGI != 0 }
+func (self RadioTapVHTFlags) SGINSYMMod() bool { return self&RadioTapVHTFlagsSGINSYMMod != 0 }
+func (self RadioTapVHTFlags) LDPCExtraOFDMSymbol() bool {
+ return self&RadioTapVHTFlagsLDPCExtraOFDMSymbol != 0
+}
+func (self RadioTapVHTFlags) Beamformed() bool { return self&RadioTapVHTFlagsBeamformed != 0 }
+
+type RadioTapVHTMCSNSS uint8
+
+func (self RadioTapVHTMCSNSS) Present() bool {
+ return self&0x0F != 0
+}
+
+func (self RadioTapVHTMCSNSS) String() string {
+ return fmt.Sprintf("NSS#%dMCS#%d", uint32(self&0xf), uint32(self>>4))
+}
+
+func decodeRadioTap(data []byte, p gopacket.PacketBuilder) error {
+ d := &RadioTap{}
+ // TODO: Should we set LinkLayer here? And implement LinkFlow
+ return decodingLayerDecoder(d, data, p)
+}
+
+type RadioTap struct {
+ BaseLayer
+
+ // Version 0. Only increases for drastic changes, introduction of compatible new fields does not count.
+ Version uint8
+ // Length of the whole header in bytes, including it_version, it_pad, it_len, and data fields.
+ Length uint16
+ // Present is a bitmap telling which fields are present. Set bit 31 (0x80000000) to extend the bitmap by another 32 bits. Additional extensions are made by setting bit 31.
+ Present RadioTapPresent
+ // TSFT: value in microseconds of the MAC's 64-bit 802.11 Time Synchronization Function timer when the first bit of the MPDU arrived at the MAC. For received frames, only.
+ TSFT uint64
+ Flags RadioTapFlags
+ // Rate Tx/Rx data rate
+ Rate RadioTapRate
+ // ChannelFrequency Tx/Rx frequency in MHz, followed by flags
+ ChannelFrequency RadioTapChannelFrequency
+ ChannelFlags RadioTapChannelFlags
+ // FHSS For frequency-hopping radios, the hop set (first byte) and pattern (second byte).
+ FHSS uint16
+ // DBMAntennaSignal RF signal power at the antenna, decibel difference from one milliwatt.
+ DBMAntennaSignal int8
+ // DBMAntennaNoise RF noise power at the antenna, decibel difference from one milliwatt.
+ DBMAntennaNoise int8
+ // LockQuality Quality of Barker code lock. Unitless. Monotonically nondecreasing with "better" lock strength. Called "Signal Quality" in datasheets.
+ LockQuality uint16
+ // TxAttenuation Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
+ TxAttenuation uint16
+ // DBTxAttenuation Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
+ DBTxAttenuation uint16
+ // DBMTxPower Transmit power expressed as dBm (decibels from a 1 milliwatt reference). This is the absolute power level measured at the antenna port.
+ DBMTxPower int8
+ // Antenna Unitless indication of the Rx/Tx antenna for this packet. The first antenna is antenna 0.
+ Antenna uint8
+ // DBAntennaSignal RF signal power at the antenna, decibel difference from an arbitrary, fixed reference.
+ DBAntennaSignal uint8
+ // DBAntennaNoise RF noise power at the antenna, decibel difference from an arbitrary, fixed reference point.
+ DBAntennaNoise uint8
+ //
+ RxFlags RadioTapRxFlags
+ TxFlags RadioTapTxFlags
+ RtsRetries uint8
+ DataRetries uint8
+ MCS RadioTapMCS
+ AMPDUStatus RadioTapAMPDUStatus
+ VHT RadioTapVHT
+}
+
+func (m *RadioTap) LayerType() gopacket.LayerType { return LayerTypeRadioTap }
+
+func (m *RadioTap) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+ m.Version = uint8(data[0])
+ m.Length = binary.LittleEndian.Uint16(data[2:4])
+ m.Present = RadioTapPresent(binary.LittleEndian.Uint32(data[4:8]))
+
+ offset := uint16(4)
+
+ for (binary.LittleEndian.Uint32(data[offset:offset+4]) & 0x80000000) != 0 {
+ // This parser only handles standard radiotap namespace,
+ // and expects all fields are packed in the first it_present.
+ // Extended bitmap will be just ignored.
+ offset += 4
+ }
+ offset += 4 // skip the bitmap
+
+ if m.Present.TSFT() {
+ offset += align(offset, 8)
+ m.TSFT = binary.LittleEndian.Uint64(data[offset : offset+8])
+ offset += 8
+ }
+ if m.Present.Flags() {
+ m.Flags = RadioTapFlags(data[offset])
+ offset++
+ }
+ if m.Present.Rate() {
+ m.Rate = RadioTapRate(data[offset])
+ offset++
+ }
+ if m.Present.Channel() {
+ offset += align(offset, 2)
+ m.ChannelFrequency = RadioTapChannelFrequency(binary.LittleEndian.Uint16(data[offset : offset+2]))
+ offset += 2
+ m.ChannelFlags = RadioTapChannelFlags(binary.LittleEndian.Uint16(data[offset : offset+2]))
+ offset += 2
+ }
+ if m.Present.FHSS() {
+ m.FHSS = binary.LittleEndian.Uint16(data[offset : offset+2])
+ offset += 2
+ }
+ if m.Present.DBMAntennaSignal() {
+ m.DBMAntennaSignal = int8(data[offset])
+ offset++
+ }
+ if m.Present.DBMAntennaNoise() {
+ m.DBMAntennaNoise = int8(data[offset])
+ offset++
+ }
+ if m.Present.LockQuality() {
+ offset += align(offset, 2)
+ m.LockQuality = binary.LittleEndian.Uint16(data[offset : offset+2])
+ offset += 2
+ }
+ if m.Present.TxAttenuation() {
+ offset += align(offset, 2)
+ m.TxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
+ offset += 2
+ }
+ if m.Present.DBTxAttenuation() {
+ offset += align(offset, 2)
+ m.DBTxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
+ offset += 2
+ }
+ if m.Present.DBMTxPower() {
+ m.DBMTxPower = int8(data[offset])
+ offset++
+ }
+ if m.Present.Antenna() {
+ m.Antenna = uint8(data[offset])
+ offset++
+ }
+ if m.Present.DBAntennaSignal() {
+ m.DBAntennaSignal = uint8(data[offset])
+ offset++
+ }
+ if m.Present.DBAntennaNoise() {
+ m.DBAntennaNoise = uint8(data[offset])
+ offset++
+ }
+ if m.Present.RxFlags() {
+ offset += align(offset, 2)
+ m.RxFlags = RadioTapRxFlags(binary.LittleEndian.Uint16(data[offset:]))
+ offset += 2
+ }
+ if m.Present.TxFlags() {
+ offset += align(offset, 2)
+ m.TxFlags = RadioTapTxFlags(binary.LittleEndian.Uint16(data[offset:]))
+ offset += 2
+ }
+ if m.Present.RtsRetries() {
+ m.RtsRetries = uint8(data[offset])
+ offset++
+ }
+ if m.Present.DataRetries() {
+ m.DataRetries = uint8(data[offset])
+ offset++
+ }
+ if m.Present.MCS() {
+ m.MCS = RadioTapMCS{
+ RadioTapMCSKnown(data[offset]),
+ RadioTapMCSFlags(data[offset+1]),
+ uint8(data[offset+2]),
+ }
+ offset += 3
+ }
+ if m.Present.AMPDUStatus() {
+ offset += align(offset, 4)
+ m.AMPDUStatus = RadioTapAMPDUStatus{
+ Reference: binary.LittleEndian.Uint32(data[offset:]),
+ Flags: RadioTapAMPDUStatusFlags(binary.LittleEndian.Uint16(data[offset+4:])),
+ CRC: uint8(data[offset+6]),
+ }
+ offset += 8
+ }
+ if m.Present.VHT() {
+ offset += align(offset, 2)
+ m.VHT = RadioTapVHT{
+ Known: RadioTapVHTKnown(binary.LittleEndian.Uint16(data[offset:])),
+ Flags: RadioTapVHTFlags(data[offset+2]),
+ Bandwidth: uint8(data[offset+3]),
+ MCSNSS: [4]RadioTapVHTMCSNSS{
+ RadioTapVHTMCSNSS(data[offset+4]),
+ RadioTapVHTMCSNSS(data[offset+5]),
+ RadioTapVHTMCSNSS(data[offset+6]),
+ RadioTapVHTMCSNSS(data[offset+7]),
+ },
+ Coding: uint8(data[offset+8]),
+ GroupId: uint8(data[offset+9]),
+ PartialAID: binary.LittleEndian.Uint16(data[offset+10:]),
+ }
+ offset += 12
+ }
+
+ payload := data[m.Length:]
+ if !m.Flags.FCS() { // Dot11.DecodeFromBytes() expects FCS present
+ fcs := make([]byte, 4)
+ h := crc32.NewIEEE()
+ h.Write(payload)
+ binary.LittleEndian.PutUint32(fcs, h.Sum32())
+ payload = append(payload, fcs...)
+ }
+ m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: payload}
+
+ return nil
+}
+
+func (m RadioTap) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+ buf := make([]byte, 1024)
+
+ buf[0] = m.Version
+ buf[1] = 0
+
+ binary.LittleEndian.PutUint32(buf[4:8], uint32(m.Present))
+
+ offset := uint16(4)
+
+ for (binary.LittleEndian.Uint32(buf[offset:offset+4]) & 0x80000000) != 0 {
+ offset += 4
+ }
+
+ offset += 4
+
+ if m.Present.TSFT() {
+ offset += align(offset, 8)
+ binary.LittleEndian.PutUint64(buf[offset:offset+8], m.TSFT)
+ offset += 8
+ }
+
+ if m.Present.Flags() {
+ buf[offset] = uint8(m.Flags)
+ offset++
+ }
+
+ if m.Present.Rate() {
+ buf[offset] = uint8(m.Rate)
+ offset++
+ }
+
+ if m.Present.Channel() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFrequency))
+ offset += 2
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFlags))
+ offset += 2
+ }
+
+ if m.Present.FHSS() {
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], m.FHSS)
+ offset += 2
+ }
+
+ if m.Present.DBMAntennaSignal() {
+ buf[offset] = byte(m.DBMAntennaSignal)
+ offset++
+ }
+
+ if m.Present.DBMAntennaNoise() {
+ buf[offset] = byte(m.DBMAntennaNoise)
+ offset++
+ }
+
+ if m.Present.LockQuality() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], m.LockQuality)
+ offset += 2
+ }
+
+ if m.Present.TxAttenuation() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], m.TxAttenuation)
+ offset += 2
+ }
+
+ if m.Present.DBTxAttenuation() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], m.DBTxAttenuation)
+ offset += 2
+ }
+
+ if m.Present.DBMTxPower() {
+ buf[offset] = byte(m.DBMTxPower)
+ offset++
+ }
+
+ if m.Present.Antenna() {
+ buf[offset] = uint8(m.Antenna)
+ offset++
+ }
+
+ if m.Present.DBAntennaSignal() {
+ buf[offset] = uint8(m.DBAntennaSignal)
+ offset++
+ }
+
+ if m.Present.DBAntennaNoise() {
+ buf[offset] = uint8(m.DBAntennaNoise)
+ offset++
+ }
+
+ if m.Present.RxFlags() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.RxFlags))
+ offset += 2
+ }
+
+ if m.Present.TxFlags() {
+ offset += align(offset, 2)
+ binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.TxFlags))
+ offset += 2
+ }
+
+ if m.Present.RtsRetries() {
+ buf[offset] = m.RtsRetries
+ offset++
+ }
+
+ if m.Present.DataRetries() {
+ buf[offset] = m.DataRetries
+ offset++
+ }
+
+ if m.Present.MCS() {
+ buf[offset] = uint8(m.MCS.Known)
+ buf[offset+1] = uint8(m.MCS.Flags)
+ buf[offset+2] = uint8(m.MCS.MCS)
+
+ offset += 3
+ }
+
+ if m.Present.AMPDUStatus() {
+ offset += align(offset, 4)
+
+ binary.LittleEndian.PutUint32(buf[offset:offset+4], m.AMPDUStatus.Reference)
+ binary.LittleEndian.PutUint16(buf[offset+4:offset+6], uint16(m.AMPDUStatus.Flags))
+
+ buf[offset+6] = m.AMPDUStatus.CRC
+
+ offset += 8
+ }
+
+ if m.Present.VHT() {
+ offset += align(offset, 2)
+
+ binary.LittleEndian.PutUint16(buf[offset:], uint16(m.VHT.Known))
+
+ buf[offset+2] = uint8(m.VHT.Flags)
+ buf[offset+3] = uint8(m.VHT.Bandwidth)
+ buf[offset+4] = uint8(m.VHT.MCSNSS[0])
+ buf[offset+5] = uint8(m.VHT.MCSNSS[1])
+ buf[offset+6] = uint8(m.VHT.MCSNSS[2])
+ buf[offset+7] = uint8(m.VHT.MCSNSS[3])
+ buf[offset+8] = uint8(m.VHT.Coding)
+ buf[offset+9] = uint8(m.VHT.GroupId)
+
+ binary.LittleEndian.PutUint16(buf[offset+10:offset+12], m.VHT.PartialAID)
+
+ offset += 12
+ }
+
+ packetBuf, err := b.PrependBytes(int(offset))
+
+ if err != nil {
+ return err
+ }
+
+ if opts.FixLengths {
+ m.Length = offset
+ }
+
+ binary.LittleEndian.PutUint16(buf[2:4], m.Length)
+
+ copy(packetBuf, buf)
+
+ return nil
+}
+
+func (m *RadioTap) CanDecode() gopacket.LayerClass { return LayerTypeRadioTap }
+func (m *RadioTap) NextLayerType() gopacket.LayerType { return LayerTypeDot11 }