diff --git a/PacketDotNet/Ieee80211/RadioTapFields.cs b/PacketDotNet/Ieee80211/RadioTapFields.cs index e2076a00..5ad71497 100644 --- a/PacketDotNet/Ieee80211/RadioTapFields.cs +++ b/PacketDotNet/Ieee80211/RadioTapFields.cs @@ -5,9 +5,6 @@ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -/* - * Copyright 2010 Chris Morgan - */ using System; using System.IO; @@ -15,1529 +12,1900 @@ This Source Code Form is subject to the terms of the Mozilla Public namespace PacketDotNet.Ieee80211; +/// +/// The presence of this field indicates that the frame was received or transmitted using the VHT PHY (Wi-Fi 5 / ieee802.11ac). +/// +public class VeryHighThroughputRadioTapField : RadioTapField +{ /// - /// Channel field + /// Indicates the precense of data in this field /// - public class ChannelRadioTapField : RadioTapField - { - /// - /// Constructor - /// - /// - /// A - /// - public ChannelRadioTapField(BinaryReader br) - { - FrequencyMHz = br.ReadUInt16(); - Channel = ChannelFromFrequencyMHz(FrequencyMHz); - Flags = (RadioTapChannelFlags) br.ReadUInt16(); - } + public RadioTapVhtKnown Known { get; set; } - /// - /// Initializes a new instance of the class. - /// - public ChannelRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// Tx/Rx Frequency in MHz. - /// Flags. - public ChannelRadioTapField(ushort frequencyMhz, RadioTapChannelFlags flags) - { - FrequencyMHz = frequencyMhz; - Channel = ChannelFromFrequencyMHz(FrequencyMHz); - Flags = flags; - } + /// + /// VHT Flags + /// + public RadioTapVhtFlags Flags { get; set; } - /// - /// Channel number derived from frequency - /// - public int Channel { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Channel; - - /// - /// Gets the channel flags. - /// - public RadioTapChannelFlags Flags { get; } - - /// - /// Frequency in MHz - /// - public ushort FrequencyMHz { get; set; } - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 4; - - /// - /// Note that the alignment of the channel field is two bytes as it is comprised of two 2 byte fields - /// - /// The alignment. - public override ushort Alignment => 2; - - /// - /// Convert a frequency to a channel - /// - /// - /// There is some overlap between the 802.11b/g channel numbers and the 802.11a channel numbers. This means that while a particular frequncy will only - /// ever map to single channel number the same channel number may be returned for more than one frequency. At present this affects channel numbers 8 and 12. - /// - /// - /// A - /// - /// - /// A - /// - public static int ChannelFromFrequencyMHz(int frequencyMHz) - { - switch (frequencyMHz) - { - //802.11 bg channel numbers - case 2412: - { - return 1; - } - case 2417: - { - return 2; - } - case 2422: - { - return 3; - } - case 2427: - { - return 4; - } - case 2432: - { - return 5; - } - case 2437: - { - return 6; - } - case 2442: - { - return 7; - } - case 2447: - { - return 8; - } - case 2452: - { - return 9; - } - case 2457: - { - return 10; - } - case 2462: - { - return 11; - } - case 2467: - { - return 12; - } - case 2472: - { - return 13; - } - case 2484: - { - return 14; - } - //802.11 a channel numbers - case 4920: - { - return 240; - } - case 4940: - { - return 244; - } - case 4960: - { - return 248; - } - case 4980: - { - return 252; - } - case 5040: - { - return 8; - } - case 5060: - { - return 12; - } - case 5080: - { - return 16; - } - case 5170: - { - return 34; - } - case 5180: - { - return 36; - } - case 5190: - { - return 38; - } - case 5200: - { - return 40; - } - case 5210: - { - return 42; - } - case 5220: - { - return 44; - } - case 5230: - { - return 46; - } - case 5240: - { - return 48; - } - case 5260: - { - return 52; - } - case 5280: - { - return 56; - } - case 5300: - { - return 60; - } - case 5320: - { - return 64; - } - case 5500: - { - return 100; - } - case 5520: - { - return 104; - } - case 5540: - { - return 108; - } - case 5560: - { - return 112; - } - case 5580: - { - return 116; - } - case 5600: - { - return 120; - } - case 5620: - { - return 124; - } - case 5640: - { - return 128; - } - case 5660: - { - return 132; - } - case 5680: - { - return 136; - } - case 5700: - { - return 140; - } - case 5745: - { - return 149; - } - case 5765: - { - return 153; - } - case 5785: - { - return 157; - } - case 5805: - { - return 161; - } - case 5825: - { - return 165; - } - default: - { - return 0; - } - } - } + /// + /// Indicates the bandwidth and side channel for a frame capture with VHT + /// + public RadioTapVhtBandwidth Bandwidth { get; set; } - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - EndianBitConverter.Little.CopyBytes(FrequencyMHz, dest, offset); - EndianBitConverter.Little.CopyBytes((ushort) Flags, dest, offset + 2); - } + /// + /// Indicates MCS and NSS for user 1 + /// + public RadioTapVhtMcsNss McsNss1 { get; set; } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"FrequencyMHz {FrequencyMHz}, Channel {Channel}, Flags {Flags}"; - } - } + /// + /// Indicates MCS and NSS for user 2 + /// + public RadioTapVhtMcsNss McsNss2 { get; set; } /// - /// Fhss radio tap field + /// Indicates MCS and NSS for user 3 /// - public class FhssRadioTapField : RadioTapField - { - /// - /// Constructor - /// - /// - /// A - /// - public FhssRadioTapField(BinaryReader br) - { - var u16 = br.ReadUInt16(); + public RadioTapVhtMcsNss McsNss3 { get; set; } - ChannelHoppingSet = (byte) (u16 & 0xff); - Pattern = (byte) ((u16 >> 8) & 0xff); - } + /// + /// Indicates MCS and NSS for user 4 + /// + public RadioTapVhtMcsNss McsNss4 { get; set; } - /// - /// Initializes a new instance of the class. - /// - public FhssRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Channel hopping set. - /// - /// - /// Channel hopping pattern. - /// - public FhssRadioTapField(byte channelHoppingSet, byte pattern) - { - ChannelHoppingSet = channelHoppingSet; - Pattern = pattern; - } + /// + /// The coding for a user is only valid if the NSS (in the mcs_nss field) for that user is nonzero. + /// Encodes the FEC for up to four users + /// + public RadioTapVhtCoding Coding { get; set; } - /// - /// Hop set - /// - public byte ChannelHoppingSet { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Fhss; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 2; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Hop pattern - /// - public byte Pattern { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = ChannelHoppingSet; - dest[offset + 1] = Pattern; - } + /// + /// Group ID + /// The Group ID can be used to differentiate between SU PPDUs (group ID is 0 or 63) and MU PPDUs (group ID is 1 through 62). + /// + public byte GroupId { get; set; } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"ChannelHoppingSet {ChannelHoppingSet}, Pattern {Pattern}"; - } - } + /// + /// Partial AID + /// Only applicable to SU PPDUs. + /// + public ushort PartialAid { get; set; } /// - /// Radio tap flags + /// Constructor /// - public class FlagsRadioTapField : RadioTapField + /// + /// A + /// + public VeryHighThroughputRadioTapField(BinaryReader br) { - /// - /// Flags set - /// - public RadioTapFlags Flags; - - /// - /// Constructor - /// - /// - /// A - /// - public FlagsRadioTapField(BinaryReader br) - { - var u8 = br.ReadByte(); - Flags = (RadioTapFlags) u8; - } - - /// - /// Initializes a new instance of the class. - /// - public FlagsRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Flags. - /// - public FlagsRadioTapField(RadioTapFlags flags) - { - Flags = flags; - } + Known = (RadioTapVhtKnown)br.ReadUInt16(); + Flags = (RadioTapVhtFlags)br.ReadByte(); + Bandwidth = (RadioTapVhtBandwidth)br.ReadByte(); + McsNss1 = (RadioTapVhtMcsNss)br.ReadByte(); + McsNss2 = (RadioTapVhtMcsNss)br.ReadByte(); + McsNss3 = (RadioTapVhtMcsNss)br.ReadByte(); + McsNss4 = (RadioTapVhtMcsNss)br.ReadByte(); + Coding = (RadioTapVhtCoding)br.ReadByte(); + GroupId = br.ReadByte(); + PartialAid = br.ReadUInt16(); + } - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Flags; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = (byte) Flags; - } + /// + /// Initializes a new instance of the class. + /// + public VeryHighThroughputRadioTapField() + { } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"Flags {Flags}"; - } + /// + /// Initializes a new instance of the class. + /// + public VeryHighThroughputRadioTapField( + RadioTapVhtKnown known, + RadioTapVhtFlags flags, + RadioTapVhtBandwidth bandwidth, + RadioTapVhtMcsNss mcsNss1, + RadioTapVhtMcsNss mcsNss2, + RadioTapVhtMcsNss mcsNss3, + RadioTapVhtMcsNss mcsNss4, + RadioTapVhtCoding coding, + byte groupId, + ushort partialAid) + { + Known = known; + Flags = flags; + Bandwidth = bandwidth; + McsNss1 = mcsNss1; + McsNss2 = mcsNss2; + McsNss3 = mcsNss3; + McsNss4 = mcsNss4; + Coding = coding; + GroupId = groupId; + PartialAid = partialAid; } + /// Type of the field + public override RadioTapType FieldType => RadioTapType.VeryHighThroughput; + /// - /// Rate field + /// Gets the length of the field data. /// - public class RateRadioTapField : RadioTapField - { - /// - /// Constructor - /// - /// - /// A - /// - public RateRadioTapField(BinaryReader br) - { - var u8 = br.ReadByte(); - RateMbps = 0.5 * (u8 & 0x7f); - } + /// + /// The length. + /// + public override ushort Length => 12; - /// - /// Initializes a new instance of the class. - /// - public RateRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Rate mbps. - /// - public RateRadioTapField(double rateMbps) - { - RateMbps = rateMbps; - } + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => 2; - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Rate; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Rate in Mbps - /// - public double RateMbps { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = (byte) (RateMbps / 0.5); - } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"RateMbps {RateMbps}"; - } + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + EndianBitConverter.Little.CopyBytes((ushort)Known, dest, offset); + EndianBitConverter.Little.CopyBytes((byte)Flags, dest, offset + 2); + EndianBitConverter.Little.CopyBytes((byte)Bandwidth, dest, offset + 3); + EndianBitConverter.Little.CopyBytes((byte)McsNss1, dest, offset + 4); + EndianBitConverter.Little.CopyBytes((byte)McsNss2, dest, offset + 5); + EndianBitConverter.Little.CopyBytes((byte)McsNss3, dest, offset + 6); + EndianBitConverter.Little.CopyBytes((byte)McsNss4, dest, offset + 7); + EndianBitConverter.Little.CopyBytes((byte)Coding, dest, offset + 8); + EndianBitConverter.Little.CopyBytes(GroupId, dest, offset + 9); + EndianBitConverter.Little.CopyBytes(PartialAid, dest, offset + 10); } /// - /// Db antenna signal + /// ToString() override /// - public class DbAntennaSignalRadioTapField : RadioTapField + /// + /// A + /// + public override string ToString() { - /// - /// Constructor - /// - /// - /// A - /// - public DbAntennaSignalRadioTapField(BinaryReader br) - { - SignalStrengthdB = br.ReadByte(); - } + return $"Known {Known}, Flags {Flags}, Bandwidth {Bandwidth}, McsNss1 {McsNss1}, McsNss2 {McsNss2}, McsNss3 {McsNss3}, McsNss4 {McsNss4}, Coding {Coding}, GroupId {GroupId}, PartialAid {PartialAid}"; + } +} - /// - /// Initializes a new instance of the class. - /// - public DbAntennaSignalRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Signal strength in dB - /// - public DbAntennaSignalRadioTapField(byte signalStrengthdB) - { - SignalStrengthdB = signalStrengthdB; - } +/// +/// The presence of this field indicates that the frame was received or transmitted using the HE PHY (Wi-Fi 6 / ieee802.11ax). +/// +public class HighEfficiencyRadioTapField : RadioTapField +{ + /// + /// Indicates the presence of known fields as well as the HE PPDU format + /// + public RadioTapHighEfficiencyData1 Data1 { get; set; } - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbAntennaSignal; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Signal strength in dB - /// - public byte SignalStrengthdB { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = SignalStrengthdB; - } + /// + /// Indicates the presence of known fields as well as the PRI/SEC 80MHz field + /// + public RadioTapHighEfficiencyData2 Data2 { get; set; } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"SignalStrengthdB {SignalStrengthdB}"; - } - } + /// + /// Indicates the presence of additional known fields as well as the value of pri/sec 80MHz + /// + public RadioTapHighEfficiencyData3 Data3 { get; set; } /// - /// Antenna noise in dB + /// Data depends on the PPDU Format (See Data.HePpduFormat) /// - public class DbAntennaNoiseRadioTapField : RadioTapField - { - /// - /// Constructor - /// - /// - /// A - /// - public DbAntennaNoiseRadioTapField(BinaryReader br) - { - AntennaNoisedB = br.ReadByte(); - } + public ushort Data4 { get; set; } - /// - /// Initializes a new instance of the class. - /// - public DbAntennaNoiseRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Antenna signal noise in dB. - /// - public DbAntennaNoiseRadioTapField(byte antennaNoisedB) - { - AntennaNoisedB = antennaNoisedB; - } + /// + /// Data fields where the availability depends on the known flags from Data1/Data2 + /// + public RadioTapHighEfficiencyData5 Data5 { get; set; } - /// - /// Antenna noise in dB - /// - public byte AntennaNoisedB { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbAntennaNoise; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = AntennaNoisedB; - } + /// + /// Data fields where the availability depends on the known flags from Data1/Data2 + /// + public RadioTapHighEfficiencyData6 Data6 { get; set; } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"AntennaNoisedB {AntennaNoisedB}"; - } + /// + /// Constructor + /// + /// + /// A + /// + public HighEfficiencyRadioTapField(BinaryReader br) + { + Data1 = (RadioTapHighEfficiencyData1)br.ReadUInt16(); + Data2 = (RadioTapHighEfficiencyData2)br.ReadUInt16(); + Data3 = (RadioTapHighEfficiencyData3)br.ReadUInt16(); + Data4 = br.ReadUInt16(); + Data5 = (RadioTapHighEfficiencyData5)br.ReadUInt16(); + Data6 = (RadioTapHighEfficiencyData6)br.ReadUInt16(); } /// - /// Antenna field + /// Initializes a new instance of the class. /// - public class AntennaRadioTapField : RadioTapField + public HighEfficiencyRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + public HighEfficiencyRadioTapField(RadioTapHighEfficiencyData1 data1, RadioTapHighEfficiencyData2 data2, RadioTapHighEfficiencyData3 data3, ushort data4, RadioTapHighEfficiencyData5 data5, RadioTapHighEfficiencyData6 data6) { - /// - /// Constructor - /// - /// - /// A - /// - public AntennaRadioTapField(BinaryReader br) - { - Antenna = br.ReadByte(); - } + Data1 = data1; + Data2 = data2; + Data3 = data3; + Data4 = data4; + Data5 = data5; + Data6 = data6; + } - /// - /// Initializes a new instance of the class. - /// - public AntennaRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Antenna index of the Rx/Tx antenna for this packet. The first antenna is antenna 0. - /// - public AntennaRadioTapField(byte antenna) - { - Antenna = antenna; - } + /// Type of the field + public override RadioTapType FieldType => RadioTapType.HighEfficiency; - /// - /// Antenna number - /// - public byte Antenna { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Antenna; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = Antenna; - } + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 12; - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"Antenna {Antenna}"; - } - } + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => 2; /// - /// Antenna signal in dBm + /// Copies the field data to the destination buffer at the specified offset. /// - public class DbmAntennaSignalRadioTapField : RadioTapField + public override void CopyTo(byte[] dest, int offset) { - /// - /// Constructor - /// - /// - /// A - /// - public DbmAntennaSignalRadioTapField(BinaryReader br) - { - AntennaSignalDbm = br.ReadSByte(); - } - - /// - /// Initializes a new instance of the class. - /// - public DbmAntennaSignalRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Antenna signal power in dB. - /// - public DbmAntennaSignalRadioTapField(sbyte antennaSignalDbm) - { - AntennaSignalDbm = antennaSignalDbm; - } - - /// - /// Antenna signal in dBm - /// - public sbyte AntennaSignalDbm { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbmAntennaSignal; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = (byte) AntennaSignalDbm; - } - - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"AntennaSignalDbm {AntennaSignalDbm}"; - } + EndianBitConverter.Little.CopyBytes((ushort)Data1, dest, offset); + EndianBitConverter.Little.CopyBytes((ushort)Data2, dest, offset + 2); + EndianBitConverter.Little.CopyBytes((ushort)Data3, dest, offset + 4); + EndianBitConverter.Little.CopyBytes(Data4, dest, offset + 6); + EndianBitConverter.Little.CopyBytes((ushort)Data5, dest, offset + 8); + EndianBitConverter.Little.CopyBytes((ushort)Data6, dest, offset + 10); } /// - /// Antenna noise in dBm + /// ToString() override /// - public class DbmAntennaNoiseRadioTapField : RadioTapField + /// + /// A + /// + public override string ToString() { - /// - /// Constructor - /// - /// - /// A - /// - public DbmAntennaNoiseRadioTapField(BinaryReader br) - { - AntennaNoisedBm = br.ReadSByte(); - } - - /// - /// Initializes a new instance of the class. - /// - public DbmAntennaNoiseRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Antenna noise in dBm. - /// - public DbmAntennaNoiseRadioTapField(sbyte antennaNoisedBm) - { - AntennaNoisedBm = antennaNoisedBm; - } - - /// - /// Antenna noise in dBm - /// - public sbyte AntennaNoisedBm { get; set; } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbmAntennaNoise; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = (byte) AntennaNoisedBm; - } - - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"AntennaNoisedBm {AntennaNoisedBm}"; - } + return $"Data1 {Data1}, Data2 {Data2}, Data3 {Data3}, Data4 {Data4}, Data5 {Data5}, Data6 {Data6}"; } +} +public class McsRadioTapField : RadioTapField +{ /// - /// Lock quality + /// Indicates which information is known /// - public class LockQualityRadioTapField : RadioTapField - { - /// - /// Constructor - /// - /// - /// A - /// - public LockQualityRadioTapField(BinaryReader br) - { - SignalQuality = br.ReadUInt16(); - } + public RadioTapMcsKnown Known { get; set; } - /// - /// Initializes a new instance of the class. - /// - public LockQualityRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Signal quality. - /// - public LockQualityRadioTapField(ushort signalQuality) - { - SignalQuality = signalQuality; - } + /// + /// Indicates which information is known + /// + public RadioTapMcsFlags Flags { get; set; } - /// Type of the field - public override RadioTapType FieldType => RadioTapType.LockQuality; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 2; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Signal quality - /// - public ushort SignalQuality { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - EndianBitConverter.Little.CopyBytes(SignalQuality, dest, offset); - } + /// + /// Modulation and Coding Scheme + /// Determines the modulation type and coding rate. + /// + public byte Mcs { get; set; } - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"SignalQuality {SignalQuality}"; - } + /// + /// Constructor + /// + /// + /// A + /// + public McsRadioTapField(BinaryReader br) + { + Known = (RadioTapMcsKnown)br.ReadByte(); + Flags = (RadioTapMcsFlags)br.ReadByte(); + Mcs = br.ReadByte(); } /// - /// Tsft radio tap field + /// Initializes a new instance of the class. + /// + public McsRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// Known information + /// MCS Flags + /// Known information /// - public class TsftRadioTapField : RadioTapField + public McsRadioTapField(RadioTapMcsKnown known, RadioTapMcsFlags flags, byte mcs) { - /// - /// Constructor - /// - /// - /// A - /// - public TsftRadioTapField(BinaryReader br) - { - TimestampUsec = br.ReadUInt64(); - } + Known = known; + Flags = flags; + Mcs = mcs; + } - /// - /// Initializes a new instance of the class. - /// - public TsftRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Value in microseconds of the Time Synchronization Function timer - /// - public TsftRadioTapField(ulong timestampUsec) - { - TimestampUsec = timestampUsec; - } + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Mcs; - /// Type of the field - public override RadioTapType FieldType => RadioTapType.Tsft; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 8; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Timestamp in microseconds - /// - public ulong TimestampUsec { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - EndianBitConverter.Little.CopyBytes(TimestampUsec, dest, offset); - } + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 3; - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"TimestampUsec {TimestampUsec}"; - } - } + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => 1; /// - /// Contains properties about the received from. + /// Copies the field data to the destination buffer at the specified offset. /// - public class RxFlagsRadioTapField : RadioTapField + public override void CopyTo(byte[] dest, int offset) { - /// - /// Constructor - /// - /// - /// A - /// - public RxFlagsRadioTapField(BinaryReader br) - { - var flags = br.ReadUInt16(); - PlcpCrcCheckFailed = (flags & 0x2) == 0x2; - } - - /// - /// Initializes a new instance of the class. - /// - public RxFlagsRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// PLCP CRC check failed. - /// - public RxFlagsRadioTapField(bool plcpCrcCheckFailed) - { - PlcpCrcCheckFailed = plcpCrcCheckFailed; - } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.RxFlags; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 2; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Gets or sets a value indicating whether the frame failed the PLCP CRC check. - /// - /// - /// true if the PLCP CRC check failed; otherwise, false. - /// - public bool PlcpCrcCheckFailed { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - var flags = (ushort) (PlcpCrcCheckFailed ? 0x2 : 0x0); - EndianBitConverter.Little.CopyBytes(flags, dest, offset); - } - - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"PlcpCrcCheckFailed {PlcpCrcCheckFailed}"; - } + EndianBitConverter.Little.CopyBytes((byte)Known, dest, offset); + EndianBitConverter.Little.CopyBytes((byte)Flags, dest, offset + 1); + EndianBitConverter.Little.CopyBytes((byte)Mcs, dest, offset + 2); } /// - /// Transmit power expressed as unitless distance from max - /// power set at factory calibration. 0 is max power. - /// Monotonically nondecreasing with lower power levels. + /// ToString() override /// - public class TxAttenuationRadioTapField : RadioTapField + /// + /// A + /// + public override string ToString() { - /// - /// Constructor - /// - /// - /// A - /// - public TxAttenuationRadioTapField(BinaryReader br) - { - TxPower = -br.ReadUInt16(); - } - - /// - /// Initializes a new instance of the class. - /// - public TxAttenuationRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. - /// - public TxAttenuationRadioTapField(int txPower) - { - TxPower = txPower; - } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.TxAttenuation; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 2; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Transmit power - /// - public int TxPower { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - var absValue = (ushort) Math.Abs(TxPower); - EndianBitConverter.Little.CopyBytes(absValue, dest, offset); - } - - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"TxPower {TxPower}"; - } + return $"Known {Known}, Flags {Flags}, Mcs {Mcs}"; } +} +/// +/// Channel field +/// +public class ChannelRadioTapField : RadioTapField +{ /// - /// Transmit power expressed as decibel distance from max power - /// set at factory calibration. 0 is max power. Monotonically - /// nondecreasing with lower power levels. + /// Constructor /// - public class DbTxAttenuationRadioTapField : RadioTapField + /// + /// A + /// + public ChannelRadioTapField(BinaryReader br) { - /// - /// Constructor - /// - /// - /// A - /// - public DbTxAttenuationRadioTapField(BinaryReader br) - { - TxPowerdB = -br.ReadUInt16(); - } - - /// - /// Initializes a new instance of the class. - /// - public DbTxAttenuationRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. - /// - public DbTxAttenuationRadioTapField(int txPowerdB) - { - TxPowerdB = txPowerdB; - } - - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbTxAttenuation; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 2; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Transmit power - /// - public int TxPowerdB { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - var absValue = (ushort) Math.Abs(TxPowerdB); - EndianBitConverter.Little.CopyBytes(absValue, dest, offset); - } - - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"TxPowerdB {TxPowerdB}"; - } + FrequencyMHz = br.ReadUInt16(); + Channel = ChannelFromFrequencyMHz(FrequencyMHz); + Flags = (RadioTapChannelFlags) br.ReadUInt16(); } /// - /// Transmit power expressed as dBm (decibels from a 1 milliwatt - /// reference). This is the absolute power level measured at - /// the antenna port. + /// Initializes a new instance of the class. + /// + public ChannelRadioTapField() + { } + + /// + /// Initializes a new instance of the class. /// - public class DbmTxPowerRadioTapField : RadioTapField + /// Tx/Rx Frequency in MHz. + /// Flags. + public ChannelRadioTapField(ushort frequencyMhz, RadioTapChannelFlags flags) { - /// - /// Constructor - /// - /// - /// A - /// - public DbmTxPowerRadioTapField(BinaryReader br) - { - TxPowerdBm = br.ReadSByte(); - } + FrequencyMHz = frequencyMhz; + Channel = ChannelFromFrequencyMHz(FrequencyMHz); + Flags = flags; + } - /// - /// Initializes a new instance of the class. - /// - public DbmTxPowerRadioTapField() - { } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Transmit power expressed as dBm (decibels from a 1 milliwatt reference). - /// - public DbmTxPowerRadioTapField(sbyte txPowerdBm) - { - TxPowerdBm = txPowerdBm; - } + /// + /// Channel number derived from frequency + /// + public int Channel { get; set; } - /// Type of the field - public override RadioTapType FieldType => RadioTapType.DbmTxPower; - - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public override ushort Length => 1; - - /// - /// Gets the alignment. - /// - /// The alignment. - public override ushort Alignment => Length; - - /// - /// Tx power in dBm - /// - public sbyte TxPowerdBm { get; set; } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public override void CopyTo(byte[] dest, int offset) - { - dest[offset] = (byte) TxPowerdBm; - } + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Channel; - /// - /// ToString() override - /// - /// - /// A - /// - public override string ToString() - { - return $"TxPowerdBm {TxPowerdBm}"; - } - } + /// + /// Gets the channel flags. + /// + public RadioTapChannelFlags Flags { get; } /// - /// Abstract class for all radio tap fields + /// Frequency in MHz /// - public abstract class RadioTapField - { - /// Type of the field - public abstract RadioTapType FieldType { get; } + public ushort FrequencyMHz { get; set; } - /// - /// Gets the length of the field data. - /// - /// - /// The length. - /// - public abstract ushort Length { get; } + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 4; - /// - /// Gets the alignment length for this field. - /// - /// The alignment. - public abstract ushort Alignment { get; } + /// + /// Note that the alignment of the channel field is two bytes as it is comprised of two 2 byte fields + /// + /// The alignment. + public override ushort Alignment => 2; - /// - /// Based on the radiotap bitfield determine the fieldAlignment - /// - /// true, if field was found, false otherwise. - /// Bit index. - /// Field length. - public static bool FieldAlignment(int bitIndex, out ushort fieldAlignment) + /// + /// Convert a frequency to a channel + /// + /// + /// There is some overlap between the 802.11b/g channel numbers and the 802.11a channel numbers. This means that while a particular frequncy will only + /// ever map to single channel number the same channel number may be returned for more than one frequency. At present this affects channel numbers 8 and 12. + /// + /// + /// A + /// + /// + /// A + /// + public static int ChannelFromFrequencyMHz(int frequencyMHz) + { + switch (frequencyMHz) { - // leverage the existing Parse() routine with a dummy buffer to decode a - // RadioTapField instance so we can retrieve its length - var emptyBuffer = new byte[32]; - var memoryStream = new MemoryStream(emptyBuffer); - var binaryReader = new BinaryReader(memoryStream); - - var field = Parse(bitIndex, binaryReader); - if (field != null) + //802.11 bg channel numbers + case 2412: { - fieldAlignment = field.Alignment; - return true; + return 1; } - - fieldAlignment = 0; - return false; - } - - /// - /// Parse a radio tap field, indicated by bitIndex, from a given BinaryReader - /// - /// - /// A - /// - /// - /// A - /// - /// - /// A - /// - public static RadioTapField Parse(int bitIndex, BinaryReader br) - { - var type = (RadioTapType) bitIndex; - switch (type) - { - case RadioTapType.Flags: - { - return new FlagsRadioTapField(br); - } - case RadioTapType.Rate: - { - return new RateRadioTapField(br); - } - case RadioTapType.DbAntennaSignal: - { - return new DbAntennaSignalRadioTapField(br); - } - case RadioTapType.DbAntennaNoise: - { - return new DbAntennaNoiseRadioTapField(br); - } - case RadioTapType.Antenna: - { - return new AntennaRadioTapField(br); - } - case RadioTapType.DbmAntennaSignal: - { - return new DbmAntennaSignalRadioTapField(br); - } - case RadioTapType.DbmAntennaNoise: - { - return new DbmAntennaNoiseRadioTapField(br); - } - case RadioTapType.Channel: - { - return new ChannelRadioTapField(br); - } - case RadioTapType.Fhss: - { - return new FhssRadioTapField(br); - } - case RadioTapType.LockQuality: - { - return new LockQualityRadioTapField(br); - } - case RadioTapType.TxAttenuation: - { - return new TxAttenuationRadioTapField(br); - } - case RadioTapType.DbTxAttenuation: - { - return new DbTxAttenuationRadioTapField(br); - } - case RadioTapType.DbmTxPower: - { - return new DbmTxPowerRadioTapField(br); - } - case RadioTapType.Tsft: - { - return new TsftRadioTapField(br); - } - case RadioTapType.RxFlags: - { - return new RxFlagsRadioTapField(br); - } - default: - { - //the RadioTap fields are extendable so there may be some we dont know about - return null; - } + case 2417: + { + return 2; } - } - - /// - /// Copies the field data to the destination buffer at the specified offset. - /// - public abstract void CopyTo(byte[] dest, int offset); - } \ No newline at end of file + case 2422: + { + return 3; + } + case 2427: + { + return 4; + } + case 2432: + { + return 5; + } + case 2437: + { + return 6; + } + case 2442: + { + return 7; + } + case 2447: + { + return 8; + } + case 2452: + { + return 9; + } + case 2457: + { + return 10; + } + case 2462: + { + return 11; + } + case 2467: + { + return 12; + } + case 2472: + { + return 13; + } + case 2484: + { + return 14; + } + //802.11 a channel numbers + case 4920: + { + return 240; + } + case 4940: + { + return 244; + } + case 4960: + { + return 248; + } + case 4980: + { + return 252; + } + case 5040: + { + return 8; + } + case 5060: + { + return 12; + } + case 5080: + { + return 16; + } + case 5170: + { + return 34; + } + case 5180: + { + return 36; + } + case 5190: + { + return 38; + } + case 5200: + { + return 40; + } + case 5210: + { + return 42; + } + case 5220: + { + return 44; + } + case 5230: + { + return 46; + } + case 5240: + { + return 48; + } + case 5260: + { + return 52; + } + case 5280: + { + return 56; + } + case 5300: + { + return 60; + } + case 5320: + { + return 64; + } + case 5500: + { + return 100; + } + case 5520: + { + return 104; + } + case 5540: + { + return 108; + } + case 5560: + { + return 112; + } + case 5580: + { + return 116; + } + case 5600: + { + return 120; + } + case 5620: + { + return 124; + } + case 5640: + { + return 128; + } + case 5660: + { + return 132; + } + case 5680: + { + return 136; + } + case 5700: + { + return 140; + } + case 5745: + { + return 149; + } + case 5765: + { + return 153; + } + case 5785: + { + return 157; + } + case 5805: + { + return 161; + } + case 5825: + { + return 165; + } + default: + { + return 0; + } + } + } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + EndianBitConverter.Little.CopyBytes(FrequencyMHz, dest, offset); + EndianBitConverter.Little.CopyBytes((ushort) Flags, dest, offset + 2); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"FrequencyMHz {FrequencyMHz}, Channel {Channel}, Flags {Flags}"; + } +} + +/// +/// Fhss radio tap field +/// +public class FhssRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public FhssRadioTapField(BinaryReader br) + { + var u16 = br.ReadUInt16(); + + ChannelHoppingSet = (byte) (u16 & 0xff); + Pattern = (byte) ((u16 >> 8) & 0xff); + } + + /// + /// Initializes a new instance of the class. + /// + public FhssRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Channel hopping set. + /// + /// + /// Channel hopping pattern. + /// + public FhssRadioTapField(byte channelHoppingSet, byte pattern) + { + ChannelHoppingSet = channelHoppingSet; + Pattern = pattern; + } + + /// + /// Hop set + /// + public byte ChannelHoppingSet { get; set; } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Fhss; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 2; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Hop pattern + /// + public byte Pattern { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = ChannelHoppingSet; + dest[offset + 1] = Pattern; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"ChannelHoppingSet {ChannelHoppingSet}, Pattern {Pattern}"; + } +} + +/// +/// Radio tap flags +/// +public class FlagsRadioTapField : RadioTapField +{ + /// + /// Flags set + /// + public RadioTapFlags Flags; + + /// + /// Constructor + /// + /// + /// A + /// + public FlagsRadioTapField(BinaryReader br) + { + var u8 = br.ReadByte(); + Flags = (RadioTapFlags) u8; + } + + /// + /// Initializes a new instance of the class. + /// + public FlagsRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Flags. + /// + public FlagsRadioTapField(RadioTapFlags flags) + { + Flags = flags; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Flags; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = (byte) Flags; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"Flags {Flags}"; + } +} + +/// +/// Rate field +/// +public class RateRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public RateRadioTapField(BinaryReader br) + { + var u8 = br.ReadByte(); + RateMbps = 0.5 * (u8 & 0x7f); + } + + /// + /// Initializes a new instance of the class. + /// + public RateRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Rate mbps. + /// + public RateRadioTapField(double rateMbps) + { + RateMbps = rateMbps; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Rate; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Rate in Mbps + /// + public double RateMbps { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = (byte) (RateMbps / 0.5); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"RateMbps {RateMbps}"; + } +} + +/// +/// Db antenna signal +/// +public class DbAntennaSignalRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbAntennaSignalRadioTapField(BinaryReader br) + { + SignalStrengthdB = br.ReadByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbAntennaSignalRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Signal strength in dB + /// + public DbAntennaSignalRadioTapField(byte signalStrengthdB) + { + SignalStrengthdB = signalStrengthdB; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbAntennaSignal; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Signal strength in dB + /// + public byte SignalStrengthdB { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = SignalStrengthdB; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"SignalStrengthdB {SignalStrengthdB}"; + } +} + +/// +/// Antenna noise in dB +/// +public class DbAntennaNoiseRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbAntennaNoiseRadioTapField(BinaryReader br) + { + AntennaNoisedB = br.ReadByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbAntennaNoiseRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Antenna signal noise in dB. + /// + public DbAntennaNoiseRadioTapField(byte antennaNoisedB) + { + AntennaNoisedB = antennaNoisedB; + } + + /// + /// Antenna noise in dB + /// + public byte AntennaNoisedB { get; set; } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbAntennaNoise; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = AntennaNoisedB; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"AntennaNoisedB {AntennaNoisedB}"; + } +} + +/// +/// Antenna field +/// +public class AntennaRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public AntennaRadioTapField(BinaryReader br) + { + Antenna = br.ReadByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public AntennaRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Antenna index of the Rx/Tx antenna for this packet. The first antenna is antenna 0. + /// + public AntennaRadioTapField(byte antenna) + { + Antenna = antenna; + } + + /// + /// Antenna number + /// + public byte Antenna { get; set; } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Antenna; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = Antenna; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"Antenna {Antenna}"; + } +} + +/// +/// Antenna signal in dBm +/// +public class DbmAntennaSignalRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbmAntennaSignalRadioTapField(BinaryReader br) + { + AntennaSignalDbm = br.ReadSByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbmAntennaSignalRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Antenna signal power in dB. + /// + public DbmAntennaSignalRadioTapField(sbyte antennaSignalDbm) + { + AntennaSignalDbm = antennaSignalDbm; + } + + /// + /// Antenna signal in dBm + /// + public sbyte AntennaSignalDbm { get; set; } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbmAntennaSignal; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = (byte) AntennaSignalDbm; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"AntennaSignalDbm {AntennaSignalDbm}"; + } +} + +/// +/// Antenna noise in dBm +/// +public class DbmAntennaNoiseRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbmAntennaNoiseRadioTapField(BinaryReader br) + { + AntennaNoisedBm = br.ReadSByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbmAntennaNoiseRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Antenna noise in dBm. + /// + public DbmAntennaNoiseRadioTapField(sbyte antennaNoisedBm) + { + AntennaNoisedBm = antennaNoisedBm; + } + + /// + /// Antenna noise in dBm + /// + public sbyte AntennaNoisedBm { get; set; } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbmAntennaNoise; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = (byte) AntennaNoisedBm; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"AntennaNoisedBm {AntennaNoisedBm}"; + } +} + +/// +/// Lock quality +/// +public class LockQualityRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public LockQualityRadioTapField(BinaryReader br) + { + SignalQuality = br.ReadUInt16(); + } + + /// + /// Initializes a new instance of the class. + /// + public LockQualityRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Signal quality. + /// + public LockQualityRadioTapField(ushort signalQuality) + { + SignalQuality = signalQuality; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.LockQuality; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 2; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Signal quality + /// + public ushort SignalQuality { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + EndianBitConverter.Little.CopyBytes(SignalQuality, dest, offset); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"SignalQuality {SignalQuality}"; + } +} + +/// +/// Tsft radio tap field +/// +public class TsftRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public TsftRadioTapField(BinaryReader br) + { + TimestampUsec = br.ReadUInt64(); + } + + /// + /// Initializes a new instance of the class. + /// + public TsftRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Value in microseconds of the Time Synchronization Function timer + /// + public TsftRadioTapField(ulong timestampUsec) + { + TimestampUsec = timestampUsec; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.Tsft; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 8; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Timestamp in microseconds + /// + public ulong TimestampUsec { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + EndianBitConverter.Little.CopyBytes(TimestampUsec, dest, offset); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"TimestampUsec {TimestampUsec}"; + } +} + +/// +/// Contains properties about the received from. +/// +public class RxFlagsRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public RxFlagsRadioTapField(BinaryReader br) + { + var flags = br.ReadUInt16(); + PlcpCrcCheckFailed = (flags & 0x2) == 0x2; + } + + /// + /// Initializes a new instance of the class. + /// + public RxFlagsRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// PLCP CRC check failed. + /// + public RxFlagsRadioTapField(bool plcpCrcCheckFailed) + { + PlcpCrcCheckFailed = plcpCrcCheckFailed; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.RxFlags; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 2; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Gets or sets a value indicating whether the frame failed the PLCP CRC check. + /// + /// + /// true if the PLCP CRC check failed; otherwise, false. + /// + public bool PlcpCrcCheckFailed { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + var flags = (ushort) (PlcpCrcCheckFailed ? 0x2 : 0x0); + EndianBitConverter.Little.CopyBytes(flags, dest, offset); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"PlcpCrcCheckFailed {PlcpCrcCheckFailed}"; + } +} + +/// +/// Transmit power expressed as unitless distance from max +/// power set at factory calibration. 0 is max power. +/// Monotonically nondecreasing with lower power levels. +/// +public class TxAttenuationRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public TxAttenuationRadioTapField(BinaryReader br) + { + TxPower = -br.ReadUInt16(); + } + + /// + /// Initializes a new instance of the class. + /// + public TxAttenuationRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. + /// + public TxAttenuationRadioTapField(int txPower) + { + TxPower = txPower; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.TxAttenuation; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 2; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Transmit power + /// + public int TxPower { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + var absValue = (ushort) Math.Abs(TxPower); + EndianBitConverter.Little.CopyBytes(absValue, dest, offset); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"TxPower {TxPower}"; + } +} + +/// +/// Transmit power expressed as decibel distance from max power +/// set at factory calibration. 0 is max power. Monotonically +/// nondecreasing with lower power levels. +/// +public class DbTxAttenuationRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbTxAttenuationRadioTapField(BinaryReader br) + { + TxPowerdB = -br.ReadUInt16(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbTxAttenuationRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. + /// + public DbTxAttenuationRadioTapField(int txPowerdB) + { + TxPowerdB = txPowerdB; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbTxAttenuation; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 2; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Transmit power + /// + public int TxPowerdB { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + var absValue = (ushort) Math.Abs(TxPowerdB); + EndianBitConverter.Little.CopyBytes(absValue, dest, offset); + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"TxPowerdB {TxPowerdB}"; + } +} + +/// +/// Transmit power expressed as dBm (decibels from a 1 milliwatt +/// reference). This is the absolute power level measured at +/// the antenna port. +/// +public class DbmTxPowerRadioTapField : RadioTapField +{ + /// + /// Constructor + /// + /// + /// A + /// + public DbmTxPowerRadioTapField(BinaryReader br) + { + TxPowerdBm = br.ReadSByte(); + } + + /// + /// Initializes a new instance of the class. + /// + public DbmTxPowerRadioTapField() + { } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Transmit power expressed as dBm (decibels from a 1 milliwatt reference). + /// + public DbmTxPowerRadioTapField(sbyte txPowerdBm) + { + TxPowerdBm = txPowerdBm; + } + + /// Type of the field + public override RadioTapType FieldType => RadioTapType.DbmTxPower; + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public override ushort Length => 1; + + /// + /// Gets the alignment. + /// + /// The alignment. + public override ushort Alignment => Length; + + /// + /// Tx power in dBm + /// + public sbyte TxPowerdBm { get; set; } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public override void CopyTo(byte[] dest, int offset) + { + dest[offset] = (byte) TxPowerdBm; + } + + /// + /// ToString() override + /// + /// + /// A + /// + public override string ToString() + { + return $"TxPowerdBm {TxPowerdBm}"; + } +} + +/// +/// Abstract class for all radio tap fields +/// +public abstract class RadioTapField +{ + /// Type of the field + public abstract RadioTapType FieldType { get; } + + /// + /// Gets the length of the field data. + /// + /// + /// The length. + /// + public abstract ushort Length { get; } + + /// + /// Gets the alignment length for this field. + /// + /// The alignment. + public abstract ushort Alignment { get; } + + /// + /// Based on the radiotap bitfield determine the fieldAlignment + /// + /// true, if field was found, false otherwise. + /// Bit index. + /// Field length. + public static bool FieldAlignment(int bitIndex, out ushort fieldAlignment) + { + // leverage the existing Parse() routine with a dummy buffer to decode a + // RadioTapField instance so we can retrieve its length + var emptyBuffer = new byte[32]; + var memoryStream = new MemoryStream(emptyBuffer); + var binaryReader = new BinaryReader(memoryStream); + + var field = Parse(bitIndex, binaryReader); + if (field != null) + { + fieldAlignment = field.Alignment; + return true; + } + + fieldAlignment = 0; + return false; + } + + /// + /// Parse a radio tap field, indicated by bitIndex, from a given BinaryReader + /// + /// + /// A + /// + /// + /// A + /// + /// + /// A + /// + public static RadioTapField Parse(int bitIndex, BinaryReader br) + { + var type = (RadioTapType) bitIndex; + switch (type) + { + case RadioTapType.Flags: + { + return new FlagsRadioTapField(br); + } + case RadioTapType.Rate: + { + return new RateRadioTapField(br); + } + case RadioTapType.DbAntennaSignal: + { + return new DbAntennaSignalRadioTapField(br); + } + case RadioTapType.DbAntennaNoise: + { + return new DbAntennaNoiseRadioTapField(br); + } + case RadioTapType.Antenna: + { + return new AntennaRadioTapField(br); + } + case RadioTapType.DbmAntennaSignal: + { + return new DbmAntennaSignalRadioTapField(br); + } + case RadioTapType.DbmAntennaNoise: + { + return new DbmAntennaNoiseRadioTapField(br); + } + case RadioTapType.Channel: + { + return new ChannelRadioTapField(br); + } + case RadioTapType.Fhss: + { + return new FhssRadioTapField(br); + } + case RadioTapType.LockQuality: + { + return new LockQualityRadioTapField(br); + } + case RadioTapType.TxAttenuation: + { + return new TxAttenuationRadioTapField(br); + } + case RadioTapType.DbTxAttenuation: + { + return new DbTxAttenuationRadioTapField(br); + } + case RadioTapType.DbmTxPower: + { + return new DbmTxPowerRadioTapField(br); + } + case RadioTapType.Tsft: + { + return new TsftRadioTapField(br); + } + case RadioTapType.RxFlags: + { + return new RxFlagsRadioTapField(br); + } + case RadioTapType.Mcs: + { + return new McsRadioTapField(br); + } + case RadioTapType.HighEfficiency: + { + return new HighEfficiencyRadioTapField(br); + } + case RadioTapType.VeryHighThroughput: + { + return new VeryHighThroughputRadioTapField(br); + } + default: + { + //the RadioTap fields are extendable so there may be some we dont know about + return null; + } + } + } + + /// + /// Copies the field data to the destination buffer at the specified offset. + /// + public abstract void CopyTo(byte[] dest, int offset); +} \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData1.cs b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData1.cs new file mode 100644 index 00000000..9aedc81a --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData1.cs @@ -0,0 +1,97 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +/// +/// Flags that indicate the presence of fields in the HE radio tap field as well as the HE PPDU Format +/// +[Flags] +public enum RadioTapHighEfficiencyData1 : ushort +{ + /// + /// HE PPDU Format: + /// 0=HE_SU + /// 1=HE_EXT_SU + /// 2=HE_MY + /// 3=HE_TRIG + /// + HePpduFormat = 0x0003, + + /// + /// BSS Color Known + /// + BssColorKnown = 0x0004, + + /// + /// Beam Change Known + /// + BeamChangeKnown = 0x0008, + + /// + /// UL/DL Known + /// + UlDlDown = 0x0010, + + /// + /// Data MCS Known + /// + DataMcsKnown = 0x0020, + + /// + /// Data DCM Known + /// + DataDcmKnown = 0x0040, + + /// + /// Coding Known + /// + CodingKnown = 0x0080, + + /// + /// LDPC extra symbol segment known + /// + LdpcExtraSymbolSegmentKnown = 0x0100, + + /// + /// STBC Known + /// + StbcKnown = 0x0200, + + /// + /// Spatial Reuse known (Spatial Reuse 1 for HE_TRIG format) + /// + SpatialReuseKnownKnown = 0x0400, + + /// + /// Spatial Reuse 2 known (HE_TRIG format), STA-ID known (HE_MU format) + /// + SpatialReuse2KnownKnown = 0x0800, + + /// + /// Spatial Reuse 3 known (HE_TRIG format) + /// + SpatialReuse3KnownKnown = 0x1000, + + /// + /// Spatial Reuse 4 known (HE_TRIG format) + /// + SpatialReuse4KnownKnown = 0x2000, + + /// + /// Data BW/RU allocation known + /// + DataBwRuAllocationKnown = 0x4000, + + /// + /// Doppler known + /// + DopplerKnown = 0x8000, +} diff --git a/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData2.cs b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData2.cs new file mode 100644 index 00000000..0c7439f8 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData2.cs @@ -0,0 +1,76 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +/// +/// Flags that indicate the presence of fields in the HE radio tap field as well as the +/// RU Allocation Offset and +/// +[Flags] +public enum RadioTapHighEfficiencyData2 : ushort +{ + /// + /// Pri/sec 80 MHz known + /// + PriSec80MHzKnown = 0x0001, + + /// + /// GI Known + /// + GiKnown = 0x0002, + + /// + /// Number of LTF symbols known + /// + NumberOfLtfSymbolsKnown = 0x0004, + + /// + /// Pre-FEC Padding Factor known + /// + PreFecPaddingFactorKnown = 0x0008, + + /// + /// TxBF known + /// + TxbfKnown = 0x0010, + + /// + /// PE Disambiguity known + /// + PeDisambiguityKnown = 0x0020, + + /// + /// TXOP known + /// + TxopKnown = 0x0040, + + /// + /// Midamble periodicity known + /// + MidamblePeriodicityKnown = 0x0080, + + /// + /// Bitmask for RU allocation offset + /// + RuAllocationOffset = 0x3f00, + + /// + /// RU allocation offset known + /// + RuAllocationOffsetKnown = 0x4000, + + /// + /// Pri/sec 80MHz. + /// 0 = primary + /// 1 = secondary + /// + PriSec80MHz = 0x8000, +} diff --git a/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData3.cs b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData3.cs new file mode 100644 index 00000000..4755c780 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData3.cs @@ -0,0 +1,57 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +[Flags] +public enum RadioTapHighEfficiencyData3 : ushort +{ + /// + /// BSS color bitmask + /// + BssColor = 0x003f, + + /// + /// Beam change bitmask + /// + BeamChange = 0x0040, + + /// + /// UL/DL bitmask + /// + UlDl = 0x0080, + + /// + /// Data MCS (not SIG-B MCS from HE-SIG-A for HE_MU format bitmask + /// + DataMcs = 0x0f00, + + /// + /// Data DCM (cf. data MCS) bitmask + /// + DataDcm = 0x1000, + + /// + /// Coding bitmask + /// 0=BCC + /// 1=LDPC + /// + Coding = 0x2000, + + /// + /// LDPC extra symbol segment + /// + LdpcExtraSymbolSegment = 0x4000, + + /// + /// STBC + /// + Stbc = 0x800 +} diff --git a/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData5.cs b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData5.cs new file mode 100644 index 00000000..9f8a1ff5 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData5.cs @@ -0,0 +1,75 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +[Flags] +public enum RadioTapHighEfficiencyData5 : ushort +{ + /// + /// Data Bandwidth/RU allocation bitmask + /// 0=20 + /// 1=40 + /// 2=80 + /// 3=160/80+80 + /// 4=26-tone RU + /// 5=52-tone RU + /// 6=106-tone RU + /// 7=242-tone RU + /// 8=484-tone RU + /// 9=996-tone RU + /// 10=2x996-tone RU + /// + DataBandwidth = 0x000f, + + /// + /// Guard Interval (GI) + /// 0=0.8us + /// 1=1.6us + /// 2=3.2us + /// 3=reserved + /// + Gi = 0x30, + + /// + /// LTF symbol size bitmask + /// 0=unknown + /// 1=1x + /// 2=2x + /// 3=4x + /// + LtfSymbolSize = 0x00c0, + + /// + /// Number of LTF symbols + /// 0=1x + /// 1=2x + /// 2=4x + /// 3=6x + /// 4=8x + /// 5-7=reserved + /// + NumberOfLtfSymbols = 0x0700, + + /// + /// Pre-FEC Padding Factor bitmask + /// + PreFecPaddingFactor = 0x3000, + + /// + /// TxBF bitmask + /// + Txbf = 0x4000, + + /// + /// PE Disambiguity + /// + PeDisambiguity = 0x8000 +} diff --git a/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData6.cs b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData6.cs new file mode 100644 index 00000000..e46b232e --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapHighEfficiencyData6.cs @@ -0,0 +1,42 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +[Flags] +public enum RadioTapHighEfficiencyData6 : ushort +{ + /// + /// NSTS (actual number of space-time streams, 0=unknown, 1=1, etc. + /// + Nsts = 0x000f, + + /// + /// Doppler value + /// + DopplerValue = 0x0010, + + /// + /// Reserved. + /// + Reserved = 0x00e0, + + /// + /// TXOP Value + /// + TxopValue = 0x7f00, + + /// + /// Midamble periodicity + /// 0=10 + /// 1=20 + /// + MidamblePeriodicity = 0x8000, +} \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapMcsFlags.cs b/PacketDotNet/Ieee80211/RadioTapMcsFlags.cs new file mode 100644 index 00000000..b68010aa --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapMcsFlags.cs @@ -0,0 +1,36 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + + /// + /// Channel flags + /// + [Flags] + public enum RadioTapMcsFlags : byte + { + /// Channel Width: 20MHz=0, 40MHz=1, 20L=2, 20U=3 + Bandwidth = 0x03, + + /// Guard Interval (GI): Long GI=0, Short GI=1 + GuardInterval = 0x04, + + /// HT Format: 0=Mixed, 1=Greenfield + HtFormat = 0x08, + + /// FEC Type: BCC=0, LDPC=1 + FecType = 0x10, + + /// Number of STBC Streams + NumberOfStbcStreams = 0x60, + + /// Number of extension spacial streams + Ness = 0x80 + } \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapMcsKnown.cs b/PacketDotNet/Ieee80211/RadioTapMcsKnown.cs new file mode 100644 index 00000000..66ca11a4 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapMcsKnown.cs @@ -0,0 +1,42 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + + /// + /// Known fields in the MCS radiko tap header + /// + [Flags] + public enum RadioTapMcsKnown : byte + { + /// Bandwidth + Bandwidth = 0x01, + + /// MCS index + McsIndexKnown = 0x02, + + /// Guard interval + GuardInterval = 0x04, + + /// HT Format + HtFormat = 0x08, + + /// FEC type + FecType = 0x10, + + /// STBC known + SbtcKnown = 0x20, + + /// Ness known (number of extension spatial streams) + NessKnown = 0x40, + + /// Bandwidth + NessData = 0x80, + } \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapType.cs b/PacketDotNet/Ieee80211/RadioTapType.cs index a7d07126..9b9e928a 100644 --- a/PacketDotNet/Ieee80211/RadioTapType.cs +++ b/PacketDotNet/Ieee80211/RadioTapType.cs @@ -132,6 +132,37 @@ public enum RadioTapType /// RxFlags = 14, + /// + /// IEEE80211_RADIOTAP_TX_FLAGS u_int16_t bitmap + /// Properties of transmitted frames. + /// + TxFlags = 15, + + /// + /// Indicates the MCS rate index as in IEEE_802.11n-2009 + /// + Mcs = 19, + + /// + /// The presence of this field indicates that the frame was received as part of an a-MPDU. + /// + AmpduStatus = 20, + + /// + /// VHT (802.11ac PHY) + /// + VeryHighThroughput = 21, + + /// + /// HE (802.11ax PHY) + /// + HighEfficiency = 23, + + /// + /// HE MU. MIMO RU tone mapping + /// + HighEfficiencyMu = 24, + /// /// Indicates that the flags bitmaps have been extended /// diff --git a/PacketDotNet/Ieee80211/RadioTapVhtBandwidth.cs b/PacketDotNet/Ieee80211/RadioTapVhtBandwidth.cs new file mode 100644 index 00000000..45fec691 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapVhtBandwidth.cs @@ -0,0 +1,145 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +namespace PacketDotNet.Ieee80211; + +/// +/// Indicates the bandwidth and side channel for a frame capture with VHT +/// +public enum RadioTapVhtBandwidth : byte +{ + /// + /// 20MHz bandwidth + /// + MHz20 = 0x00, + + /// + /// 40MHz bandwidth + /// + MHz40 = 0x01, + + /// + /// 40MHz bandwidth with 20L side band. Sideband index=0 + /// + MHz40Side20L = 2, + + /// + /// 40MHz bandwidth with 20U side band. Sideband index=1 + /// + MHz40Side20U = 3, + + /// + /// 80MHz bandwidth + /// + MHz80 = 4, + + /// + /// 80MHz with 40L side channel + /// + MHz80Side40L = 5, + + /// + /// 80MHz with 44U side channel + /// + MHz80Side40U = 6, + + /// + /// 80MHz with 20LL side channel + /// + MHz80Side20LL = 7, + + /// + /// 80MHz with 20LU side channel + /// + MHz80Side20LU = 8, + + /// + /// 80MHz with 20UL side channel + /// + MHz80Side20UL = 9, + + /// + /// 80MHz with 20UU side channel + /// + MHz80Side20UU = 10, + + /// + /// 160MHz bandwidth + /// + MHz160 = 11, + + /// + /// 160MHz with 80L side channel + /// + MHz160Side80L = 12, + + /// + /// 160MHz with 80U side channel + /// + MHz160Side80U = 13, + + /// + /// 160MHz with 40LL side channel + /// + MHz160Side40LL = 14, + + /// + /// 160MHz with 40LU side channel + /// + MHz160Side40LU = 15, + + /// + /// 160MHz with 40UL side channel + /// + MHz160Side40UL = 16, + + /// + /// 160MHz with 40UU side channel + /// + MHz160Side40UU = 17, + + /// + /// 160MHz with 20LLL side channel + /// + MHz160Side20LLL = 18, + + /// + /// 160MHz with 20LLU side channel + /// + MHz160Side20LLU = 19, + + /// + /// 160MHz with 20LUL side channel + /// + MHz160Side20LUL = 20, + + /// + /// 160MHz with 20LUU side channel + /// + MHz160Side20LUU = 21, + + /// + /// 160MHz with 20ULL side channel + /// + MHz160Side20ULL = 22, + + /// + /// 160MHz with 20ULU side channel + /// + MHz160Side20ULU = 23, + + /// + /// 160MHz with 20UUL side channel + /// + MHz160Side20UUL = 24, + + /// + /// 160MHz with 20UUU side channel + /// + MHz160Side20UUU = 25, +} \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapVhtCoding.cs b/PacketDotNet/Ieee80211/RadioTapVhtCoding.cs new file mode 100644 index 00000000..8c14ef7e --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapVhtCoding.cs @@ -0,0 +1,48 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +[Flags] +public enum RadioTapVhtCoding : byte +{ + /// + /// Coding for user 1 + /// 0: BCC + /// 1: LDPC + /// + CodingForUser1 = 0x01, + + /// + /// Coding for user 2 + /// 0: BCC + /// 1: LDPC + /// + CodingForUser2 = 0x02, + + /// + /// Coding for user 3 + /// 0: BCC + /// 1: LDPC + /// + CodingForUser3 = 0x03, + + /// + /// Coding for user 4 + /// 0: BCC + /// 1: LDPC + /// + CodingForUser4 = 0x04, + + /// + /// Unused. + /// + Unused = 0xf0 +} diff --git a/PacketDotNet/Ieee80211/RadioTapVhtFlags.cs b/PacketDotNet/Ieee80211/RadioTapVhtFlags.cs new file mode 100644 index 00000000..22427066 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapVhtFlags.cs @@ -0,0 +1,53 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +[Flags] +public enum RadioTapVhtFlags : byte +{ + /// + /// Space-time block coding. + /// Set to 0 if no spatial streams of any user has STBC. + /// Set to 1 if all spatial streams of all users have STBC. + /// + Stbc = 0x01, + + /// + /// Valid only for AP transmitters. + /// Set to 0 if STAs may doze during TXOP. + /// Set to 1 if STAs may not doze during TXOP or transmitter is non-AP. + /// + TxopPsNotAllowed = 0x02, + + /// + /// Set to 0 for long GI. + /// Set to 1 for short GI. + /// + GuardInterval = 0x04, + + /// + /// Valid only if short GI is used. + /// Set to 0 if NSYM mod 10 != 9 or short GI not used. + /// Set to 1 if NSYM mod 10 = 9. + /// + ShortGiNsymDisambiguation = 0x08, + + /// + /// Set to 1 if one or more users are using LDPC and the encoding process resulted in extra OFDM symbol(s). + /// Set to 0 otherwise. + /// + LdpcExtraOfdmSymbol = 0x10, + + /// + /// Valid only for SU PPDUs + /// + Beamformed = 0x20 +} diff --git a/PacketDotNet/Ieee80211/RadioTapVhtKnown.cs b/PacketDotNet/Ieee80211/RadioTapVhtKnown.cs new file mode 100644 index 00000000..7d4754f7 --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapVhtKnown.cs @@ -0,0 +1,63 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +/// +/// Indicates the precense of data fields +/// +[Flags] +public enum RadioTapVhtKnown : ushort +{ + /// + /// STBC Known + /// + StbcKnown = 0x0001, + + /// + /// TXOP PS Not Allowed Known + /// + TxopPsNotAllowedKnown = 0x0002, + + /// + /// Guard Interval (GI) Known + /// + GuardIntervalKnown = 0x0004, + + /// + /// Short GI NSYM Disambiguation Known + /// + ShortGiNsymDisambiguationKnown = 0x0008, + + /// + /// LDPC Extra OFDM Sybmol Known + /// + LdpcExtraOfdmSymbolKnown = 0x0010, + + /// + /// Beamformed Known + /// + BeamformedKnown = 0x0020, + + /// + /// Bandwidth Known + /// + BandwidthKnown = 0x0040, + + /// + /// Group ID Known + /// + GroupIdKnown = 0x0080, + + /// + /// Partial AID Known + /// + PartialAidKnown = 0x0100 +} \ No newline at end of file diff --git a/PacketDotNet/Ieee80211/RadioTapVhtMcsNss.cs b/PacketDotNet/Ieee80211/RadioTapVhtMcsNss.cs new file mode 100644 index 00000000..650581ff --- /dev/null +++ b/PacketDotNet/Ieee80211/RadioTapVhtMcsNss.cs @@ -0,0 +1,28 @@ +/* +This file is part of PacketDotNet. + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +using System; + +namespace PacketDotNet.Ieee80211; + +/// +/// MCS rate index and spatial streams for one user +/// +[Flags] +public enum RadioTapVhtMcsNss : byte +{ + /// + /// Number of Spatial Streams (1-8) + /// + Nss = 0x0f, + + /// + /// MCS rate index + /// + Mcs = 0xf0 +} diff --git a/Test/PacketType/Ieee80211/RadioTapFieldsTest.cs b/Test/PacketType/Ieee80211/RadioTapFieldsTest.cs index 677d808a..d854a499 100644 --- a/Test/PacketType/Ieee80211/RadioTapFieldsTest.cs +++ b/Test/PacketType/Ieee80211/RadioTapFieldsTest.cs @@ -4,204 +4,276 @@ namespace Test.PacketType.Ieee80211; - [TestFixture] - public class RadioTapFieldsTest +[TestFixture] +public class RadioTapFieldsTest +{ + [Test] + public void Test_AntennaRadioTapField() { - [Test] - public void Test_AntennaRadioTapField() - { - var field = new AntennaRadioTapField(0xAB); + var field = new AntennaRadioTapField(0xAB); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new AntennaRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new AntennaRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.Antenna, recreatedField.Antenna); - } + Assert.AreEqual(field.Antenna, recreatedField.Antenna); + } - [Test] - public void Test_ChannelRadioTapField() - { - var field = new ChannelRadioTapField(2142, RadioTapChannelFlags.Channel2Ghz | RadioTapChannelFlags.Ofdm); + [Test] + public void Test_ChannelRadioTapField() + { + var field = new ChannelRadioTapField(2142, RadioTapChannelFlags.Channel2Ghz | RadioTapChannelFlags.Ofdm); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new ChannelRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new ChannelRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.FrequencyMHz, recreatedField.FrequencyMHz); - Assert.AreEqual(field.Channel, recreatedField.Channel); - Assert.AreEqual(field.Flags, recreatedField.Flags); - } + Assert.AreEqual(field.FrequencyMHz, recreatedField.FrequencyMHz); + Assert.AreEqual(field.Channel, recreatedField.Channel); + Assert.AreEqual(field.Flags, recreatedField.Flags); + } - [Test] - public void Test_DbAntennaNoiseRadioTapField() - { - var field = new DbAntennaNoiseRadioTapField(0xAB); + [Test] + public void Test_DbAntennaNoiseRadioTapField() + { + var field = new DbAntennaNoiseRadioTapField(0xAB); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbAntennaNoiseRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbAntennaNoiseRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.AntennaNoisedB, recreatedField.AntennaNoisedB); - } + Assert.AreEqual(field.AntennaNoisedB, recreatedField.AntennaNoisedB); + } - [Test] - public void Test_DbAntennaSignalRadioTapField() - { - var field = new DbAntennaSignalRadioTapField(0x12); + [Test] + public void Test_DbAntennaSignalRadioTapField() + { + var field = new DbAntennaSignalRadioTapField(0x12); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbAntennaSignalRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbAntennaSignalRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.SignalStrengthdB, recreatedField.SignalStrengthdB); - } + Assert.AreEqual(field.SignalStrengthdB, recreatedField.SignalStrengthdB); + } - [Test] - public void Test_DbmAntennaNoiseRadioTapField() - { - var field = new DbmAntennaNoiseRadioTapField(127); + [Test] + public void Test_DbmAntennaNoiseRadioTapField() + { + var field = new DbmAntennaNoiseRadioTapField(127); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbmAntennaNoiseRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbmAntennaNoiseRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.AntennaNoisedBm, recreatedField.AntennaNoisedBm); - } + Assert.AreEqual(field.AntennaNoisedBm, recreatedField.AntennaNoisedBm); + } - [Test] - public void Test_DbmAntennaSignalRadioTapField() - { - var field = new DbmAntennaSignalRadioTapField(-128); + [Test] + public void Test_DbmAntennaSignalRadioTapField() + { + var field = new DbmAntennaSignalRadioTapField(-128); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbmAntennaSignalRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbmAntennaSignalRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.AntennaSignalDbm, recreatedField.AntennaSignalDbm); - } + Assert.AreEqual(field.AntennaSignalDbm, recreatedField.AntennaSignalDbm); + } - [Test] - public void Test_DbmTxPowerRadioTapField() - { - var field = new DbmTxPowerRadioTapField(100); + [Test] + public void Test_DbmTxPowerRadioTapField() + { + var field = new DbmTxPowerRadioTapField(100); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbmTxPowerRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbmTxPowerRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.TxPowerdBm, recreatedField.TxPowerdBm); - } + Assert.AreEqual(field.TxPowerdBm, recreatedField.TxPowerdBm); + } - [Test] - public void Test_DbTxAttenuationRadioTapField() - { - var field = new DbTxAttenuationRadioTapField(-1234); + [Test] + public void Test_DbTxAttenuationRadioTapField() + { + var field = new DbTxAttenuationRadioTapField(-1234); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new DbTxAttenuationRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new DbTxAttenuationRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.TxPowerdB, recreatedField.TxPowerdB); - } + Assert.AreEqual(field.TxPowerdB, recreatedField.TxPowerdB); + } - [Test] - public void Test_FhssRadioTapField() - { - var field = new FhssRadioTapField(5, 6); + [Test] + public void Test_FhssRadioTapField() + { + var field = new FhssRadioTapField(5, 6); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new FhssRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new FhssRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.ChannelHoppingSet, recreatedField.ChannelHoppingSet); - Assert.AreEqual(field.Pattern, recreatedField.Pattern); - } + Assert.AreEqual(field.ChannelHoppingSet, recreatedField.ChannelHoppingSet); + Assert.AreEqual(field.Pattern, recreatedField.Pattern); + } - [Test] - public void Test_FlagsRadioTapField() - { - var field = new FlagsRadioTapField(RadioTapFlags.ShortPreamble | RadioTapFlags.WepEncrypted); + [Test] + public void Test_FlagsRadioTapField() + { + var field = new FlagsRadioTapField(RadioTapFlags.ShortPreamble | RadioTapFlags.WepEncrypted); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new FlagsRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new FlagsRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.Flags, recreatedField.Flags); - } + Assert.AreEqual(field.Flags, recreatedField.Flags); + } - [Test] - public void Test_LockQualityRadioTapField() - { - var field = new LockQualityRadioTapField(0x1234); + [Test] + public void Test_LockQualityRadioTapField() + { + var field = new LockQualityRadioTapField(0x1234); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new LockQualityRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new LockQualityRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.SignalQuality, recreatedField.SignalQuality); - } + Assert.AreEqual(field.SignalQuality, recreatedField.SignalQuality); + } - [Test] - public void Test_RateRadioTapField() - { - var field = new RateRadioTapField(2); + [Test] + public void Test_RateRadioTapField() + { + var field = new RateRadioTapField(2); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new RateRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new RateRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.RateMbps, recreatedField.RateMbps); - } + Assert.AreEqual(field.RateMbps, recreatedField.RateMbps); + } - [Test] - public void Test_RxFlagsRadioTapField() - { - var field = new RxFlagsRadioTapField(true); + [Test] + public void Test_RxFlagsRadioTapField() + { + var field = new RxFlagsRadioTapField(true); + + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); + + var recreatedField = new RxFlagsRadioTapField(new BinaryReader(new MemoryStream(bytes))); + + Assert.AreEqual(field.PlcpCrcCheckFailed, recreatedField.PlcpCrcCheckFailed); + } + + [Test] + public void Test_TsftRadioTapField() + { + var field = new TsftRadioTapField(0x12345678); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new RxFlagsRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new TsftRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.PlcpCrcCheckFailed, recreatedField.PlcpCrcCheckFailed); - } + Assert.AreEqual(field.TimestampUsec, recreatedField.TimestampUsec); + } - [Test] - public void Test_TsftRadioTapField() - { - var field = new TsftRadioTapField(0x12345678); + [Test] + public void Test_TxAttenuationRadioTapField() + { + var field = new TxAttenuationRadioTapField(-4321); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new TsftRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new TxAttenuationRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.TimestampUsec, recreatedField.TimestampUsec); - } + Assert.AreEqual(field.TxPower, recreatedField.TxPower); + } - [Test] - public void Test_TxAttenuationRadioTapField() - { - var field = new TxAttenuationRadioTapField(-4321); + [Test] + public void Test_HighEfficiencyRadioTapField() + { + var field = new HighEfficiencyRadioTapField( + RadioTapHighEfficiencyData1.StbcKnown, + RadioTapHighEfficiencyData2.PeDisambiguityKnown, + RadioTapHighEfficiencyData3.Stbc | RadioTapHighEfficiencyData3.BssColor, + 4, + RadioTapHighEfficiencyData5.Gi | RadioTapHighEfficiencyData5.Txbf, + RadioTapHighEfficiencyData6.MidamblePeriodicity | RadioTapHighEfficiencyData6.Nsts); + + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); + + var recreatedField = new HighEfficiencyRadioTapField(new BinaryReader(new MemoryStream(bytes))); + + Assert.AreEqual(field.Data1, recreatedField.Data1); + Assert.AreEqual(field.Data2, recreatedField.Data2); + Assert.AreEqual(field.Data3, recreatedField.Data3); + Assert.AreEqual(field.Data4, recreatedField.Data4); + Assert.AreEqual(field.Data5, recreatedField.Data5); + Assert.AreEqual(field.Data6, recreatedField.Data6); + } + + + [Test] + public void Test_VeryHighThroughputRadioTapField() + { + var field = new VeryHighThroughputRadioTapField( + RadioTapVhtKnown.BandwidthKnown | RadioTapVhtKnown.StbcKnown, + RadioTapVhtFlags.Stbc, + bandwidth: RadioTapVhtBandwidth.MHz160Side20LLU, + mcsNss1: (RadioTapVhtMcsNss)0xf1, + mcsNss2: (RadioTapVhtMcsNss)0xe2, + mcsNss3: (RadioTapVhtMcsNss)0xd3, + mcsNss4: (RadioTapVhtMcsNss)0xc4, + coding: RadioTapVhtCoding.CodingForUser1 | RadioTapVhtCoding.CodingForUser2 | RadioTapVhtCoding.CodingForUser3 | RadioTapVhtCoding.CodingForUser4, + groupId: 6, + partialAid: 7 + ); + + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); + + var recreatedField = new VeryHighThroughputRadioTapField(new BinaryReader(new MemoryStream(bytes))); + + Assert.AreEqual(field.Known, recreatedField.Known); + Assert.AreEqual(field.Flags, recreatedField.Flags); + Assert.AreEqual(field.McsNss1, recreatedField.McsNss1); + Assert.AreEqual(field.McsNss2, recreatedField.McsNss2); + Assert.AreEqual(field.McsNss3, recreatedField.McsNss3); + Assert.AreEqual(field.McsNss4, recreatedField.McsNss4); + Assert.AreEqual(field.Coding, recreatedField.Coding); + Assert.AreEqual(field.GroupId, recreatedField.GroupId); + Assert.AreEqual(field.PartialAid, recreatedField.PartialAid); + } + + [Test] + public void Test_McsRadioTapField() + { + var field = new McsRadioTapField(RadioTapMcsKnown.FecType | RadioTapMcsKnown.Bandwidth, RadioTapMcsFlags.Bandwidth, 12); - var bytes = new byte[field.Length]; - field.CopyTo(bytes, 0); + var bytes = new byte[field.Length]; + field.CopyTo(bytes, 0); - var recreatedField = new TxAttenuationRadioTapField(new BinaryReader(new MemoryStream(bytes))); + var recreatedField = new McsRadioTapField(new BinaryReader(new MemoryStream(bytes))); - Assert.AreEqual(field.TxPower, recreatedField.TxPower); - } - } \ No newline at end of file + Assert.AreEqual(field.Known, recreatedField.Known); + Assert.AreEqual(field.Flags, recreatedField.Flags); + Assert.AreEqual(field.Mcs, recreatedField.Mcs); + } +} \ No newline at end of file