/* This file is part of PacketDotNet PacketDotNet is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PacketDotNet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PacketDotNet. If not, see . */ /* * Copyright 2010 Chris Morgan */ using System; using System.Collections.Generic; using System.IO; using PacketDotNet.Utils; using MiscUtil.Conversion; namespace PacketDotNet { namespace Ieee80211 { /// /// Channel field /// public class ChannelRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Channel; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 4; } } /// /// Frequency in MHz /// public UInt16 FrequencyMHz { get; set; } /// /// Channel number derived from frequency /// public int Channel { get; set; } /// /// Channel flags /// public RadioTapChannelFlags Flags; /// /// 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; }; } /// /// 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((UInt16)Flags, dest, offset + 2); } /// /// Constructor /// /// /// A /// public ChannelRadioTapField(BinaryReader br) { FrequencyMHz = br.ReadUInt16(); Channel = ChannelFromFrequencyMHz(FrequencyMHz); Flags = (RadioTapChannelFlags)br.ReadUInt16(); } /// /// Initializes a new instance of the class. /// public ChannelRadioTapField() { } /// /// Initializes a new instance of the class. /// /// /// Tx/Rx Frequency in MHz. /// /// /// Flags. /// public ChannelRadioTapField(UInt16 FrequencyMhz, RadioTapChannelFlags Flags) { this.FrequencyMHz = FrequencyMHz; this.Channel = ChannelFromFrequencyMHz(FrequencyMHz); this.Flags = Flags; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("FrequencyMHz {0}, Channel {1}, Flags {2}", FrequencyMHz, Channel, Flags); } } /// /// Fhss radio tap field /// public class FhssRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Fhss; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 2; } } /// /// Hop set /// public byte ChannelHoppingSet { get; set; } /// /// 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; } /// /// 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) { this.ChannelHoppingSet = ChannelHoppingSet; this.Pattern = Pattern; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("ChannelHoppingSet {0}, Pattern {1}", ChannelHoppingSet, Pattern); } } /// /// Radio tap flags /// public class FlagsRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Flags; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// Flags set /// public RadioTapFlags Flags; /// /// Copies the field data to the destination buffer at the specified offset. /// public override void CopyTo(byte[] dest, int offset) { dest[offset] = (byte) 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) { this.Flags = Flags; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("Flags {0}", Flags); } } /// /// Rate field /// public class RateRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Rate; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// 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); } /// /// 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) { this.RateMbps = RateMbps; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("RateMbps {0}", RateMbps); } } /// /// Db antenna signal /// public class DbAntennaSignalRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbAntennaSignal; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// 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; } /// /// 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) { this.SignalStrengthdB = SignalStrengthdB; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("SignalStrengthdB {0}", SignalStrengthdB); } } /// /// Antenna noise in dB /// public class DbAntennaNoiseRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbAntennaNoise; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// Antenna noise in dB /// public byte AntennaNoisedB { get; set; } /// /// Copies the field data to the destination buffer at the specified offset. /// public override void CopyTo(byte[] dest, int offset) { dest[offset] = AntennaNoisedB; } /// /// 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) { this.AntennaNoisedB = AntennaNoisedB; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("AntennaNoisedB {0}", AntennaNoisedB); } } /// /// Antenna field /// public class AntennaRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Antenna; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// Antenna number /// public byte Antenna { get; set; } /// /// Copies the field data to the destination buffer at the specified offset. /// public override void CopyTo(byte[] dest, int offset) { dest[offset] = Antenna; } /// /// 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) { this.Antenna = Antenna; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("Antenna {0}", Antenna); } } /// /// Antenna signal in dBm /// public class DbmAntennaSignalRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbmAntennaSignal; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// Antenna signal in dBm /// public sbyte AntennaSignalDbm { 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)AntennaSignalDbm; } /// /// 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) { this.AntennaSignalDbm = AntennaSignalDbm; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("AntennaSignalDbm {0}", AntennaSignalDbm); } } /// /// Antenna noise in dBm /// public class DbmAntennaNoiseRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbmAntennaNoise; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// Antenna noise in dBm /// public sbyte AntennaNoisedBm { 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)AntennaNoisedBm; } /// /// 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) { this.AntennaNoisedBm = AntennaNoisedBm; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("AntennaNoisedBm {0}", AntennaNoisedBm); } } /// /// Lock quality /// public class LockQualityRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.LockQuality; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 2; } } /// /// Signal quality /// public UInt16 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); } /// /// 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(UInt16 SignalQuality) { this.SignalQuality = SignalQuality; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("SignalQuality {0}", SignalQuality); } } /// /// Tsft radio tap field /// public class TsftRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.Tsft; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 8; } } /// /// Timestamp in microseconds /// public UInt64 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); } /// /// 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(UInt64 TimestampUsec) { this.TimestampUsec = TimestampUsec; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("TimestampUsec {0}", TimestampUsec); } } /// /// Contains properties about the received from. /// public class RxFlagsRadioTapField : RadioTapField { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.RxFlags; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 2; } } /// /// 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) { UInt16 flags = (UInt16)((PlcpCrcCheckFailed) ? 0x2 : 0x0); EndianBitConverter.Little.CopyBytes(flags, dest, offset); } /// /// Constructor /// /// /// A /// public RxFlagsRadioTapField(BinaryReader br) { UInt16 flags = br.ReadUInt16(); Console.WriteLine("RxFlagsRadioTapField {0}", flags); 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) { this.PlcpCrcCheckFailed = PlcpCrcCheckFailed; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("PlcpCrcCheckFailed {0}", 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 { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.TxAttenuation; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 2; } } /// /// 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) { UInt16 absValue = (UInt16) Math.Abs(TxPower); EndianBitConverter.Little.CopyBytes(absValue, dest, offset); } /// /// Constructor /// /// /// A /// public TxAttenuationRadioTapField(BinaryReader br) { TxPower = -(int)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) { this.TxPower = TxPower; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("TxPower {0}", 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 { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbTxAttenuation; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 2; } } /// /// 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) { UInt16 absValue = (UInt16) Math.Abs(TxPowerdB); EndianBitConverter.Little.CopyBytes(absValue, dest, offset); } /// /// Constructor /// /// /// A /// public DbTxAttenuationRadioTapField(BinaryReader br) { TxPowerdB = -(int)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) { this.TxPowerdB = TxPowerdB; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("TxPowerdB {0}", 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 { /// Type of the field public override RadioTapType FieldType { get { return RadioTapType.DbmTxPower; } } /// /// Gets the length of the field data. /// /// /// The length. /// public override ushort Length { get { return 1; } } /// /// 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; } /// /// 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) { this.TxPowerdBm = TxPowerdBm; } /// /// ToString() override /// /// /// A /// public override string ToString() { return string.Format("TxPowerdBm {0}", TxPowerdBm); } } /// /// Abstract class for all radio tap fields /// public abstract class RadioTapField { /// Type of the field public abstract RadioTapType FieldType { get; } /// /// 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; } } /// /// Gets the length of the field data. /// /// /// The length. /// public abstract ushort Length {get;} /// /// Copies the field data to the destination buffer at the specified offset. /// public abstract void CopyTo(byte[] dest, int offset); }; } }