diff --git a/src/wifi/helper/spectrum-wifi-helper.cc b/src/wifi/helper/spectrum-wifi-helper.cc index 26a49e9be..c9079fbd9 100644 --- a/src/wifi/helper/spectrum-wifi-helper.cc +++ b/src/wifi/helper/spectrum-wifi-helper.cc @@ -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 stream, - std::string context, - Ptr 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 stream, - Ptr 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 stream, - std::string context, - Ptr 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 stream, - Ptr 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 SpectrumWifiPhyHelper::Create (Ptr node, Ptr device) const { @@ -160,528 +72,4 @@ SpectrumWifiPhyHelper::Create (Ptr node, Ptr device) const return phy; } -static void -PcapSniffTxEvent ( - Ptr file, - Ptr 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 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 (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 file, - Ptr 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 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 (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 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 device = nd->GetObject (); - if (device == 0) - { - NS_LOG_INFO ("SpectrumWifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice"); - return; - } - - Ptr 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 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 stream, - std::string prefix, - Ptr 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 device = nd->GetObject (); - 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 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 diff --git a/src/wifi/helper/spectrum-wifi-helper.h b/src/wifi/helper/spectrum-wifi-helper.h index ef52680dc..4756941d8 100644 --- a/src/wifi/helper/spectrum-wifi-helper.h +++ b/src/wifi/helper/spectrum-wifi-helper.h @@ -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 Create (Ptr node, Ptr 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 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 stream, - std::string prefix, - Ptr nd, - bool explicitFilename); - - ObjectFactory m_phy; - ObjectFactory m_errorRateModel; Ptr m_channel; - PcapHelper::DataLinkType m_pcapDlt; }; } //namespace ns3 diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index 00e0d7634..86bc8a136 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -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 stream, + std::string context, + Ptr 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 stream, + Ptr 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 stream, + std::string context, + Ptr 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 stream, + Ptr 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 file, + Ptr 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 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 (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 file, + Ptr 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 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 (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 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 device = nd->GetObject (); + if (device == 0) + { + NS_LOG_INFO ("WifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice"); + return; + } + + Ptr 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 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 stream, + std::string prefix, + Ptr 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 device = nd->GetObject (); + 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 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 () { } diff --git a/src/wifi/helper/wifi-helper.h b/src/wifi/helper/wifi-helper.h index 1aa668dcb..0744393d2 100644 --- a/src/wifi/helper/wifi-helper.h +++ b/src/wifi/helper/wifi-helper.h @@ -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 Create (Ptr node, Ptr 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 file, + Ptr 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 file, + Ptr 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 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 stream, + std::string prefix, + Ptr nd, + bool explicitFilename); + + PcapHelper::DataLinkType m_pcapDlt; }; diff --git a/src/wifi/helper/yans-wifi-helper.cc b/src/wifi/helper/yans-wifi-helper.cc index e993136ee..9c7f7649f 100644 --- a/src/wifi/helper/yans-wifi-helper.cc +++ b/src/wifi/helper/yans-wifi-helper.cc @@ -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 stream, - std::string context, - Ptr 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 stream, - Ptr 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 stream, - std::string context, - Ptr 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 stream, - Ptr 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 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 YansWifiPhyHelper::Create (Ptr node, Ptr device) const { @@ -248,528 +162,4 @@ YansWifiPhyHelper::Create (Ptr node, Ptr device) const return phy; } -void -YansWifiPhyHelper::PcapSniffTxEvent ( - Ptr file, - Ptr 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 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 (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 file, - Ptr 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 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 (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 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 device = nd->GetObject (); - if (device == 0) - { - NS_LOG_INFO ("YansWifiHelper::EnablePcapInternal(): Device " << &device << " not of type ns3::WifiNetDevice"); - return; - } - - Ptr 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 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 stream, - std::string prefix, - Ptr 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 device = nd->GetObject (); - 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 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 diff --git a/src/wifi/helper/yans-wifi-helper.h b/src/wifi/helper/yans-wifi-helper.h index 629830685..df5380cf1 100644 --- a/src/wifi/helper/yans-wifi-helper.h +++ b/src/wifi/helper/yans-wifi-helper.h @@ -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 file, - Ptr 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 file, - Ptr 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 Create (Ptr node, Ptr 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 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 stream, - std::string prefix, - Ptr nd, - bool explicitFilename); - - ObjectFactory m_phy; - ObjectFactory m_errorRateModel; Ptr m_channel; - PcapHelper::DataLinkType m_pcapDlt; }; } //namespace ns3