wifi: remove code duplication in yans and spectrum helpers

This commit is contained in:
Sébastien Deronne
2016-08-04 22:43:09 +02:00
parent 275d52f141
commit 017940af6e
6 changed files with 773 additions and 1487 deletions

View File

@@ -22,77 +22,18 @@
#include "ns3/trace-helper.h"
#include "spectrum-wifi-helper.h"
#include "ns3/error-rate-model.h"
#include "ns3/propagation-loss-model.h"
#include "ns3/propagation-delay-model.h"
#include "ns3/spectrum-channel.h"
#include "ns3/spectrum-wifi-phy.h"
#include "ns3/ampdu-subframe-header.h"
#include "ns3/wifi-net-device.h"
#include "ns3/radiotap-header.h"
#include "ns3/pcap-file-wrapper.h"
#include "ns3/simulator.h"
#include "ns3/config.h"
#include "ns3/names.h"
#include "ns3/abort.h"
#include "ns3/log.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("SpectrumWifiHelper");
static void
AsciiPhyTransmitSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << context << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyTransmitSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << context << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
SpectrumWifiPhyHelper::SpectrumWifiPhyHelper ()
: m_channel (0),
m_pcapDlt (PcapHelper::DLT_IEEE802_11)
: m_channel (0)
{
m_phy.SetTypeId ("ns3::SpectrumWifiPhy");
}
@@ -118,35 +59,6 @@ SpectrumWifiPhyHelper::SetChannel (std::string channelName)
m_channel = channel;
}
void
SpectrumWifiPhyHelper::Set (std::string name, const AttributeValue &v)
{
m_phy.Set (name, v);
}
void
SpectrumWifiPhyHelper::SetErrorRateModel (std::string name,
std::string n0, const AttributeValue &v0,
std::string n1, const AttributeValue &v1,
std::string n2, const AttributeValue &v2,
std::string n3, const AttributeValue &v3,
std::string n4, const AttributeValue &v4,
std::string n5, const AttributeValue &v5,
std::string n6, const AttributeValue &v6,
std::string n7, const AttributeValue &v7)
{
m_errorRateModel = ObjectFactory ();
m_errorRateModel.SetTypeId (name);
m_errorRateModel.Set (n0, v0);
m_errorRateModel.Set (n1, v1);
m_errorRateModel.Set (n2, v2);
m_errorRateModel.Set (n3, v3);
m_errorRateModel.Set (n4, v4);
m_errorRateModel.Set (n5, v5);
m_errorRateModel.Set (n6, v6);
m_errorRateModel.Set (n7, v7);
}
Ptr<WifiPhy>
SpectrumWifiPhyHelper::Create (Ptr<Node> node, Ptr<NetDevice> device) const
{
@@ -160,528 +72,4 @@ SpectrumWifiPhyHelper::Create (Ptr<Node> node, Ptr<NetDevice> device) const
return phy;
}
static void
PcapSniffTxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffTxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffTxEvent(): Unexpected data link type " << dlt);
}
}
static void
PcapSniffRxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu,
struct signalNoiseDbm signalNoise)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffRxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
header.SetAntennaSignalPower (signalNoise.signal);
header.SetAntennaNoisePower (signalNoise.noise);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_DELIMITER_CRC_KNOWN;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffRxEvent(): Unexpected data link type " << dlt);
}
}
void
SpectrumWifiPhyHelper::SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt)
{
switch (dlt)
{
case DLT_IEEE802_11:
m_pcapDlt = PcapHelper::DLT_IEEE802_11;
return;
case DLT_PRISM_HEADER:
m_pcapDlt = PcapHelper::DLT_PRISM_HEADER;
return;
case DLT_IEEE802_11_RADIO:
m_pcapDlt = PcapHelper::DLT_IEEE802_11_RADIO;
return;
default:
NS_ABORT_MSG ("SpectrumWifiPhyHelper::SetPcapFormat(): Unexpected format");
}
}
PcapHelper::DataLinkType
SpectrumWifiPhyHelper::GetPcapDataLinkType (void) const
{
return m_pcapDlt;
}
void
SpectrumWifiPhyHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
{
//All of the Pcap enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("SpectrumWifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice");
return;
}
Ptr<WifiPhy> phy = device->GetPhy ();
NS_ABORT_MSG_IF (phy == 0, "SpectrumWifiPhyHelper::EnablePcapInternal(): Phy layer in WifiNetDevice must be set");
PcapHelper pcapHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, m_pcapDlt);
phy->TraceConnectWithoutContext ("MonitorSnifferTx", MakeBoundCallback (&PcapSniffTxEvent, file));
phy->TraceConnectWithoutContext ("MonitorSnifferRx", MakeBoundCallback (&PcapSniffRxEvent, file));
}
void
SpectrumWifiPhyHelper::EnableAsciiInternal (
Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename)
{
//All of the ascii enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("SpectrumWifiHelper::EnableAsciiInternal(): Device " << device << " not of type ns3::WifiNetDevice");
return;
}
//Our trace sinks are going to use packet printing, so we have to make sure
//that is turned on.
Packet::EnablePrinting ();
uint32_t nodeid = nd->GetNode ()->GetId ();
uint32_t deviceid = nd->GetIfIndex ();
std::ostringstream oss;
//If we are not provided an OutputStreamWrapper, we are expected to create
//one using the usual trace filename conventions and write our traces
//without a context since there will be one file per context and therefore
//the context would be redundant.
if (stream == 0)
{
//Set up an output stream object to deal with private ofstream copy
//constructor and lifetime issues. Let the helper decide the actual
//name of the file given the prefix.
AsciiTraceHelper asciiTraceHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//We could go poking through the phy and the state looking for the
//correct trace source, but we can let Config deal with that with
//some search cost. Since this is presumably happening at topology
//creation time, it doesn't seem much of a price to pay.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithoutContext, theStream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithoutContext, theStream));
return;
}
//If we are provided an OutputStreamWrapper, we are expected to use it, and
//to provide a context. We are free to come up with our own context if we
//want, and use the AsciiTraceHelper Hook*WithContext functions, but for
//compatibility and simplicity, we just use Config::Connect and let it deal
//with coming up with a context.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithContext, stream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithContext, stream));
}
} //namespace ns3

