// 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 and performs a hard chop on the checksum // If a user is handing in subslices or packets from a buffered stream, the capacity of the slice // may extend beyond the len, rather than expecting callers to enforce cap==len on every packet // we take the hit in this one case and do a reallocation. If the user DOES enforce cap==len // then the reallocation will happen anyway on the append. This is requried because the append // write to the memory directly after the payload if there is sufficient capacity, which callers // may not expect. reallocPayload := make([]byte, len(payload)+4) copy(reallocPayload[0:len(payload)], payload) h := crc32.NewIEEE() h.Write(payload) binary.LittleEndian.PutUint32(reallocPayload[len(payload):], h.Sum32()) payload = reallocPayload } 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 }