/*
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);
};
}
}