View File

@@ -23,7 +23,6 @@
#include "wifi-helper.h"
#include "ns3/trace-helper.h"
#include "ns3/wifi-phy.h"
namespace ns3 {
@@ -36,9 +35,7 @@ class SpectrumChannel;
* in this class correspond to PHY-level traces and come to us via WifiPhyHelper
*
*/
class SpectrumWifiPhyHelper : public WifiPhyHelper,
public PcapHelperForDevice,
public AsciiTraceHelperForDevice
class SpectrumWifiPhyHelper : public WifiPhyHelper
{
public:
/**
@@ -64,75 +61,6 @@ public:
* Every PHY created by a call to Install is associated to this channel.
*/
void SetChannel (std::string channelName);
/**
* \param name the name of the attribute to set
* \param v the value of the attribute
*
* Set an attribute of the underlying PHY object.
*/
void Set (std::string name, const AttributeValue &v);
/**
* \param name the name of the error rate model to set.
* \param n0 the name of the attribute to set
* \param v0 the value of the attribute to set
* \param n1 the name of the attribute to set
* \param v1 the value of the attribute to set
* \param n2 the name of the attribute to set
* \param v2 the value of the attribute to set
* \param n3 the name of the attribute to set
* \param v3 the value of the attribute to set
* \param n4 the name of the attribute to set
* \param v4 the value of the attribute to set
* \param n5 the name of the attribute to set
* \param v5 the value of the attribute to set
* \param n6 the name of the attribute to set
* \param v6 the value of the attribute to set
* \param n7 the name of the attribute to set
* \param v7 the value of the attribute to set
*
* Set the error rate model and its attributes to use when Install is called.
*/
void SetErrorRateModel (std::string name,
std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (),
std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (),
std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (),
std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (),
std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
/**
* An enumeration of the pcap data link types (DLTs) which this helper
* supports. See http://wiki.wireshark.org/Development/LibpcapFileFormat
* for more information on these formats.
*/
enum SupportedPcapDataLinkTypes
{
DLT_IEEE802_11 = PcapHelper::DLT_IEEE802_11, /**< IEEE 802.11 Wireless LAN headers on packets */
DLT_PRISM_HEADER = PcapHelper::DLT_PRISM_HEADER, /**< Include Prism monitor mode information */
DLT_IEEE802_11_RADIO = PcapHelper::DLT_IEEE802_11_RADIO /**< Include Radiotap link layer information */
};
/**
* Set the data link type of PCAP traces to be used. This function has to be
* called before EnablePcap(), so that the header of the pcap file can be
* written correctly.
*
* @see SupportedPcapDataLinkTypes
*
* @param dlt The data link type of the pcap file (and packets) to be used
*/
void SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt);
/**
* Get the data link type of PCAP traces to be used.
*
* @see SupportedPcapDataLinkTypes
*
* @returns The data link type of the pcap file (and packets) to be used
*/
PcapHelper::DataLinkType GetPcapDataLinkType (void) const;
private:
/**
@@ -144,42 +72,7 @@ private:
*/
virtual Ptr<WifiPhy> Create (Ptr<Node> node, Ptr<NetDevice> device) const;
/**
* @brief Enable pcap output the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* @param prefix Filename prefix to use for pcap files.
* @param nd Net device for which you want to enable tracing.
* @param promiscuous If true capture all possible packets available at the device.
* @param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnablePcapInternal (std::string prefix,
Ptr<NetDevice> nd,
bool promiscuous,
bool explicitFilename);
/**
* \brief Enable ascii trace output on the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* \param stream The output stream object to use when logging ascii traces.
* \param prefix Filename prefix to use for ascii trace files.
* \param nd Net device for which you want to enable tracing.
* \param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename);
ObjectFactory m_phy;
ObjectFactory m_errorRateModel;
Ptr<SpectrumChannel> m_channel;
PcapHelper::DataLinkType m_pcapDlt;
};
} //namespace ns3

View File

@@ -29,6 +29,7 @@
#include "ns3/minstrel-wifi-manager.h"
#include "ns3/ap-wifi-mac.h"
#include "ns3/wifi-phy.h"
#include "ns3/ampdu-subframe-header.h"
#include "ns3/wifi-remote-station-manager.h"
#include "ns3/wifi-channel.h"
#include "ns3/yans-wifi-channel.h"
@@ -36,8 +37,11 @@
#include "ns3/propagation-loss-model.h"
#include "ns3/mobility-model.h"
#include "ns3/log.h"
#include "ns3/config.h"
#include "ns3/pointer.h"
#include "ns3/radiotap-header.h"
#include "ns3/pcap-file-wrapper.h"
#include "ns3/abort.h"
#include "ns3/config.h"
#include "ns3/simulator.h"
#include "ns3/names.h"
@@ -45,10 +49,618 @@ namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("WifiHelper");
static void
AsciiPhyTransmitSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << context << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyTransmitSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << context << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
WifiPhyHelper::WifiPhyHelper ()
: m_pcapDlt (PcapHelper::DLT_IEEE802_11)
{
}
WifiPhyHelper::~WifiPhyHelper ()
{
}
void
WifiPhyHelper::Set (std::string name, const AttributeValue &v)
{
m_phy.Set (name, v);
}
void
WifiPhyHelper::SetErrorRateModel (std::string name,
std::string n0, const AttributeValue &v0,
std::string n1, const AttributeValue &v1,
std::string n2, const AttributeValue &v2,
std::string n3, const AttributeValue &v3,
std::string n4, const AttributeValue &v4,
std::string n5, const AttributeValue &v5,
std::string n6, const AttributeValue &v6,
std::string n7, const AttributeValue &v7)
{
m_errorRateModel = ObjectFactory ();
m_errorRateModel.SetTypeId (name);
m_errorRateModel.Set (n0, v0);
m_errorRateModel.Set (n1, v1);
m_errorRateModel.Set (n2, v2);
m_errorRateModel.Set (n3, v3);
m_errorRateModel.Set (n4, v4);
m_errorRateModel.Set (n5, v5);
m_errorRateModel.Set (n6, v6);
m_errorRateModel.Set (n7, v7);
}
void
WifiPhyHelper::PcapSniffTxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffTxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffTxEvent(): Unexpected data link type " << dlt);
}
}
void
WifiPhyHelper::PcapSniffRxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu,
struct signalNoiseDbm signalNoise)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffRxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
header.SetAntennaSignalPower (signalNoise.signal);
header.SetAntennaNoisePower (signalNoise.noise);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_DELIMITER_CRC_KNOWN;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffRxEvent(): Unexpected data link type " << dlt);
}
}
void
WifiPhyHelper::SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt)
{
switch (dlt)
{
case DLT_IEEE802_11:
m_pcapDlt = PcapHelper::DLT_IEEE802_11;
return;
case DLT_PRISM_HEADER:
m_pcapDlt = PcapHelper::DLT_PRISM_HEADER;
return;
case DLT_IEEE802_11_RADIO:
m_pcapDlt = PcapHelper::DLT_IEEE802_11_RADIO;
return;
default:
NS_ABORT_MSG ("WifiPhyHelper::SetPcapFormat(): Unexpected format");
}
}
PcapHelper::DataLinkType
WifiPhyHelper::GetPcapDataLinkType (void) const
{
return m_pcapDlt;
}
void
WifiPhyHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
{
//All of the Pcap enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("WifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice");
return;
}
Ptr<WifiPhy> phy = device->GetPhy ();
NS_ABORT_MSG_IF (phy == 0, "WifiPhyHelper::EnablePcapInternal(): Phy layer in WifiNetDevice must be set");
PcapHelper pcapHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, m_pcapDlt);
phy->TraceConnectWithoutContext ("MonitorSnifferTx", MakeBoundCallback (&WifiPhyHelper::PcapSniffTxEvent, file));
phy->TraceConnectWithoutContext ("MonitorSnifferRx", MakeBoundCallback (&WifiPhyHelper::PcapSniffRxEvent, file));
}
void
WifiPhyHelper::EnableAsciiInternal (
Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename)
{
//All of the ascii enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("WifiHelper::EnableAsciiInternal(): Device " << device << " not of type ns3::WifiNetDevice");
return;
}
//Our trace sinks are going to use packet printing, so we have to make sure
//that is turned on.
Packet::EnablePrinting ();
uint32_t nodeid = nd->GetNode ()->GetId ();
uint32_t deviceid = nd->GetIfIndex ();
std::ostringstream oss;
//If we are not provided an OutputStreamWrapper, we are expected to create
//one using the usual trace filename conventions and write our traces
//without a context since there will be one file per context and therefore
//the context would be redundant.
if (stream == 0)
{
//Set up an output stream object to deal with private ofstream copy
//constructor and lifetime issues. Let the helper decide the actual
//name of the file given the prefix.
AsciiTraceHelper asciiTraceHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//We could go poking through the phy and the state looking for the
//correct trace source, but we can let Config deal with that with
//some search cost. Since this is presumably happening at topology
//creation time, it doesn't seem much of a price to pay.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithoutContext, theStream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithoutContext, theStream));
return;
}
//If we are provided an OutputStreamWrapper, we are expected to use it, and
//to provide a context. We are free to come up with our own context if we
//want, and use the AsciiTraceHelper Hook*WithContext functions, but for
//compatibility and simplicity, we just use Config::Connect and let it deal
//with coming up with a context.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithContext, stream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithContext, stream));
}
WifiHelper::~WifiHelper ()
{
}

View File

@@ -31,6 +31,7 @@
#include "ns3/wifi-phy-standard.h"
#include "ns3/trace-helper.h"
#include "ns3/wifi-mac-helper.h"
#include "ns3/wifi-phy.h"
namespace ns3 {
@@ -44,9 +45,11 @@ class Node;
* This base class must be implemented by new PHY implementation which wish to integrate
* with the \ref ns3::WifiHelper class.
*/
class WifiPhyHelper
class WifiPhyHelper : public PcapHelperForDevice,
public AsciiTraceHelperForDevice
{
public:
WifiPhyHelper ();
virtual ~WifiPhyHelper ();
/**
@@ -63,6 +66,158 @@ public:
* by other Wifi device variants such as WaveNetDevice.
*/
virtual Ptr<WifiPhy> Create (Ptr<Node> node, Ptr<NetDevice> device) const = 0;
/**
* \param name the name of the attribute to set
* \param v the value of the attribute
*
* Set an attribute of the underlying PHY object.
*/
void Set (std::string name, const AttributeValue &v);
/**
* \param name the name of the error rate model to set.
* \param n0 the name of the attribute to set
* \param v0 the value of the attribute to set
* \param n1 the name of the attribute to set
* \param v1 the value of the attribute to set
* \param n2 the name of the attribute to set
* \param v2 the value of the attribute to set
* \param n3 the name of the attribute to set
* \param v3 the value of the attribute to set
* \param n4 the name of the attribute to set
* \param v4 the value of the attribute to set
* \param n5 the name of the attribute to set
* \param v5 the value of the attribute to set
* \param n6 the name of the attribute to set
* \param v6 the value of the attribute to set
* \param n7 the name of the attribute to set
* \param v7 the value of the attribute to set
*
* Set the error rate model and its attributes to use when Install is called.
*/
void SetErrorRateModel (std::string name,
std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (),
std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (),
std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (),
std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (),
std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
/**
* An enumeration of the pcap data link types (DLTs) which this helper
* supports. See http://wiki.wireshark.org/Development/LibpcapFileFormat
* for more information on these formats.
*/
enum SupportedPcapDataLinkTypes
{
DLT_IEEE802_11 = PcapHelper::DLT_IEEE802_11, /**< IEEE 802.11 Wireless LAN headers on packets */
DLT_PRISM_HEADER = PcapHelper::DLT_PRISM_HEADER, /**< Include Prism monitor mode information */
DLT_IEEE802_11_RADIO = PcapHelper::DLT_IEEE802_11_RADIO /**< Include Radiotap link layer information */
};
/**
* Set the data link type of PCAP traces to be used. This function has to be
* called before EnablePcap(), so that the header of the pcap file can be
* written correctly.
*
* @see SupportedPcapDataLinkTypes
*
* @param dlt The data link type of the pcap file (and packets) to be used
*/
void SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt);
/**
* Get the data link type of PCAP traces to be used.
*
* @see SupportedPcapDataLinkTypes
*
* @returns The data link type of the pcap file (and packets) to be used
*/
PcapHelper::DataLinkType GetPcapDataLinkType (void) const;
protected:
/**
* \param file the pcap file wrapper
* \param packet the packet
* \param channelFreqMhz the channel frequency
* \param channelNumber the channel number
* \param rate the PHY bitrate
* \param preamble the preamble type
* \param txVector the TXVECTOR
* \param aMpdu the A-MPDU information
*
* Handle tx pcap.
*/
static void PcapSniffTxEvent (Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu);
/**
* \param file the pcap file wrapper
* \param packet the packet
* \param channelFreqMhz the channel frequency
* \param channelNumber the channel number
* \param rate the PHY bitrate
* \param preamble the preamble type
* \param txVector the TXVECTOR
* \param aMpdu the A-MPDU information
* \param signalNoise the rx signal and noise information
*
* Handle rx pcap.
*/
static void PcapSniffRxEvent (Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu,
struct signalNoiseDbm signalNoise);
ObjectFactory m_phy;
ObjectFactory m_errorRateModel;
private:
/**
* @brief Enable pcap output the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* @param prefix Filename prefix to use for pcap files.
* @param nd Net device for which you want to enable tracing.
* @param promiscuous If true capture all possible packets available at the device.
* @param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnablePcapInternal (std::string prefix,
Ptr<NetDevice> nd,
bool promiscuous,
bool explicitFilename);
/**
* \brief Enable ascii trace output on the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* \param stream The output stream object to use when logging ascii traces.
* \param prefix Filename prefix to use for ascii trace files.
* \param nd Net device for which you want to enable tracing.
* \param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename);
PcapHelper::DataLinkType m_pcapDlt;
};

View File

@@ -26,70 +26,14 @@
#include "ns3/propagation-delay-model.h"
#include "ns3/yans-wifi-channel.h"
#include "ns3/yans-wifi-phy.h"
#include "ns3/ampdu-subframe-header.h"
#include "ns3/wifi-net-device.h"
#include "ns3/radiotap-header.h"
#include "ns3/pcap-file-wrapper.h"
#include "ns3/simulator.h"
#include "ns3/config.h"
#include "ns3/names.h"
#include "ns3/abort.h"
#include "ns3/log.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("YansWifiHelper");
static void
AsciiPhyTransmitSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << context << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyTransmitSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
WifiMode mode,
WifiPreamble preamble,
uint8_t txLevel)
{
NS_LOG_FUNCTION (stream << p << mode << preamble << txLevel);
*stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithContext (
Ptr<OutputStreamWrapper> stream,
std::string context,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << context << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
}
static void
AsciiPhyReceiveSinkWithoutContext (
Ptr<OutputStreamWrapper> stream,
Ptr<const Packet> p,
double snr,
WifiMode mode,
enum WifiPreamble preamble)
{
NS_LOG_FUNCTION (stream << p << snr << mode << preamble);
*stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
}
YansWifiChannelHelper::YansWifiChannelHelper ()
{
}
@@ -181,8 +125,7 @@ YansWifiChannelHelper::AssignStreams (Ptr<YansWifiChannel> c, int64_t stream)
}
YansWifiPhyHelper::YansWifiPhyHelper ()
: m_channel (0),
m_pcapDlt (PcapHelper::DLT_IEEE802_11)
: m_channel (0)
{
m_phy.SetTypeId ("ns3::YansWifiPhy");
}
@@ -208,35 +151,6 @@ YansWifiPhyHelper::SetChannel (std::string channelName)
m_channel = channel;
}
void
YansWifiPhyHelper::Set (std::string name, const AttributeValue &v)
{
m_phy.Set (name, v);
}
void
YansWifiPhyHelper::SetErrorRateModel (std::string name,
std::string n0, const AttributeValue &v0,
std::string n1, const AttributeValue &v1,
std::string n2, const AttributeValue &v2,
std::string n3, const AttributeValue &v3,
std::string n4, const AttributeValue &v4,
std::string n5, const AttributeValue &v5,
std::string n6, const AttributeValue &v6,
std::string n7, const AttributeValue &v7)
{
m_errorRateModel = ObjectFactory ();
m_errorRateModel.SetTypeId (name);
m_errorRateModel.Set (n0, v0);
m_errorRateModel.Set (n1, v1);
m_errorRateModel.Set (n2, v2);
m_errorRateModel.Set (n3, v3);
m_errorRateModel.Set (n4, v4);
m_errorRateModel.Set (n5, v5);
m_errorRateModel.Set (n6, v6);
m_errorRateModel.Set (n7, v7);
}
Ptr<WifiPhy>
YansWifiPhyHelper::Create (Ptr<Node> node, Ptr<NetDevice> device) const
{
@@ -248,528 +162,4 @@ YansWifiPhyHelper::Create (Ptr<Node> node, Ptr<NetDevice> device) const
return phy;
}
void
YansWifiPhyHelper::PcapSniffTxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffTxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffTxEvent(): Unexpected data link type " << dlt);
}
}
void
YansWifiPhyHelper::PcapSniffRxEvent (
Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu,
struct signalNoiseDbm signalNoise)
{
uint32_t dlt = file->GetDataLinkType ();
switch (dlt)
{
case PcapHelper::DLT_IEEE802_11:
file->Write (Simulator::Now (), packet);
return;
case PcapHelper::DLT_PRISM_HEADER:
{
NS_FATAL_ERROR ("PcapSniffRxEvent(): DLT_PRISM_HEADER not implemented");
return;
}
case PcapHelper::DLT_IEEE802_11_RADIO:
{
Ptr<Packet> p = packet->Copy ();
RadiotapHeader header;
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft (Simulator::Now ().GetMicroSeconds ());
//Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.IsShortGuardInterval ())
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags (frameFlags);
header.SetRate (rate);
uint16_t channelFlags = 0;
switch (rate)
{
case 2: //1Mbps
case 4: //2Mbps
case 10: //5Mbps
case 22: //11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFrequencyAndFlags (channelFreqMhz, channelFlags);
header.SetAntennaSignalPower (signalNoise.signal);
header.SetAntennaNoisePower (signalNoise.noise);
if (preamble == WIFI_PREAMBLE_HT_MF || preamble == WIFI_PREAMBLE_HT_GF || preamble == WIFI_PREAMBLE_NONE)
{
uint8_t mcsRate = 0;
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsRate = rate - 128;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth () == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
if (preamble == WIFI_PREAMBLE_HT_GF)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_HT_GREENFIELD;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess () & 0x01) //bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess () & 0x02) //bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; //only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc ())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields (mcsKnown, mcsFlags, mcsRate);
}
if (txVector.IsAggregation ())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_DELIMITER_CRC_KNOWN;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
p->RemoveHeader (hdr);
extractedLength = hdr.GetLength ();
p = p->CreateFragment (0, static_cast<uint32_t> (extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof () == true && hdr.GetLength () > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus (aMpdu.mpduRefNumber, ampduStatusFlags, hdr.GetCrc ());
}
if (preamble == WIFI_PREAMBLE_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0,0,0,0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.IsShortGuardInterval ())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; //Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
//not all bandwidth values are currently supported
if (txVector.GetChannelWidth () == 40)
{
vhtBandwidth = 1;
}
else if (txVector.GetChannelWidth () == 80)
{
vhtBandwidth = 4;
}
else if (txVector.GetChannelWidth () == 160)
{
vhtBandwidth = 11;
}
//only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss () & 0x0f);
vhtMcsNss[0] |= (((rate - 128) << 4) & 0xf0);
header.SetVhtFields (vhtKnown, vhtFlags, vhtBandwidth, vhtMcsNss, vhtCoding, vhtGroupId, vhtPartialAid);
}
p->AddHeader (header);
file->Write (Simulator::Now (), p);
return;
}
default:
NS_ABORT_MSG ("PcapSniffRxEvent(): Unexpected data link type " << dlt);
}
}
void
YansWifiPhyHelper::SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt)
{
switch (dlt)
{
case DLT_IEEE802_11:
m_pcapDlt = PcapHelper::DLT_IEEE802_11;
return;
case DLT_PRISM_HEADER:
m_pcapDlt = PcapHelper::DLT_PRISM_HEADER;
return;
case DLT_IEEE802_11_RADIO:
m_pcapDlt = PcapHelper::DLT_IEEE802_11_RADIO;
return;
default:
NS_ABORT_MSG ("YansWifiPhyHelper::SetPcapFormat(): Unexpected format");
}
}
PcapHelper::DataLinkType
YansWifiPhyHelper::GetPcapDataLinkType (void) const
{
return m_pcapDlt;
}
void
YansWifiPhyHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
{
//All of the Pcap enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("YansWifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice");
return;
}
Ptr<WifiPhy> phy = device->GetPhy ();
NS_ABORT_MSG_IF (phy == 0, "YansWifiPhyHelper::EnablePcapInternal(): Phy layer in WifiNetDevice must be set");
PcapHelper pcapHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, m_pcapDlt);
phy->TraceConnectWithoutContext ("MonitorSnifferTx", MakeBoundCallback (&YansWifiPhyHelper::PcapSniffTxEvent, file));
phy->TraceConnectWithoutContext ("MonitorSnifferRx", MakeBoundCallback (&YansWifiPhyHelper::PcapSniffRxEvent, file));
}
void
YansWifiPhyHelper::EnableAsciiInternal (
Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename)
{
//All of the ascii enable functions vector through here including the ones
//that are wandering through all of devices on perhaps all of the nodes in
//the system. We can only deal with devices of type WifiNetDevice.
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("YansWifiHelper::EnableAsciiInternal(): Device " << device << " not of type ns3::WifiNetDevice");
return;
}
//Our trace sinks are going to use packet printing, so we have to make sure
//that is turned on.
Packet::EnablePrinting ();
uint32_t nodeid = nd->GetNode ()->GetId ();
uint32_t deviceid = nd->GetIfIndex ();
std::ostringstream oss;
//If we are not provided an OutputStreamWrapper, we are expected to create
//one using the usual trace filename conventions and write our traces
//without a context since there will be one file per context and therefore
//the context would be redundant.
if (stream == 0)
{
//Set up an output stream object to deal with private ofstream copy
//constructor and lifetime issues. Let the helper decide the actual
//name of the file given the prefix.
AsciiTraceHelper asciiTraceHelper;
std::string filename;
if (explicitFilename)
{
filename = prefix;
}
else
{
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
}
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
//We could go poking through the phy and the state looking for the
//correct trace source, but we can let Config deal with that with
//some search cost. Since this is presumably happening at topology
//creation time, it doesn't seem much of a price to pay.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithoutContext, theStream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithoutContext, theStream));
return;
}
//If we are provided an OutputStreamWrapper, we are expected to use it, and
//to provide a context. We are free to come up with our own context if we
//want, and use the AsciiTraceHelper Hook*WithContext functions, but for
//compatibility and simplicity, we just use Config::Connect and let it deal
//with coming up with a context.
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyReceiveSinkWithContext, stream));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyTransmitSinkWithContext, stream));
}
} //namespace ns3

View File

@@ -157,9 +157,7 @@ private:
* in this class correspond to PHY-level traces and come to us via WifiPhyHelper
*
*/
class YansWifiPhyHelper : public WifiPhyHelper,
public PcapHelperForDevice,
public AsciiTraceHelperForDevice
class YansWifiPhyHelper : public WifiPhyHelper
{
public:
/**
@@ -185,121 +183,6 @@ public:
* Every PHY created by a call to Install is associated to this channel.
*/
void SetChannel (std::string channelName);
/**
* \param name the name of the attribute to set
* \param v the value of the attribute
*
* Set an attribute of the underlying PHY object.
*/
void Set (std::string name, const AttributeValue &v);
/**
* \param name the name of the error rate model to set.
* \param n0 the name of the attribute to set
* \param v0 the value of the attribute to set
* \param n1 the name of the attribute to set
* \param v1 the value of the attribute to set
* \param n2 the name of the attribute to set
* \param v2 the value of the attribute to set
* \param n3 the name of the attribute to set
* \param v3 the value of the attribute to set
* \param n4 the name of the attribute to set
* \param v4 the value of the attribute to set
* \param n5 the name of the attribute to set
* \param v5 the value of the attribute to set
* \param n6 the name of the attribute to set
* \param v6 the value of the attribute to set
* \param n7 the name of the attribute to set
* \param v7 the value of the attribute to set
*
* Set the error rate model and its attributes to use when Install is called.
*/
void SetErrorRateModel (std::string name,
std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (),
std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (),
std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (),
std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (),
std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
/**
* An enumeration of the pcap data link types (DLTs) which this helper
* supports. See http://wiki.wireshark.org/Development/LibpcapFileFormat
* for more information on these formats.
*/
enum SupportedPcapDataLinkTypes
{
DLT_IEEE802_11 = PcapHelper::DLT_IEEE802_11, /**< IEEE 802.11 Wireless LAN headers on packets */
DLT_PRISM_HEADER = PcapHelper::DLT_PRISM_HEADER, /**< Include Prism monitor mode information */
DLT_IEEE802_11_RADIO = PcapHelper::DLT_IEEE802_11_RADIO /**< Include Radiotap link layer information */
};
/**
* Set the data link type of PCAP traces to be used. This function has to be
* called before EnablePcap(), so that the header of the pcap file can be
* written correctly.
*
* @see SupportedPcapDataLinkTypes
*
* @param dlt The data link type of the pcap file (and packets) to be used
*/
void SetPcapDataLinkType (enum SupportedPcapDataLinkTypes dlt);
/**
* Get the data link type of PCAP traces to be used.
*
* @see SupportedPcapDataLinkTypes
*
* @returns The data link type of the pcap file (and packets) to be used
*/
PcapHelper::DataLinkType GetPcapDataLinkType (void) const;
protected:
/**
* \param file the pcap file wrapper
* \param packet the packet
* \param channelFreqMhz the channel frequency
* \param channelNumber the channel number
* \param rate the PHY bitrate
* \param preamble the preamble type
* \param txVector the TXVECTOR
* \param aMpdu the A-MPDU information
*
* Handle tx pcap.
*/
static void PcapSniffTxEvent (Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu);
/**
* \param file the pcap file wrapper
* \param packet the packet
* \param channelFreqMhz the channel frequency
* \param channelNumber the channel number
* \param rate the PHY bitrate
* \param preamble the preamble type
* \param txVector the TXVECTOR
* \param aMpdu the A-MPDU information
* \param signalNoise the rx signal and noise information
*
* Handle rx pcap.
*/
static void PcapSniffRxEvent (Ptr<PcapFileWrapper> file,
Ptr<const Packet> packet,
uint16_t channelFreqMhz,
uint16_t channelNumber,
uint32_t rate,
WifiPreamble preamble,
WifiTxVector txVector,
struct mpduInfo aMpdu,
struct signalNoiseDbm signalNoise);
private:
/**
@@ -311,42 +194,7 @@ private:
*/
virtual Ptr<WifiPhy> Create (Ptr<Node> node, Ptr<NetDevice> device) const;
/**
* @brief Enable pcap output the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* @param prefix Filename prefix to use for pcap files.
* @param nd Net device for which you want to enable tracing.
* @param promiscuous If true capture all possible packets available at the device.
* @param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnablePcapInternal (std::string prefix,
Ptr<NetDevice> nd,
bool promiscuous,
bool explicitFilename);
/**
* \brief Enable ascii trace output on the indicated net device.
*
* NetDevice-specific implementation mechanism for hooking the trace and
* writing to the trace file.
*
* \param stream The output stream object to use when logging ascii traces.
* \param prefix Filename prefix to use for ascii trace files.
* \param nd Net device for which you want to enable tracing.
* \param explicitFilename Treat the prefix as an explicit filename if true
*/
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename);
ObjectFactory m_phy;
ObjectFactory m_errorRateModel;
Ptr<YansWifiChannel> m_channel;
PcapHelper::DataLinkType m_pcapDlt;
};
} //namespace ns3