wifi: remove code duplication in yans and spectrum helpers
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user