diff --git a/examples/wireless/power-adaptation-distance.cc b/examples/wireless/power-adaptation-distance.cc index f729045ed..a73dacf17 100644 --- a/examples/wireless/power-adaptation-distance.cc +++ b/examples/wireless/power-adaptation-distance.cc @@ -172,7 +172,7 @@ NodeStatistics::SetupPhy (Ptr phy) WifiMode mode = phy->GetMode (i); WifiTxVector txVector; txVector.SetMode (mode); - timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode)); + timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency (), 0, 0), mode)); } } diff --git a/examples/wireless/power-adaptation-interference.cc b/examples/wireless/power-adaptation-interference.cc index e17f67689..1e7ad29d5 100644 --- a/examples/wireless/power-adaptation-interference.cc +++ b/examples/wireless/power-adaptation-interference.cc @@ -168,7 +168,7 @@ NodeStatistics::SetupPhy (Ptr phy) WifiMode mode = phy->GetMode (i); WifiTxVector txVector; txVector.SetMode (mode); - timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode)); + timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency (), 0, 0), mode)); } } diff --git a/src/mesh/model/dot11s/airtime-metric.cc b/src/mesh/model/dot11s/airtime-metric.cc index 9384701cd..225bd61ac 100644 --- a/src/mesh/model/dot11s/airtime-metric.cc +++ b/src/mesh/model/dot11s/airtime-metric.cc @@ -95,7 +95,7 @@ AirtimeLinkMetricCalculator::CalculateMetric (Mac48Address peerAddress, PtrGetPifs () + mac->GetSlot () + mac->GetEifsNoDifs () + //DIFS + SIFS + AckTxTime = PIFS + SLOT + EifsNoDifs - mac->GetWifiPhy ()->CalculateTxDuration (m_testFrame->GetSize (), txVector, WIFI_PREAMBLE_LONG, mac->GetWifiPhy ()->GetFrequency()) + mac->GetWifiPhy ()->CalculateTxDuration (m_testFrame->GetSize (), txVector, WIFI_PREAMBLE_LONG, mac->GetWifiPhy ()->GetFrequency(), 0, 0) ).GetMicroSeconds () / (10.24 * (1.0 - failAvg))); return metric; } diff --git a/src/wifi/doc/wifi.rst b/src/wifi/doc/wifi.rst index 94cf51181..b5bb85e35 100644 --- a/src/wifi/doc/wifi.rst +++ b/src/wifi/doc/wifi.rst @@ -19,7 +19,7 @@ on the IEEE 802.11 standard [ieee80211]_. We will go into more detail below but * basic 802.11 DCF with **infrastructure** and **adhoc** modes * **802.11a**, **802.11b**, **802.11g** and **802.11n** (both 2.4 and 5 GHz bands) physical layers -* **MSDU aggregation** extension of 802.11n +* **MSDU aggregation** and **MPDU aggregation** extensions of 802.11n * QoS-based EDCA and queueing extensions of **802.11e** * the ability to use different propagation loss models and propagation delay models, please see the chapter on :ref:`Propagation` for more detail @@ -701,7 +701,7 @@ Note on the current implementation * PHY_RXSTART is not supported * 802.11e TXOP is not supported * 802.11n MIMO is not supported -* MPDU aggregation is not supported +* hybrid aggregation is not supported Wifi Tracing @@ -737,6 +737,6 @@ References .. [maguolo2008aarfcd] \ F. Maguolo, M. Lacage, and T. Turletti, *Efficient collision detection for auto rate fallback algorithm*, in IEEE Symposium on Computers and Communications, 2008 -.. [akella2007parf] \ A. Akella, G. Judd, S. Seshan, and P. Steenkiste, 'Self-management in chaotic wireless deployments', in Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755. ``_ +.. [akella2007parf] \ A. Akella, G. Judd, S. Seshan, and P. Steenkiste, 'Self-management in chaotic wireless deployments', in Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755. ``__ -.. [chevillat2005aparf] \ Chevillat, P.; Jelitto, J., and Truong, H. L., 'Dynamic data rate and transmit power adjustment in IEEE 802.11 wireless LANs', in International Journal of Wireless Information Networks, Springer, 2005, 12, 123-145. ``_ +.. [chevillat2005aparf] \ Chevillat, P.; Jelitto, J., and Truong, H. L., 'Dynamic data rate and transmit power adjustment in IEEE 802.11 wireless LANs', in International Journal of Wireless Information Networks, Springer, 2005, 12, 123-145. ``__ \ No newline at end of file diff --git a/src/wifi/examples/wifi-phy-test.cc b/src/wifi/examples/wifi-phy-test.cc index 1be89a5fe..15d9896b3 100644 --- a/src/wifi/examples/wifi-phy-test.cc +++ b/src/wifi/examples/wifi-phy-test.cc @@ -73,7 +73,7 @@ PsrExperiment::Send (void) WifiTxVector txVector; txVector.SetTxPowerLevel (m_input.txPowerLevel); txVector.SetMode (mode); - m_tx->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT); + m_tx->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0); } void @@ -178,7 +178,7 @@ CollisionExperiment::SendA (void) const WifiTxVector txVector; txVector.SetTxPowerLevel (m_input.txPowerLevelA); txVector.SetMode (WifiMode (m_input.txModeA)); - m_txA->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT); + m_txA->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0); } void @@ -189,7 +189,7 @@ CollisionExperiment::SendB (void) const WifiTxVector txVector; txVector.SetTxPowerLevel (m_input.txPowerLevelB); txVector.SetMode (WifiMode (m_input.txModeB)); - m_txB->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT); + m_txB->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0); } void diff --git a/src/wifi/helper/qos-wifi-mac-helper.cc b/src/wifi/helper/qos-wifi-mac-helper.cc index 8df5247b5..8ffa08535 100644 --- a/src/wifi/helper/qos-wifi-mac-helper.cc +++ b/src/wifi/helper/qos-wifi-mac-helper.cc @@ -24,6 +24,8 @@ #include "ns3/pointer.h" #include "ns3/boolean.h" #include "ns3/uinteger.h" +#include "ns3/mpdu-aggregator.h" +#include "ns3/mac-low.h" namespace ns3 { @@ -100,6 +102,21 @@ QosWifiMacHelper::SetMsduAggregatorForAc (AcIndex ac, std::string type, } } +void +QosWifiMacHelper::SetMpduAggregatorForAc (enum AcIndex ac, 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) +{ + m_mpduAggregator = ObjectFactory (); + m_mpduAggregator.SetTypeId (name); + m_mpduAggregator.Set (n0, v0); + m_mpduAggregator.Set (n1, v1); + m_mpduAggregator.Set (n2, v2); + m_mpduAggregator.Set (n3, v3); +} + void QosWifiMacHelper::SetBlockAckThresholdForAc (enum AcIndex ac, uint8_t threshold) { @@ -120,6 +137,12 @@ QosWifiMacHelper::Setup (Ptr mac, enum AcIndex ac, std::string dcaAttrN mac->GetAttribute (dcaAttrName, ptr); Ptr edca = ptr.Get (); + if (m_mpduAggregator.GetTypeId().GetUid() != 0) + { + Ptr mpduaggregator = m_mpduAggregator.Create (); + Ptr low = edca->Low(); + low->SetMpduAggregator (mpduaggregator); + } if (it != m_aggregators.end ()) { ObjectFactory factory = it->second; @@ -136,7 +159,6 @@ QosWifiMacHelper::Setup (Ptr mac, enum AcIndex ac, std::string dcaAttrN } } - Ptr QosWifiMacHelper::Create (void) const { diff --git a/src/wifi/helper/qos-wifi-mac-helper.h b/src/wifi/helper/qos-wifi-mac-helper.h index 605d744fb..f7ea9fe86 100644 --- a/src/wifi/helper/qos-wifi-mac-helper.h +++ b/src/wifi/helper/qos-wifi-mac-helper.h @@ -108,6 +108,29 @@ public: std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ()); + /** + * Set the class, type and attributes for the Mpdu aggregator + * + * \param ac access category for which we are setting aggregator. Possibilities + * are: AC_BK, AC_BE, AC_VI, AC_VO. + * \param type the type of ns3::MsduAggregator to create. + * \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 + * + * All the attributes specified in this method should exist + * in the requested aggregator. + */ + void SetMpduAggregatorForAc (enum AcIndex ac, std::string type, + 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 ()); //A-MPDU /** * This method sets value of block ack threshold for a specific access class. * If number of packets in the respective queue reaches this value block ack mechanism @@ -141,7 +164,8 @@ private: virtual Ptr Create (void) const; void Setup (Ptr mac, enum AcIndex ac, std::string dcaAttrName) const; - std::map m_aggregators; + std::map m_aggregators; //!< + ObjectFactory m_mpduAggregator; //!< /* * Next maps contain, for every access category, the values for * block ack threshold and block ack inactivity timeout. diff --git a/src/wifi/model/ampdu-subframe-header.cc b/src/wifi/model/ampdu-subframe-header.cc new file mode 100644 index 000000000..cffcd078d --- /dev/null +++ b/src/wifi/model/ampdu-subframe-header.cc @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#include "ampdu-subframe-header.h" +#include "ns3/address-utils.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (AmpduSubframeHeader); + +TypeId +AmpduSubframeHeader::GetTypeId () +{ + static TypeId tid = TypeId ("ns3::AmpduSubframeHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +AmpduSubframeHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +AmpduSubframeHeader::AmpduSubframeHeader () + : m_length (0) +{ +} + +AmpduSubframeHeader::~AmpduSubframeHeader () +{ +} + +uint32_t +AmpduSubframeHeader::GetSerializedSize () const +{ + return (2 + 1 + 1); +} + +void +AmpduSubframeHeader::Serialize (Buffer::Iterator i) const +{ + i.WriteHtolsbU16 (m_length); + i.WriteU8 (m_crc); + i.WriteU8 (m_sig); +} + +uint32_t +AmpduSubframeHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_length = i.ReadLsbtohU16 (); + m_crc = i.ReadU8 (); + m_sig = i.ReadU8 (); + return i.GetDistanceFrom (start); +} + +void +AmpduSubframeHeader::Print (std::ostream &os) const +{ + os << "length = " << m_length << ", CRC = " << m_crc << ", Signature = " << m_sig; +} + +void +AmpduSubframeHeader::SetCrc (uint8_t crc) +{ + m_crc = crc; +} + +void +AmpduSubframeHeader::SetSig () +{ + m_sig = 0x4E; +} + +void +AmpduSubframeHeader::SetLength (uint16_t length) +{ + m_length = length; +} + +uint8_t +AmpduSubframeHeader::GetCrc (void) const +{ + return m_crc; +} + +uint8_t +AmpduSubframeHeader::GetSig (void) const +{ + return m_sig; +} + +uint16_t +AmpduSubframeHeader::GetLength (void) const +{ + return m_length; +} + +} // namespace ns3 diff --git a/src/wifi/model/ampdu-subframe-header.h b/src/wifi/model/ampdu-subframe-header.h new file mode 100644 index 000000000..f22ddc1ce --- /dev/null +++ b/src/wifi/model/ampdu-subframe-header.h @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#ifndef AMPDU_SUBFRAME_HEADER_H +#define AMPDU_SUBFRAME_HEADER_H + +#include "ns3/header.h" +#include "ns3/mac48-address.h" + +namespace ns3 { + +/** + * \ingroup wifi + * + * + */ +class AmpduSubframeHeader : public Header +{ +public: + AmpduSubframeHeader (); + virtual ~AmpduSubframeHeader (); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * Set the CRC field. + * + * \param crc + */ + void SetCrc (uint8_t crc); + /** + * Set the SIG field. + * + * \param crc + */ + void SetSig (); + /** + * Set the length field. + * + * \param length + */ + void SetLength (uint16_t length); + /** + * Return the CRC field. + * + * \return the CRC field + */ + uint8_t GetCrc (void) const; + /** + * Return the SIG field. + * + * \return the SIG field + */ + uint8_t GetSig (void) const; + /** + * Return the length field. + * + * \return the length field + */ + uint16_t GetLength (void) const; + +private: + uint8_t m_crc; //!< CRC field + uint8_t m_sig; //!< SIG field + uint16_t m_length; //!< length field +}; + +} // namespace ns3 + +#endif /* AMPDU_SUBFRAME_HEADER_H */ diff --git a/src/wifi/model/ampdu-tag.cc b/src/wifi/model/ampdu-tag.cc new file mode 100644 index 000000000..d4c26fe98 --- /dev/null +++ b/src/wifi/model/ampdu-tag.cc @@ -0,0 +1,104 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#include "ampdu-tag.h" +#include "ns3/tag.h" +#include "ns3/uinteger.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (AmpduTag); + +TypeId +AmpduTag::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::AmpduTag") + .SetParent () + .AddConstructor () + .AddAttribute ("Ampdu Exists", "The value that indicates that the packet contains an AMPDU", + UintegerValue (false), + MakeUintegerAccessor (&AmpduTag::GetAmpdu), + MakeUintegerChecker ()) + ; + return tid; +} + +TypeId +AmpduTag::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +AmpduTag::AmpduTag () + : m_ampdu (0) +{ +} + +void +AmpduTag::SetAmpdu (bool supported) +{ + m_ampdu = supported; +} + +void +AmpduTag::SetNoOfMpdus (uint8_t noofmpdus) +{ + NS_ASSERT (noofmpdus <= 64); + m_noOfMpdus = noofmpdus; +} + +uint32_t +AmpduTag::GetSerializedSize (void) const +{ + return 2; +} + +void +AmpduTag::Serialize (TagBuffer i) const +{ + i.WriteU8 (m_ampdu); + i.WriteU8 (m_noOfMpdus); +} + +void +AmpduTag::Deserialize (TagBuffer i) +{ + m_ampdu = i.ReadU8 (); + m_noOfMpdus = i.ReadU8 (); +} + +bool +AmpduTag::GetAmpdu () const +{ + return (m_ampdu == 1) ? true : false; +} + +uint8_t +AmpduTag::GetNoOfMpdus () const +{ + return m_noOfMpdus; +} + +void +AmpduTag::Print (std::ostream &os) const +{ + os << "A-MPDU exists=" << m_ampdu; +} + +} // namespace ns3 diff --git a/src/wifi/model/ampdu-tag.h b/src/wifi/model/ampdu-tag.h new file mode 100644 index 000000000..3869f535f --- /dev/null +++ b/src/wifi/model/ampdu-tag.h @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#ifndef AMPDU_TAG_H +#define AMPDU_TAG_H + +#include "ns3/packet.h" + +namespace ns3 { + +class Tag; + +/** + * \ingroup wifi + * + * The aim of the AmpduTag is to provide means for a MAC to specify that a packet includes A-MPDU + * since this is done in HT-SIG and there is no HT-SIG representation in ns-3 + */ +class AmpduTag : public Tag +{ +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + /** + * Create a AmpduTag with the default =0 no Ampdu + */ + AmpduTag (); + /** + * Set m_ampdu to 1. + */ + void SetAmpdu (bool supported); + /** + * \param noofmpdus the number of MPDUs + * + * Set the number of MPDUs in the A-MPDU. + */ + void SetNoOfMpdus (uint8_t noofmpdus); + + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + virtual uint32_t GetSerializedSize () const; + virtual void Print (std::ostream &os) const; + + /** + * \return true if it is an A-MPDU, + * false otherwise. + * + * Returns m_ampdu + */ + bool GetAmpdu (void) const; + /** + * \return the number of MPDUs in an A-MPDU + * + * Returns the number of MPDUs in an A-MPDU + */ + uint8_t GetNoOfMpdus (void) const; + +private: + uint8_t m_ampdu; //!< Flag whether it is an A-MPDU + uint8_t m_noOfMpdus; //!< number of MPDUs in the A-MPDU +}; + +} // namespace ns3 + +#endif /* AMPDU_TAG_H */ diff --git a/src/wifi/model/block-ack-agreement.cc b/src/wifi/model/block-ack-agreement.cc index ff624f11f..be7ee2fb5 100644 --- a/src/wifi/model/block-ack-agreement.cc +++ b/src/wifi/model/block-ack-agreement.cc @@ -27,6 +27,7 @@ NS_LOG_COMPONENT_DEFINE ("BlockAckAgreement"); BlockAckAgreement::BlockAckAgreement () : m_amsduSupported (0), m_blockAckPolicy (1), + m_htSupported (0), m_inactivityEvent () { NS_LOG_FUNCTION (this); @@ -35,6 +36,7 @@ BlockAckAgreement::BlockAckAgreement () BlockAckAgreement::BlockAckAgreement (Mac48Address peer, uint8_t tid) : m_amsduSupported (0), m_blockAckPolicy (1), + m_htSupported (0), m_inactivityEvent () { NS_LOG_FUNCTION (this << peer << static_cast (tid)); @@ -137,5 +139,27 @@ BlockAckAgreement::IsAmsduSupported (void) const NS_LOG_FUNCTION (this); return (m_amsduSupported == 1) ? true : false; } +uint16_t +BlockAckAgreement::GetWinEnd (void) const +{ + return m_winEnd; +} +void +BlockAckAgreement::SetWinEnd (uint16_t seq) +{ + m_winEnd = seq; +} +void +BlockAckAgreement::SetHtSupported (bool htSupported) +{ + NS_LOG_FUNCTION (this << htSupported); + m_htSupported = htSupported; +} +bool +BlockAckAgreement::IsHtSupported (void) const +{ + NS_LOG_FUNCTION (this); + return (m_htSupported == 1) ? true : false; +} } // namespace ns3 diff --git a/src/wifi/model/block-ack-agreement.h b/src/wifi/model/block-ack-agreement.h index ebdc11776..3c3940995 100644 --- a/src/wifi/model/block-ack-agreement.h +++ b/src/wifi/model/block-ack-agreement.h @@ -73,7 +73,12 @@ public: * \param supported enable or disable A-MSDU support */ void SetAmsduSupport (bool supported); - + /** + * Set ending sequence number. + * + * \param seq the ending sequence number + */ + void SetWinEnd (uint16_t seq); /** * Return the Traffic ID (TID). * @@ -110,6 +115,12 @@ public: * \return starting sequence control */ uint16_t GetStartingSequenceControl (void) const; + /** + * Return the ending sequence number + * + * \return ending sequence number + */ + uint16_t GetWinEnd (void) const; /** * Check whether the current ACK policy is immediate block ACK. * @@ -124,17 +135,31 @@ public: * false otherwise */ bool IsAmsduSupported (void) const; + /** + * Enable or disable HT support. + * + * \param htSupported enable or disable HT support + */ + void SetHtSupported (bool htSupported); + /** + * Check whether HT is supported + * + * \return true if HT is supported, + * false otherwise + */ + bool IsHtSupported (void) const; protected: - Mac48Address m_peer; - uint8_t m_amsduSupported; - uint8_t m_blockAckPolicy; /* represents type of block ack: immediate or delayed */ - uint8_t m_tid; - uint16_t m_bufferSize; - uint16_t m_timeout; - uint16_t m_startingSeq; - - EventId m_inactivityEvent; + Mac48Address m_peer; //!< Peer address + uint8_t m_amsduSupported; //!< Flag whether MSDU aggregation is supported + uint8_t m_blockAckPolicy; //!< Type of block ack: immediate or delayed + uint8_t m_tid; //!< Traffic ID + uint16_t m_bufferSize; //!< Buffer size + uint16_t m_timeout; //!< Timeout + uint16_t m_startingSeq; //!< Starting squence control + uint16_t m_winEnd; //!< Ending sequence number + uint8_t m_htSupported; //!< Flag whether HT is supported + EventId m_inactivityEvent; //!< }; } // namespace ns3 diff --git a/src/wifi/model/block-ack-cache.cc b/src/wifi/model/block-ack-cache.cc index d580652b7..b0b71fd11 100644 --- a/src/wifi/model/block-ack-cache.cc +++ b/src/wifi/model/block-ack-cache.cc @@ -39,6 +39,12 @@ BlockAckCache::Init (uint16_t winStart, uint16_t winSize) memset (m_bitmap, 0, sizeof (m_bitmap)); } +uint16_t +BlockAckCache::GetWinStart () +{ + return m_winStart; +} + void BlockAckCache::UpdateWithMpdu (const WifiMacHeader *hdr) { diff --git a/src/wifi/model/block-ack-cache.h b/src/wifi/model/block-ack-cache.h index c16acfd26..6acadbba0 100644 --- a/src/wifi/model/block-ack-cache.h +++ b/src/wifi/model/block-ack-cache.h @@ -38,7 +38,13 @@ public: void Init (uint16_t winStart, uint16_t winSize); void UpdateWithMpdu (const WifiMacHeader *hdr); - void UpdateWithBlockAckReq (uint16_t startingSeq); + void UpdateWithBlockAckReq (uint16_t startingSeq); + /** + * When an A-MPDU is received, the window start may change to a new value + * depending on the sequence number of the received MPDU (standard11n page 134). + * This function is used to retrieve this value in order to add it to the BlockAck. + */ + uint16_t GetWinStart (void); void FillBlockAckBitmap (CtrlBAckResponseHeader *blockAckHeader); private: diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index cd3a9b932..e38fbd160 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -30,6 +30,7 @@ #include "mac-low.h" #include "wifi-mac-queue.h" #include "mac-tx-middle.h" +#include "qos-utils.h" namespace ns3 { @@ -117,9 +118,11 @@ BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Addr agreement.SetStartingSequence (reqHdr->GetStartingSequence ()); /* for now we assume that originator doesn't use this field. Use of this field is mandatory only for recipient */ - agreement.SetBufferSize (0); + agreement.SetBufferSize (64); + agreement.SetWinEnd ((agreement.GetStartingSequence()+ agreement.GetBufferSize()-1) % 4096); agreement.SetTimeout (reqHdr->GetTimeout ()); agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ()); + agreement.SetHtSupported (m_stationManager->HasHtSupported ()); if (reqHdr->IsImmediateBlockAck ()) { agreement.SetImmediateBlockAck (); @@ -214,48 +217,184 @@ BlockAckManager::StorePacket (Ptr packet, const WifiMacHeader &hdr Item item (packet, hdr, tStamp); AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); NS_ASSERT (it != m_agreements.end ()); - it->second.second.push_back (item); + PacketQueueI queueIt = it->second.second.begin (); + for (; queueIt != it->second.second.end ();) + { + if(((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047) + { + queueIt = it->second.second.insert (queueIt, item); + break; + } + else + { + queueIt++; + } + } + if(queueIt == it->second.second.end ()) + { + it->second.second.push_back (item); + } +} + +void +BlockAckManager::CompleteAmpduExchange(Mac48Address recipient, uint8_t tid) +{ + AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (it != m_agreements.end ()); + OriginatorBlockAckAgreement &agreement = (*it).second.first; + agreement.CompleteExchange (); } Ptr BlockAckManager::GetNextPacket (WifiMacHeader &hdr) + { + NS_LOG_FUNCTION (this << &hdr); + Ptr packet = 0; + uint8_t tid; + Mac48Address recipient; + CleanupBuffers (); + if (!m_retryPackets.empty()) + { + NS_LOG_DEBUG("Retry buffer size is " << m_retryPackets.size ()); + std::list::iterator it = m_retryPackets.begin (); + while (it != m_retryPackets.end ()) + { + if ((*it)->hdr.IsQosData ()) + tid = (*it)->hdr.GetQosTid (); + else + NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data"); + recipient = (*it)->hdr.GetAddr1 (); + AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (agreement != m_agreements.end()); + if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ())) + { + //standard says the originator should not send a packet with seqnum < winstart + NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ()); + agreement->second.second.erase ((*it)); + it = m_retryPackets.erase (it); + continue; + } + else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence ()+63) %4096) + { + agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ()); + } + packet = (*it)->packet->Copy(); + hdr = (*it)->hdr; + hdr.SetRetry (); + NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ()); + if (hdr.IsQosData ()) + tid = hdr.GetQosTid (); + else + NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data"); + recipient = hdr.GetAddr1 (); + if (!agreement->second.first.IsHtSupported () + && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) + || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ()))) + { + hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); + } + else + { + /* From section 9.10.3 in IEEE802.11e standard: + * In order to improve efficiency, originators using the Block Ack facility + * may send MPDU frames with the Ack Policy subfield in QoS control frames + * set to Normal Ack if only a few MPDUs are available for transmission.[...] + * When there are sufficient number of MPDUs, the originator may switch back to + * the use of Block Ack. + */ + hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); + AgreementsI i = m_agreements.find (std::make_pair (recipient, tid)); + i->second.second.erase (*it); + } + it = m_retryPackets.erase (it); + NS_LOG_DEBUG("Removed one packet retry buffer size = " < +BlockAckManager::PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp) { - NS_LOG_FUNCTION (this << &hdr); + NS_LOG_FUNCTION (this); Ptr packet = 0; CleanupBuffers (); - if (m_retryPackets.size () > 0) + AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (agreement != m_agreements.end()); + std::list::iterator it = m_retryPackets.begin (); + for (; it != m_retryPackets.end();it++) { - PacketQueueI queueIt = m_retryPackets.front (); - m_retryPackets.pop_front (); - packet = queueIt->packet; - hdr = queueIt->hdr; - hdr.SetRetry (); - NS_LOG_INFO ("Retry packet seq=" << hdr.GetSequenceNumber ()); - uint8_t tid = hdr.GetQosTid (); - Mac48Address recipient = hdr.GetAddr1 (); - - if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) - || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())) - { - hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); - } - else - { - /* From section 9.10.3 in IEEE802.11e standard: - * In order to improve efficiency, originators using the Block Ack facility - * may send MPDU frames with the Ack Policy subfield in QoS control frames - * set to Normal Ack if only a few MPDUs are available for transmission.[...] - * When there are sufficient number of MPDUs, the originator may switch back to - * the use of Block Ack. - */ - hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - AgreementsI i = m_agreements.find (std::make_pair (recipient, tid)); - i->second.second.erase (queueIt); - } + if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid) + { + if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ())) + { + //standard says the originator should not send a packet with seqnum < winstart + NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ()); + agreement->second.second.erase ((*it)); + it = m_retryPackets.erase (it); + it--; + continue; + } + else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096) + { + agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ()); + } + packet = (*it)->packet->Copy(); + hdr = (*it)->hdr; + hdr.SetRetry (); + *tstamp = (*it)->timestamp; + NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ()); + Mac48Address recipient = hdr.GetAddr1 (); + if (!agreement->second.first.IsHtSupported () + && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) + || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ()))) + { + hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); + } + else + { + /* From section 9.10.3 in IEEE802.11e standard: + * In order to improve efficiency, originators using the Block Ack facility + * may send MPDU frames with the Ack Policy subfield in QoS control frames + * set to Normal Ack if only a few MPDUs are available for transmission.[...] + * When there are sufficient number of MPDUs, the originator may switch back to + * the use of Block Ack. + */ + hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); + } + NS_LOG_DEBUG("Peeked one packet from retry buffer size = " << m_retryPackets.size () ); + return packet; + } } return packet; } +bool +BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) +{ + + std::list::iterator it = m_retryPackets.begin (); + for (; it != m_retryPackets.end (); it++) + { + if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber) + { + WifiMacHeader hdr = (*it)->hdr; + uint8_t tid = hdr.GetQosTid (); + Mac48Address recipient = hdr.GetAddr1 (); + + AgreementsI i = m_agreements.find (std::make_pair (recipient, tid)); + i->second.second.erase ((*it)); + + m_retryPackets.erase (it); + NS_LOG_DEBUG("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint32_t) tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ()); + return true; + } + } + return false; +} + bool BlockAckManager::HasBar (struct Bar &bar) { @@ -322,6 +461,11 @@ BlockAckManager::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) co it++; } } + //go to next packet + if (it != m_retryPackets.end ()) + { + it++; + } } } return nPackets; @@ -333,9 +477,30 @@ BlockAckManager::SetBlockAckThreshold (uint8_t nPackets) NS_LOG_FUNCTION (this << static_cast (nPackets)); m_blockAckThreshold = nPackets; } + +void +BlockAckManager::SetWifiRemoteStationManager (Ptr manager) +{ + NS_LOG_FUNCTION (this << manager); + m_stationManager = manager; +} + +bool +BlockAckManager::AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid) +{ + std::list::const_iterator it = m_retryPackets.begin (); + while (it != m_retryPackets.end ()) + { + NS_LOG_FUNCTION (this<<(*it)->hdr.GetType()); + if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ()) + return true; + it++; + } + return false; +} void -BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient) +BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode) { NS_LOG_FUNCTION (this << blockAck << recipient); uint16_t sequenceFirstLost = 0; @@ -377,7 +542,10 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac4 sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber (); (*it).second.first.SetStartingSequence (sequenceFirstLost); } - m_retryPackets.push_back (queueIt); + + if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid)) + InsertInRetryQueue(queueIt); + queueIt++; } } @@ -392,6 +560,12 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac4 while (queueIt != queueEnd && (*queueIt).hdr.GetSequenceNumber () == currentSeq) { + //notify remote station of successful transmission + m_stationManager->ReportDataOk ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr, 0, txMode, 0); + if (!m_txOkCallback.IsNull ()) + { + m_txOkCallback ((*queueIt).hdr); + } queueIt = it->second.second.erase (queueIt); } } @@ -403,7 +577,16 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac4 sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber (); (*it).second.first.SetStartingSequence (sequenceFirstLost); } - m_retryPackets.push_back (queueIt); + //notify remote station of unsuccessful transmission + m_stationManager->ReportDataFailed ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr); + if (!m_txFailedCallback.IsNull ()) + { + m_txFailedCallback ((*queueIt).hdr); + } + if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid)) + { + InsertInRetryQueue(queueIt); + } queueIt++; } } @@ -412,7 +595,7 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac4 if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost)) || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq))) { - it->second.first.SetState (OriginatorBlockAckAgreement::INACTIVE); + it->second.first.CompleteExchange(); } } } @@ -502,7 +685,7 @@ BlockAckManager::NotifyAgreementUnsuccessful (Mac48Address recipient, uint8_t ti } void -BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber) +BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy) { NS_LOG_FUNCTION (this << recipient << static_cast (tid) << nextSeqNumber); Ptr bar = 0; @@ -519,11 +702,14 @@ BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, ui nextSeq = nextSeqNumber; } it->second.first.NotifyMpduTransmission (nextSeq); - bar = ScheduleBlockAckReqIfNeeded (recipient, tid); - if (bar != 0) + if (policy == WifiMacHeader::BLOCK_ACK) { - Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ()); - m_bars.push_back (request); + bar = ScheduleBlockAckReqIfNeeded (recipient, tid); + if (bar != 0) + { + Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ()); + m_bars.push_back (request); + } } } @@ -588,6 +774,18 @@ BlockAckManager::GetNextPacketSize (void) const return size; } +bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient) +{ + //the standard says the BAR gets discarded when all MSDUs lifetime expires + AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (it != m_agreements.end()); + CleanupBuffers(); + if ((seqNumber+63) < it->second.first.GetStartingSequence()) + return false; + else + return true; +} + void BlockAckManager::CleanupBuffers (void) { @@ -616,7 +814,7 @@ BlockAckManager::CleanupBuffers (void) && (*it)->hdr.GetQosTid () == j->second.first.GetTid () && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ()) { - it = m_retryPackets.erase (it); + it = m_retryPackets.erase (it); } else { @@ -676,8 +874,48 @@ BlockAckManager::GetSeqNumOfNextRetryPacket (Mac48Address recipient, uint8_t tid { return (*it)->hdr.GetSequenceNumber (); } + it++; } return 4096; } +void +BlockAckManager::SetTxOkCallback (TxOk callback) +{ + m_txOkCallback = callback; +} + +void +BlockAckManager::SetTxFailedCallback (TxFailed callback) +{ + m_txFailedCallback = callback; +} + +void +BlockAckManager::InsertInRetryQueue (PacketQueueI item) +{ + NS_LOG_INFO ("Adding to retry queue " <<(*item).hdr.GetSequenceNumber ()); + if (m_retryPackets.size () == 0) + { + m_retryPackets.push_back (item); + } + else + { + for (std::list::iterator it = m_retryPackets.begin (); it != m_retryPackets.end ();) + { + if(((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047) + { + it = m_retryPackets.insert (it, item); + break; + } + else + { + it++; + if(it == m_retryPackets.end ()) + m_retryPackets.push_back (item); + } + } + } +} + } // namespace ns3 diff --git a/src/wifi/model/block-ack-manager.h b/src/wifi/model/block-ack-manager.h index 4b55f0d56..3cc549815 100644 --- a/src/wifi/model/block-ack-manager.h +++ b/src/wifi/model/block-ack-manager.h @@ -30,6 +30,8 @@ #include "originator-block-ack-agreement.h" #include "ctrl-headers.h" #include "qos-utils.h" +#include "wifi-mode.h" +#include "wifi-remote-station-manager.h" namespace ns3 { @@ -79,6 +81,13 @@ private: public: BlockAckManager (); ~BlockAckManager (); + + /** + * Set up WifiRemoteStationManager associated with this BlockAckManager. + * + * \param manager WifiRemoteStationManager associated with this BlockAckManager + */ + void SetWifiRemoteStationManager (Ptr manager); /** * \param recipient Address of peer station involved in block ack mechanism. * \param tid Traffic ID. @@ -151,13 +160,14 @@ public: /** * \param blockAck The received block ack frame. * \param recipient Sender of block ack frame. + * \param txMode mode of block ack frame. * * Invoked upon receipt of a block ack frame. Typically, this function, is called * by ns3::EdcaTxopN object. Performs a check on which MPDUs, previously sent * with ack policy set to Block Ack, were correctly received by the recipient. * An acknowledged MPDU is removed from the buffer, retransmitted otherwise. */ - void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient); + void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode); /** * \param recipient Address of peer station involved in block ack mechanism. * \param tid Traffic ID. @@ -198,12 +208,20 @@ public: * \param recipient Address of peer station involved in block ack mechanism. * \param tid Traffic ID of transmitted packet. * \param nextSeqNumber Sequence number of the next packet that would be trasmitted by EdcaTxopN. + * \param policy ack policy of the transmitted packet. * * This method is typically invoked by ns3::EdcaTxopN object every time that a MPDU * with ack policy subfield in Qos Control field set to Block Ack is transmitted. * The nextSeqNumber parameter is used to block transmission of packets that are out of bitmap. */ - void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber); + void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy); + /** + * \param recipient Address of peer station involved in block ack mechanism. + * \param tid Traffic ID of transmitted packet. + * + * This method to set the number of packets waitin for blockAck = 0 since the receiver will send the blockAck right away + */ + void CompleteAmpduExchange(Mac48Address recipient, uint8_t tid); /** * \param nPackets Minimum number of packets for use of block ack. * @@ -281,6 +299,45 @@ public: * the agreement doesn't exist the function returns 4096; */ uint16_t GetSeqNumOfNextRetryPacket (Mac48Address recipient, uint8_t tid) const; + /** + * Checks if the packet already exists in the retransmit queue or not if it does then it doesn't add it again + */ + bool AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid); + /** + * Remove a packet after you peek in the queue and get it + */ + bool RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber); + /* + * Peek in retransmit queue and get the next packet without removing it from the queue + */ + Ptr PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp); + /** + * This function returns true if the lifetime of the packets a BAR refers to didn't expire yet else it returns false. + * If it return false then the BAR will be discarded (i.e. will not be re-transmitted) + */ + bool NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient); + + /** + * typedef for a callback to invoke when a + * packet transmission was completed successfully. + */ + typedef Callback TxOk; + /** + * typedef for a callback to invoke when a + * packet transmission was failed. + */ + typedef Callback TxFailed; + /** + * \param callback the callback to invoke when a + * packet transmission was completed successfully. + */ + void SetTxOkCallback (TxOk callback); + /** + * \param callback the callback to invoke when a + * packet transmission was completed unsuccessfully. + */ + void SetTxFailedCallback (TxFailed callback); + private: /** * \param recipient @@ -343,6 +400,13 @@ private: WifiMacHeader hdr; Time timestamp; }; + /** + * \param item + * + * Insert item in retransmission queue. + * This method ensures packets are retransmitted in the correct order. + */ + void InsertInRetryQueue (PacketQueueI item); /** * This data structure contains, for each block ack agreement (recipient, tid), a set of packets @@ -368,6 +432,9 @@ private: Callback m_blockAckInactivityTimeout; Callback m_blockPackets; Callback m_unblockPackets; + TxOk m_txOkCallback; + TxFailed m_txFailedCallback; + Ptr m_stationManager; //!< }; } // namespace ns3 diff --git a/src/wifi/model/edca-txop-n.cc b/src/wifi/model/edca-txop-n.cc index 67d2a9f04..55871170b 100644 --- a/src/wifi/model/edca-txop-n.cc +++ b/src/wifi/model/edca-txop-n.cc @@ -103,9 +103,9 @@ public: { m_txop->MissedAck (); } - virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source) + virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode) { - m_txop->GotBlockAck (blockAck, source); + m_txop->GotBlockAck (blockAck, source,txMode); } virtual void MissedBlockAck (void) { @@ -123,6 +123,10 @@ public: { m_txop->EndTxNoAck (); } + virtual Ptr GetQueue (void) + { + return m_txop->GetEdcaQueue (); + } private: EdcaTxopN *m_txop; @@ -141,6 +145,50 @@ public: { m_txop->SendDelbaFrame (address, tid, false); } + virtual Ptr GetQueue (void) + { + return m_txop->GetEdcaQueue (); + } + virtual void CompleteTransfer (Mac48Address recipient, uint8_t tid) + { + m_txop->CompleteAmpduTransfer (recipient, tid); + } + virtual void SetAmpdu(bool ampdu) + { + return m_txop->SetAmpduExist (ampdu); + } + virtual void CompleteMpduTx(Ptr packet, WifiMacHeader hdr, Time tstamp) + { + m_txop->CompleteMpduTx (packet, hdr, tstamp); + } + virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr) + { + return m_txop->GetNextSequenceNumberfor (hdr); + } + virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr) + { + return m_txop->PeekNextSequenceNumberfor (hdr); + } + virtual Ptr PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp) + { + return m_txop->PeekNextRetransmitPacket (header, recipient, tid, timestamp); + } + virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) + { + m_txop->RemoveRetransmitPacket(tid, recipient, seqnumber); + } + virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid) + { + return m_txop->GetBaAgreementExists (address,tid); + } + virtual uint32_t GetNOutstandingPackets (Mac48Address address, uint8_t tid) + { + return m_txop->GetNOutstandingPacketsInBa (address, tid); + } + virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const + { + return m_txop->GetNRetryNeededPackets (recipient, tid); + } private: EdcaTxopN *m_txop; @@ -169,7 +217,7 @@ EdcaTxopN::GetTypeId (void) MakeUintegerChecker ()) .AddAttribute ("Queue", "The WifiMacQueue object", PointerValue (), - MakePointerAccessor (&EdcaTxopN::GetQueue), + MakePointerAccessor (&EdcaTxopN::GetEdcaQueue), MakePointerChecker ()) ; return tid; @@ -179,7 +227,8 @@ EdcaTxopN::EdcaTxopN () : m_manager (0), m_currentPacket (0), m_aggregator (0), - m_blockAckType (COMPRESSED_BLOCK_ACK) + m_blockAckType (COMPRESSED_BLOCK_ACK), + m_ampduExist (false) { NS_LOG_FUNCTION (this); m_transmissionListener = new EdcaTxopN::TransmissionListener (this); @@ -194,6 +243,8 @@ EdcaTxopN::EdcaTxopN () m_baManager->SetBlockDestinationCallback (MakeCallback (&QosBlockedDestinations::Block, m_qosBlockedDestinations)); m_baManager->SetUnblockDestinationCallback (MakeCallback (&QosBlockedDestinations::Unblock, m_qosBlockedDestinations)); m_baManager->SetMaxPacketDelay (m_queue->GetMaxDelay ()); + m_baManager->SetTxOkCallback (MakeCallback (&EdcaTxopN::BaTxOk, this)); + m_baManager->SetTxFailedCallback (MakeCallback (&EdcaTxopN::BaTxFailed, this)); } EdcaTxopN::~EdcaTxopN () @@ -224,6 +275,30 @@ EdcaTxopN::DoDispose (void) m_aggregator = 0; } +bool +EdcaTxopN::GetBaAgreementExists (Mac48Address address, uint8_t tid) +{ + return m_baManager->ExistsAgreement (address, tid); +} + +uint32_t +EdcaTxopN::GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid) +{ + return m_baManager->GetNBufferedPackets (address, tid); +} + +uint32_t +EdcaTxopN::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const +{ + return m_baManager->GetNRetryNeededPackets (recipient, tid); +} + +void +EdcaTxopN::CompleteAmpduTransfer (Mac48Address recipient, uint8_t tid) +{ + m_baManager->CompleteAmpduExchange (recipient, tid); +} + void EdcaTxopN::SetManager (DcfManager *manager) { @@ -251,6 +326,7 @@ EdcaTxopN::SetWifiRemoteStationManager (Ptr remoteMana { NS_LOG_FUNCTION (this << remoteManager); m_stationManager = remoteManager; + m_baManager->SetWifiRemoteStationManager(m_stationManager); } void EdcaTxopN::SetTypeOfStation (enum TypeOfStation type) @@ -267,7 +343,7 @@ EdcaTxopN::GetTypeOfStation (void) const } Ptr -EdcaTxopN::GetQueue () const +EdcaTxopN::GetEdcaQueue () const { NS_LOG_FUNCTION (this); return m_queue; @@ -343,6 +419,28 @@ EdcaTxopN::NeedsAccess (void) const return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets (); } +uint16_t EdcaTxopN::GetNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return m_txMiddle->GetNextSequenceNumberfor (hdr); +} + +uint16_t EdcaTxopN::PeekNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return m_txMiddle->PeekNextSequenceNumberfor (hdr); +} + +Ptr +EdcaTxopN::PeekNextRetransmitPacket (WifiMacHeader &header,Mac48Address recipient, uint8_t tid, Time *timestamp) +{ + return m_baManager->PeekNextPacket (header,recipient,tid, timestamp); +} + +void +EdcaTxopN::RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) +{ + m_baManager->RemovePacket (tid, recipient, seqnumber); +} + void EdcaTxopN::NotifyAccessGranted (void) { @@ -413,7 +511,7 @@ EdcaTxopN::NotifyAccessGranted (void) } else { - if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ()) + if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ()) { params.DisableAck (); } @@ -449,9 +547,10 @@ EdcaTxopN::NotifyAccessGranted (void) else { WifiMacHeader peekedHdr; + Time tstamp; if (m_currentHdr.IsQosData () && m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (), - WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ()) + WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp) && !m_currentHdr.GetAddr1 ().IsBroadcast () && m_aggregator != 0 && !m_currentHdr.IsRetry ()) { @@ -464,7 +563,7 @@ EdcaTxopN::NotifyAccessGranted (void) bool isAmsdu = false; Ptr peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (), WifiMacHeader::ADDR1, - m_currentHdr.GetAddr1 ()); + m_currentHdr.GetAddr1 (), &tstamp); while (peekedPacket != 0) { aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket, @@ -480,7 +579,7 @@ EdcaTxopN::NotifyAccessGranted (void) break; } peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (), - WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ()); + WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp); } if (isAmsdu) { @@ -504,7 +603,8 @@ EdcaTxopN::NotifyAccessGranted (void) params.DisableNextData (); m_low->StartTransmission (m_currentPacket, &m_currentHdr, params, m_transmissionListener); - CompleteTx (); + if(!GetAmpduExist()) + CompleteTx (); } } } @@ -543,6 +643,10 @@ EdcaTxopN::MissedCts (void) { m_txFailedCallback (m_currentHdr); } + if (GetAmpduExist()) + { + m_low->FlushAggregateQueue (); + } // to reset the dcf. m_currentPacket = 0; m_dcf->ResetCw (); @@ -650,8 +754,36 @@ EdcaTxopN::MissedAck (void) { m_txFailedCallback (m_currentHdr); } - // to reset the dcf. - m_currentPacket = 0; + if (!GetAmpduExist()) + { + // to reset the dcf. + m_currentPacket = 0; + } + else + { + NS_LOG_DEBUG ("Transmit Block Ack Request"); + CtrlBAckRequestHeader reqHdr; + reqHdr.SetType (COMPRESSED_BLOCK_ACK); + uint8_t tid = m_currentHdr.GetQosTid (); + reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr)); + reqHdr.SetTidInfo (tid); + reqHdr.SetHtImmediateAck(true); + Ptr bar = Create (); + bar->AddHeader (reqHdr); + Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck()); + m_currentBar = request; + WifiMacHeader hdr; + hdr.SetType (WIFI_MAC_CTL_BACKREQ); + hdr.SetAddr1 (request.recipient); + hdr.SetAddr2 (m_low->GetAddress ()); + hdr.SetAddr3 (m_low->GetBssid ()); + hdr.SetDsNotTo (); + hdr.SetDsNotFrom (); + hdr.SetNoRetry (); + hdr.SetNoMoreFragments (); + m_currentPacket = request.bar; + m_currentHdr = hdr; + } m_dcf->ResetCw (); } else @@ -669,11 +801,68 @@ EdcaTxopN::MissedBlockAck (void) { NS_LOG_FUNCTION (this); NS_LOG_DEBUG ("missed block ack"); - //should i report this to station addressed by ADDR1? - NS_LOG_DEBUG ("Retransmit block ack request"); - m_currentHdr.SetRetry (); - m_dcf->UpdateFailedCw (); + if (NeedBarRetransmission()) + { + if (!GetAmpduExist()) + { + //should i report this to station addressed by ADDR1? + NS_LOG_DEBUG ("Retransmit block ack request"); + m_currentHdr.SetRetry (); + } + else + { + //standard says when loosing a BlockAck originator may send a BAR page 139 + NS_LOG_DEBUG ("Transmit Block Ack Request"); + CtrlBAckRequestHeader reqHdr; + reqHdr.SetType (COMPRESSED_BLOCK_ACK); + uint8_t tid = 0; + if (m_currentHdr.IsQosData()) + { + tid = m_currentHdr.GetQosTid (); + reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ()); + } + else if (m_currentHdr.IsBlockAckReq()) + { + CtrlBAckRequestHeader baReqHdr; + m_currentPacket->PeekHeader (baReqHdr); + tid = baReqHdr.GetTidInfo (); + reqHdr.SetStartingSequence (baReqHdr.GetStartingSequence ()); + } + else if (m_currentHdr.IsBlockAck()) + { + CtrlBAckResponseHeader baRespHdr; + m_currentPacket->PeekHeader (baRespHdr); + tid = baRespHdr.GetTidInfo(); + reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ()); + } + reqHdr.SetTidInfo (tid); + reqHdr.SetHtImmediateAck (true); + Ptr bar = Create (); + bar->AddHeader (reqHdr); + Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ()); + m_currentBar = request; + WifiMacHeader hdr; + hdr.SetType (WIFI_MAC_CTL_BACKREQ); + hdr.SetAddr1 (request.recipient); + hdr.SetAddr2 (m_low->GetAddress ()); + hdr.SetAddr3 (m_low->GetBssid ()); + hdr.SetDsNotTo (); + hdr.SetDsNotFrom (); + hdr.SetNoRetry (); + hdr.SetNoMoreFragments (); + m_currentPacket = request.bar; + m_currentHdr = hdr; + } + m_dcf->UpdateFailedCw (); + } + else + { + NS_LOG_DEBUG ("Block Ack Request Fail"); + // to reset the dcf. + m_currentPacket = 0; + m_dcf->ResetCw (); + } m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ())); RestartAccessIfNeeded (); } @@ -732,6 +921,33 @@ EdcaTxopN::NeedDataRetransmission (void) m_currentPacket); } +bool +EdcaTxopN::NeedBarRetransmission (void) +{ + uint8_t tid = 0; + uint16_t seqNumber = 0; + if (m_currentHdr.IsQosData ()) + { + tid = m_currentHdr.GetQosTid (); + seqNumber = m_currentHdr.GetSequenceNumber (); + } + else if (m_currentHdr.IsBlockAckReq ()) + { + CtrlBAckRequestHeader baReqHdr; + m_currentPacket->PeekHeader (baReqHdr); + tid = baReqHdr.GetTidInfo (); + seqNumber = baReqHdr.GetStartingSequence (); + } + else if (m_currentHdr.IsBlockAck ()) + { + CtrlBAckResponseHeader baRespHdr; + m_currentPacket->PeekHeader (baRespHdr); + tid = baRespHdr.GetTidInfo (); + seqNumber = m_currentHdr.GetSequenceNumber (); + } + return m_baManager->NeedBarRetransmission (tid, seqNumber, m_currentHdr.GetAddr1 ()); +} + void EdcaTxopN::NextFragment (void) { @@ -932,11 +1148,15 @@ EdcaTxopN::GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient } void -EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient) +EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode) { NS_LOG_FUNCTION (this << blockAck << recipient); NS_LOG_DEBUG ("got block ack from=" << recipient); - m_baManager->NotifyGotBlockAck (blockAck, recipient); + m_baManager->NotifyGotBlockAck (blockAck, recipient, txMode); + if (!m_txOkCallback.IsNull ()) + { + m_txOkCallback (m_currentHdr); + } m_currentPacket = 0; m_dcf->ResetCw (); m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ())); @@ -956,10 +1176,20 @@ EdcaTxopN::VerifyBlockAck (void) } if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED)) { - m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); + m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); } } +bool EdcaTxopN::GetAmpduExist(void) +{ + return m_ampduExist; +} + +void EdcaTxopN::SetAmpduExist(bool ampdu) +{ + m_ampduExist = ampdu; +} + void EdcaTxopN::CompleteTx (void) { @@ -972,10 +1202,19 @@ EdcaTxopN::CompleteTx (void) } m_baManager->NotifyMpduTransmission (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid (), m_txMiddle->GetNextSeqNumberByTidAndAddress (m_currentHdr.GetQosTid (), - m_currentHdr.GetAddr1 ())); + m_currentHdr.GetAddr1 ()), WifiMacHeader::BLOCK_ACK); } } +void +EdcaTxopN::CompleteMpduTx (Ptr packet, WifiMacHeader hdr, Time tstamp) +{ + m_baManager->StorePacket (packet, hdr, tstamp); + m_baManager->NotifyMpduTransmission (hdr.GetAddr1 (), hdr.GetQosTid (), + m_txMiddle->GetNextSeqNumberByTidAndAddress (hdr.GetQosTid (), + hdr.GetAddr1 ()), WifiMacHeader::NORMAL_ACK); +} + bool EdcaTxopN::SetupBlockAckIfNeeded () { @@ -1184,4 +1423,25 @@ EdcaTxopN::DoInitialize () m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ())); ns3::Dcf::DoInitialize (); } + +void +EdcaTxopN::BaTxOk (const WifiMacHeader &hdr) +{ + NS_LOG_FUNCTION (this << hdr); + if (!m_txOkCallback.IsNull ()) + { + m_txOkCallback (m_currentHdr); + } +} + +void +EdcaTxopN::BaTxFailed (const WifiMacHeader &hdr) +{ + NS_LOG_FUNCTION (this << hdr); + if (!m_txFailedCallback.IsNull ()) + { + m_txFailedCallback (m_currentHdr); + } +} + } // namespace ns3 diff --git a/src/wifi/model/edca-txop-n.h b/src/wifi/model/edca-txop-n.h index 229ef1476..fa2bb3be5 100644 --- a/src/wifi/model/edca-txop-n.h +++ b/src/wifi/model/edca-txop-n.h @@ -141,13 +141,12 @@ public: * \return type of station */ enum TypeOfStation GetTypeOfStation (void) const; - /** * Return the packet queue associated with this EdcaTxopN. * * \return WifiMacQueue */ - Ptr GetQueue () const; + Ptr GetEdcaQueue () const; virtual void SetMinCw (uint32_t minCw); virtual void SetMaxCw (uint32_t maxCw); virtual void SetAifsn (uint32_t aifsn); @@ -162,6 +161,39 @@ public: */ Ptr Low (void); Ptr GetMsduAggregator (void) const; + /** + * \param recipient address of the peer station + * \param tid traffic ID. + * \return true if a block ack agreement exists, false otherwise + * + * Checks if a block ack agreement exists with station addressed by + * recipient for tid tid. + */ + bool GetBaAgreementExists (Mac48Address address, uint8_t tid); + /** + * \param recipient address of peer station involved in block ack mechanism. + * \param tid traffic ID. + * \return the number of packets buffered for a specified agreement + * + * Returns number of packets buffered for a specified agreement. + */ + uint32_t GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid); + /** + * \param recipient address of peer station involved in block ack mechanism. + * \param tid traffic ID. + * \return the number of packets for a specific agreement that need retransmission + * + * Returns number of packets for a specific agreement that need retransmission. + */ + uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const; + /** + * \param recipient address of peer station involved in block ack mechanism. + * \param tid Ttraffic ID of transmitted packet. + * + * This function resets the status of OriginatorBlockAckAgreement after the transfer + * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled) + */ + void CompleteAmpduTransfer(Mac48Address recipient, uint8_t tid); /* dcf notifications forwarded here */ /** @@ -220,8 +252,9 @@ public: * * \param blockAck * \param recipient + * \param txMode */ - void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient); + void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode); /** * Event handler when a Block ACK timeout has occurred. */ @@ -246,7 +279,6 @@ public: * does not require an ACK has completed. */ void EndTxNoAck (void); - /** * Restart access request if needed. */ @@ -273,6 +305,12 @@ public: * \return true if DATA should be re-transmitted, false otherwise */ bool NeedDataRetransmission (void); + /** + * Check if Block ACK Request should be re-transmitted. + * + * \return true if BAR should be re-transmitted, false otherwise + */ + bool NeedBarRetransmission (void); /** * Check if the current packet should be fragmented. * @@ -319,7 +357,6 @@ public: * \return the fragment with the current fragment number */ Ptr GetFragmentPacket (WifiMacHeader *hdr); - /** * Set the access category of this EDCAF. * @@ -360,8 +397,46 @@ public: * \return the current threshold for block ACK mechanism */ uint8_t GetBlockAckThreshold (void) const; + void SetBlockAckInactivityTimeout (uint16_t timeout); void SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator); + void CompleteMpduTx (Ptr packet, WifiMacHeader hdr, Time tstamp); + bool GetAmpduExist (void); + void SetAmpduExist (bool ampdu); + /** + * Return the next sequence number for the given header. + * + * \param hdr Wi-Fi header + * \return the next sequence number + */ + uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr); + /** + * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged). + * + * \param hdr Wi-Fi header + * \return the next sequence number + */ + uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr); + /** + * Remove a packet after you peek in the retransmit queue and get it + */ + void RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber); + /* + * Peek in retransmit queue and get the next packet without removing it from the queue + */ + Ptr PeekNextRetransmitPacket (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp); + /** + * The packet we sent was successfully received by the receiver + * + * \param hdr the header of the packet that we successfully sent + */ + void BaTxOk (const WifiMacHeader &hdr); + /** + * The packet we sent was successfully received by the receiver + * + * \param hdr the header of the packet that we failed to sent + */ + void BaTxFailed (const WifiMacHeader &hdr); /** * Assign a fixed random variable stream number to the random variables @@ -466,6 +541,7 @@ private: Time m_currentPacketTimestamp; uint16_t m_blockAckInactivityTimeout; struct Bar m_currentBar; + bool m_ampduExist; }; } // namespace ns3 diff --git a/src/wifi/model/mac-low.cc b/src/wifi/model/mac-low.cc index 7595a1684..a43c80ffa 100644 --- a/src/wifi/model/mac-low.cc +++ b/src/wifi/model/mac-low.cc @@ -34,6 +34,10 @@ #include "qos-utils.h" #include "edca-txop-n.h" #include "snr-tag.h" +#include "yans-wifi-phy.h" +#include "ampdu-tag.h" +#include "wifi-mac-queue.h" +#include "mpdu-aggregator.h" #undef NS_LOG_APPEND_CONTEXT #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] " @@ -50,8 +54,7 @@ MacLowTransmissionListener::~MacLowTransmissionListener () { } void -MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck, - Mac48Address source) +MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode mode) { } void @@ -72,6 +75,46 @@ MacLowBlockAckEventListener::~MacLowBlockAckEventListener () { } +void MacLowBlockAckEventListener::SetAmpdu (bool ampdu) +{ +} +void MacLowBlockAckEventListener::CompleteTransfer(Mac48Address address, uint8_t tid) +{ +} +void +MacLowBlockAckEventListener::CompleteMpduTx (Ptr packet, WifiMacHeader hdr, Time tstamp) +{ +} +uint16_t +MacLowBlockAckEventListener::GetNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return 0; +} +uint16_t +MacLowBlockAckEventListener::PeekNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return 0; +} +Ptr +MacLowBlockAckEventListener::PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp) +{ + return 0; +} +void +MacLowBlockAckEventListener::RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) +{ +} +uint32_t +MacLowBlockAckEventListener::GetNOutstandingPackets (Mac48Address recipient, uint8_t tid) +{ + return 0; +} +uint32_t +MacLowBlockAckEventListener::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const +{ + return 0; +} + MacLowTransmissionParameters::MacLowTransmissionParameters () : m_nextSize (0), m_waitAck (ACK_NONE), @@ -304,15 +347,20 @@ MacLow::MacLow () m_sendDataEvent (), m_waitSifsEvent (), m_endTxNoAckEvent (), + m_mpduAggregator (0), m_currentPacket (0), m_listener (0), m_phyMacLowListener (0), - m_ctsToSelfSupported (false) + m_ctsToSelfSupported (false), + m_receivedAtLeastOneMpdu (false) { NS_LOG_FUNCTION (this); m_lastNavDuration = Seconds (0); m_lastNavStart = Seconds (0); m_promisc = false; + m_ampdu = false; + m_sentMpdus = 0; + m_aggregateQueue = CreateObject (); } MacLow::~MacLow () @@ -361,6 +409,10 @@ MacLow::DoDispose (void) delete m_phyMacLowListener; m_phyMacLowListener = 0; } + m_mpduAggregator = 0; + m_sentMpdus = 0; + m_aggregateQueue = 0; + m_ampdu = false; } void @@ -439,7 +491,7 @@ void MacLow::SetPhy (Ptr phy) { m_phy = phy; - m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this)); + m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this)); m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this)); SetupPhyMacLowListener (phy); } @@ -594,6 +646,22 @@ MacLow::RegisterDcfListener (MacLowDcfListener *listener) m_dcfListeners.push_back (listener); } +bool +MacLow::IsAmpdu (Ptr packet, const WifiMacHeader hdr) +{ + uint32_t size, actualSize; + WifiMacTrailer fcs; + size = packet->GetSize () + hdr.GetSize () + fcs.GetSerializedSize (); + Ptr p = AggregateToAmpdu (packet, hdr); + actualSize = p->GetSize(); + if (actualSize > size) + { + m_currentPacket = p; + return true; + } + else + return false; +} void MacLow::StartTransmission (Ptr packet, @@ -616,7 +684,6 @@ MacLow::StartTransmission (Ptr packet, * QapScheduler has taken access to the channel from * one of the Edca of the QAP. */ - m_currentPacket = packet->Copy (); m_currentHdr = *hdr; CancelAllEvents (); m_listener = listener; @@ -624,9 +691,26 @@ MacLow::StartTransmission (Ptr packet, //NS_ASSERT (m_phy->IsStateIdle ()); + if(m_aggregateQueue->GetSize () == 0) + { + m_currentPacket = packet->Copy (); + m_ampdu = IsAmpdu (m_currentPacket, m_currentHdr); + } + else + { + /*m_aggregateQueue > 0 occurs when a RTS/CTS exchange failed before an A-MPDU transmission. + *In that case, we transmit the same A-MPDU as previously. + */ + m_sentMpdus = m_aggregateQueue->GetSize (); + m_ampdu = true; + } + NS_LOG_DEBUG ("startTx size=" << GetSize (m_currentPacket, &m_currentHdr) << ", to=" << m_currentHdr.GetAddr1 () << ", listener=" << m_listener); + if (m_ampdu) + m_txParams.EnableCompressedBlockAck (); + if (m_txParams.MustSendRts ()) { SendRtsForPacket (); @@ -657,7 +741,33 @@ MacLow::ReceiveError (Ptr packet, double rxSnr) { NS_LOG_FUNCTION (this << packet << rxSnr); NS_LOG_DEBUG ("rx failed "); - if (m_txParams.MustWaitFastAck ()) + AmpduTag ampdu; + Ptr pkt = packet->Copy(); + bool isInAmpdu = pkt->RemovePacketTag(ampdu); + + if(isInAmpdu && m_receivedAtLeastOneMpdu && (ampdu.GetNoOfMpdus() == 1)) + { + MpduAggregator::DeaggregatedMpdus packets = MpduAggregator::Deaggregate (pkt); + MpduAggregator::DeaggregatedMpdusCI n = packets.begin (); + WifiMacHeader hdr; + (*n).first->PeekHeader(hdr); + if(hdr.IsQosData()) + { + NS_LOG_DEBUG ("last a-mpdu subframe detected/sendImmediateBlockAck from=" << hdr.GetAddr2 ()); + m_sendAckEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendBlockAckAfterAmpdu, this, + hdr.GetQosTid(), + hdr.GetAddr2 (), + hdr.GetDuration (), + m_currentMode); + } + else if (hdr.IsBlockAckReq()) + { + NS_LOG_DEBUG("last a-mpdu subframe is BAR"); + } + m_receivedAtLeastOneMpdu = false; + } + else if (m_txParams.MustWaitFastAck ()) { NS_ASSERT (m_fastAckFailedTimeoutEvent.IsExpired ()); m_fastAckFailedTimeoutEvent = Simulator::Schedule (GetSifs (), @@ -698,7 +808,7 @@ MacLow::NotifySleepNow (void) } void -MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamble preamble) +MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamble preamble, bool ampduSubframe) { NS_LOG_FUNCTION (this << packet << rxSnr << txMode << preamble); /* A packet is received from the PHY. @@ -720,23 +830,30 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb * idle. If the NAV at the STA receiving the RTS indicates the medium is not idle, * that STA shall not respond to the RTS frame. */ - if (isPrevNavZero - && hdr.GetAddr1 () == m_self) + if (ampduSubframe) { - NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS"); - NS_ASSERT (m_sendCtsEvent.IsExpired ()); - m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr, - rxSnr, txMode); - m_sendCtsEvent = Simulator::Schedule (GetSifs (), - &MacLow::SendCtsAfterRts, this, - hdr.GetAddr2 (), - hdr.GetDuration (), - txMode, - rxSnr); + NS_FATAL_ERROR ("Received RTS as part of an A-MPDU"); } else { - NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS"); + if (isPrevNavZero + && hdr.GetAddr1 () == m_self) + { + NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS"); + NS_ASSERT (m_sendCtsEvent.IsExpired ()); + m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr, + rxSnr, txMode); + m_sendCtsEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendCtsAfterRts, this, + hdr.GetAddr2 (), + hdr.GetDuration (), + txMode, + rxSnr); + } + else + { + NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS"); + } } } else if (hdr.IsCts () @@ -744,6 +861,10 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb && m_ctsTimeoutEvent.IsRunning () && m_currentPacket != 0) { + if (ampduSubframe) + { + NS_FATAL_ERROR ("Received CTS as part of an A-MPDU"); + } NS_LOG_DEBUG ("receive cts from=" << m_currentHdr.GetAddr1 ()); SnrTag tag; packet->RemovePacketTag (tag); @@ -776,6 +897,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb rxSnr, txMode); m_stationManager->ReportDataOk (m_currentHdr.GetAddr1 (), &m_currentHdr, rxSnr, txMode, tag.Get ()); + bool gotAck = false; if (m_txParams.MustWaitNormalAck () && m_normalAckTimeoutEvent.IsRunning ()) @@ -809,7 +931,10 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb CtrlBAckResponseHeader blockAck; packet->RemoveHeader (blockAck); m_blockAckTimeoutEvent.Cancel (); - m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 ()); + NotifyAckTimeoutResetNow (); + m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 (),txMode); + m_sentMpdus = 0; + m_ampdu = false; } else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self) { @@ -843,6 +968,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb { NS_FATAL_ERROR ("Delayed block ack not supported."); } + m_receivedAtLeastOneMpdu = false; } else { @@ -857,22 +983,24 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb else if (hdr.IsCtl ()) { NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ()); + m_receivedAtLeastOneMpdu = false; } else if (hdr.GetAddr1 () == m_self) { m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr, rxSnr, txMode); - - if (hdr.IsQosData () && StoreMpduIfNeeded (packet, hdr)) + if (hdr.IsQosData () && ReceiveMpdu (packet, hdr)) { /* From section 9.10.4 in IEEE 802.11: Upon the receipt of a QoS data frame from the originator for which the Block Ack agreement exists, the recipient shall buffer the MSDU regardless of the value of the Ack Policy subfield within the - QoS Control field of the QoS data frame. */ - if (hdr.IsQosAck ()) + QoS Control field of the QoS data frame. */; + if (hdr.IsQosAck () && !ampduSubframe) { + NS_LOG_DEBUG ("rx QoS unicast/sendAck from=" << hdr.GetAddr2 ()); AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ())); + RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (), hdr.GetAddr2 (), hdr.GetQosTid ()); RxCompleteBufferedPacketsUntilFirstLost (hdr.GetAddr2 (), hdr.GetQosTid ()); @@ -883,6 +1011,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb hdr.GetDuration (), txMode, rxSnr); + m_receivedAtLeastOneMpdu = false; } else if (hdr.IsQosBlockAck ()) { @@ -908,31 +1037,53 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb } else if (hdr.IsQosData () && hdr.IsQosNoAck ()) { - NS_LOG_DEBUG ("rx unicast/noAck from=" << hdr.GetAddr2 ()); + if (ampduSubframe) + { + NS_LOG_DEBUG ("rx Ampdu with No Ack Policy from=" << hdr.GetAddr2 ()); + } + else + { + NS_LOG_DEBUG ("rx unicast/noAck from=" << hdr.GetAddr2 ()); + } } else if (hdr.IsData () || hdr.IsMgt ()) { - NS_LOG_DEBUG ("rx unicast/sendAck from=" << hdr.GetAddr2 ()); - NS_ASSERT (m_sendAckEvent.IsExpired ()); - m_sendAckEvent = Simulator::Schedule (GetSifs (), - &MacLow::SendAckAfterData, this, - hdr.GetAddr2 (), - hdr.GetDuration (), - txMode, - rxSnr); + if (hdr.IsMgt() && ampduSubframe) + { + NS_FATAL_ERROR ("Received management packet as part of an A-MPDU"); + } + else + { + NS_LOG_DEBUG ("rx unicast/sendAck from=" << hdr.GetAddr2 ()); + NS_ASSERT (m_sendAckEvent.IsExpired ()); + m_sendAckEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendAckAfterData, this, + hdr.GetAddr2 (), + hdr.GetDuration (), + txMode, + rxSnr); + } } goto rxPacket; } else if (hdr.GetAddr1 ().IsGroup ()) { - if (hdr.IsData () || hdr.IsMgt ()) + if (ampduSubframe) { - NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ()); - goto rxPacket; + NS_FATAL_ERROR ("Received group addressed packet as part of an A-MPDU"); } else { - // DROP + if (hdr.IsData () || hdr.IsMgt ()) + { + NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ()); + m_receivedAtLeastOneMpdu = false; + goto rxPacket; + } + else + { + // DROP + } } } else if (m_promisc) @@ -955,6 +1106,27 @@ rxPacket: return; } +uint8_t +MacLow::GetTid (Ptr packet, const WifiMacHeader hdr) const +{ + uint8_t tid = 0; + if (hdr.IsQosData ()) + tid = hdr.GetQosTid (); + else if (hdr.IsBlockAckReq ()) + { + CtrlBAckRequestHeader baReqHdr; + packet->PeekHeader (baReqHdr); + tid = baReqHdr.GetTidInfo(); + } + else if (hdr.IsBlockAck ()) + { + CtrlBAckResponseHeader baRespHdr; + packet->PeekHeader (baRespHdr); + tid = baRespHdr.GetTidInfo (); + } + return tid; +} + uint32_t MacLow::GetAckSize (void) const { @@ -1004,7 +1176,7 @@ MacLow::GetAckDuration (WifiTxVector ackTxVector) const preamble= WIFI_PREAMBLE_HT_MF; else preamble=WIFI_PREAMBLE_LONG; - return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, preamble, m_phy->GetFrequency()); + return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, preamble, m_phy->GetFrequency(), 0, 0); } Time MacLow::GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const @@ -1022,7 +1194,7 @@ MacLow::GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, preamble= WIFI_PREAMBLE_HT_MF; else preamble=WIFI_PREAMBLE_LONG; - return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency()); + return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency(), 0, 0); } Time MacLow::GetCtsDuration (Mac48Address to, WifiTxVector rtsTxVector) const @@ -1039,7 +1211,7 @@ MacLow::GetCtsDuration (WifiTxVector ctsTxVector) const preamble= WIFI_PREAMBLE_HT_MF; else preamble=WIFI_PREAMBLE_LONG; - return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency()); + return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency(), 0, 0); } uint32_t MacLow::GetCtsSize (void) const @@ -1051,8 +1223,13 @@ MacLow::GetCtsSize (void) const uint32_t MacLow::GetSize (Ptr packet, const WifiMacHeader *hdr) const { + uint32_t size; WifiMacTrailer fcs; - return packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize (); + if (m_ampdu) + size = packet->GetSize (); + else + size= packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize (); + return size; } WifiTxVector @@ -1127,7 +1304,7 @@ MacLow::CalculateOverallTxTime (Ptr packet, { preamble = WIFI_PREAMBLE_LONG; } - txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency()); + txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency(), 0, 0); txTime += GetCtsDuration (hdr->GetAddr1 (), rtsTxVector); txTime += Time (GetSifs () * 2); } @@ -1140,7 +1317,7 @@ MacLow::CalculateOverallTxTime (Ptr packet, else preamble=WIFI_PREAMBLE_LONG; uint32_t dataSize = GetSize (packet, hdr); - txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency()); + txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); if (params.MustWaitAck ()) { txTime += GetSifs (); @@ -1167,7 +1344,7 @@ MacLow::CalculateTransmissionTime (Ptr packet, else preamble=WIFI_PREAMBLE_LONG; txTime += GetSifs (); - txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency()); + txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); } return txTime; } @@ -1205,7 +1382,7 @@ MacLow::NotifyNav (Ptr packet,const WifiMacHeader &hdr, WifiMode t cts.SetType (WIFI_MAC_CTL_CTS); WifiTxVector txVector=GetRtsTxVector (packet, &hdr); Time navCounterResetCtsMissedDelay = - m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, preamble, m_phy->GetFrequency()) + + m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, preamble, m_phy->GetFrequency(), 0, 0) + Time (2 * GetSifs ()) + Time (2 * GetSlotTime ()); m_navCounterResetCtsMissed = Simulator::Schedule (navCounterResetCtsMissedDelay, &MacLow::NavCounterResetCtsMissed, this, @@ -1294,7 +1471,61 @@ MacLow::ForwardDown (Ptr packet, const WifiMacHeader* hdr, ", mode=" << txVector.GetMode() << ", duration=" << hdr->GetDuration () << ", seq=0x" << std::hex << m_currentHdr.GetSequenceControl () << std::dec); - m_phy->SendPacket (packet, txVector, preamble); + if (!m_ampdu || hdr->IsRts ()) + { + m_phy->SendPacket (packet, txVector, preamble, 0); + } + else + { + Ptr newPacket; + Ptr dequeuedPacket; + WifiMacHeader newHdr; + WifiMacTrailer fcs; + uint32_t queueSize = m_aggregateQueue->GetSize (); + bool last = false; + uint8_t packetType = 0; + //Add packet tag + AmpduTag ampdutag; + ampdutag.SetAmpdu (true); + Time delay = Seconds (0); + for ( ; queueSize > 0; queueSize--) + { + dequeuedPacket = m_aggregateQueue->Dequeue (&newHdr); + newPacket = dequeuedPacket->Copy (); + newHdr.SetDuration (hdr->GetDuration ()); + newPacket->AddHeader (newHdr); + newPacket->AddTrailer (fcs); + if (queueSize == 1) + { + last = true; + packetType = 2; + } + m_mpduAggregator->AddHeaderAndPad (newPacket, last); + + ampdutag.SetNoOfMpdus(queueSize); + newPacket->AddPacketTag(ampdutag); + if (delay == Seconds (0)) + { + NS_LOG_DEBUG("Sending MPDU as part of A-MPDU"); + packetType = 1; + m_phy->SendPacket (newPacket, txVector, preamble, packetType); + } + else + { + Simulator::Schedule (delay, &MacLow::SendPacket, this, newPacket, txVector, preamble, packetType); + } + if(queueSize > 1) + delay = delay + m_phy->CalculateTxDuration (GetSize (newPacket, &newHdr), txVector, preamble, m_phy->GetFrequency(), packetType, 0); + preamble = WIFI_PREAMBLE_NONE; + } + } +} + +void +MacLow::SendPacket (Ptr packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType) +{ + NS_LOG_DEBUG("Sending MPDU as part of A-MPDU"); + m_phy->SendPacket (packet, txVector, preamble, packetType); } void @@ -1306,9 +1537,14 @@ MacLow::CtsTimeout (void) /// we should restart a new cts timeout now until the expected /// end of rx if there was a rx start before now. m_stationManager->ReportRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); - m_currentPacket = 0; + if(m_sentMpdus == 0) + { + m_currentPacket = 0; + } MacLowTransmissionListener *listener = m_listener; m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; listener->MissedCts (); } void @@ -1322,6 +1558,8 @@ MacLow::NormalAckTimeout (void) m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); MacLowTransmissionListener *listener = m_listener; m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; listener->MissedAck (); } void @@ -1350,6 +1588,8 @@ MacLow::BlockAckTimeout (void) m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); MacLowTransmissionListener *listener = m_listener; m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; listener->MissedBlockAck (); } void @@ -1407,13 +1647,36 @@ MacLow::SendRtsForPacket (void) duration += GetCtsDuration (m_currentHdr.GetAddr1 (), rtsTxVector); duration += GetSifs (); duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), - dataTxVector, preamble, m_phy->GetFrequency()); + dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); duration += GetSifs (); - duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + if (m_txParams.MustWaitBasicBlockAck ()) + { + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2(), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK); + } + else if (m_txParams.MustWaitCompressedBlockAck ()) + { + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2(), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); + } + else if (m_txParams.MustWaitAck ()) + { + duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + } + if (m_txParams.HasNextPacket ()) + { + duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), + dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); + if (m_txParams.MustWaitAck ()) + { + duration += GetSifs (); + duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + } + } } rts.SetDuration (duration); - Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency()); + Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency(), 0, 0); Time timerDelay = txDuration + GetCtsTimeout (); NS_ASSERT (m_ctsTimeoutEvent.IsExpired ()); @@ -1441,7 +1704,7 @@ MacLow::StartDataTxTimers (WifiTxVector dataTxVector) else preamble=WIFI_PREAMBLE_LONG; - Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency()); + Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); if (m_txParams.MustWaitNormalAck ()) { Time timerDelay = txDuration + GetAckTimeout (); @@ -1528,12 +1791,14 @@ MacLow::SendDataPacket (void) if (m_txParams.MustWaitBasicBlockAck ()) { duration += GetSifs (); - duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, BASIC_BLOCK_ACK); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK); } else if (m_txParams.MustWaitCompressedBlockAck ()) { duration += GetSifs (); - duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); } else if (m_txParams.MustWaitAck ()) { @@ -1544,7 +1809,7 @@ MacLow::SendDataPacket (void) { duration += GetSifs (); duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), - dataTxVector, preamble, m_phy->GetFrequency()); + dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); if (m_txParams.MustWaitAck ()) { duration += GetSifs (); @@ -1554,9 +1819,12 @@ MacLow::SendDataPacket (void) } m_currentHdr.SetDuration (duration); - m_currentPacket->AddHeader (m_currentHdr); - WifiMacTrailer fcs; - m_currentPacket->AddTrailer (fcs); + if (!m_ampdu) + { + m_currentPacket->AddHeader (m_currentHdr); + WifiMacTrailer fcs; + m_currentPacket->AddTrailer (fcs); + } ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector,preamble); m_currentPacket = 0; @@ -1604,17 +1872,19 @@ MacLow::SendCtsToSelf (void) WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); duration += GetSifs (); duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket,&m_currentHdr), - dataTxVector, preamble, m_phy->GetFrequency()); + dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); if (m_txParams.MustWaitBasicBlockAck ()) { duration += GetSifs (); - duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, BASIC_BLOCK_ACK); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK); } else if (m_txParams.MustWaitCompressedBlockAck ()) { duration += GetSifs (); - duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); } else if (m_txParams.MustWaitAck ()) { @@ -1625,11 +1895,12 @@ MacLow::SendCtsToSelf (void) { duration += GetSifs (); duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), - dataTxVector, preamble, m_phy->GetFrequency()); + dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); if (m_txParams.MustWaitCompressedBlockAck ()) { duration += GetSifs (); - duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); } else if (m_txParams.MustWaitAck ()) { @@ -1648,7 +1919,7 @@ MacLow::SendCtsToSelf (void) ForwardDown (packet, &cts, ctsTxVector,preamble); - Time txDuration = m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency()); + Time txDuration = m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency(), 0, 0); txDuration += GetSifs (); NS_ASSERT (m_sendDataEvent.IsExpired ()); @@ -1716,10 +1987,41 @@ MacLow::SendDataAfterCts (Mac48Address source, Time duration, WifiMode txMode) StartDataTxTimers (dataTxVector); Time newDuration = Seconds (0); - newDuration += GetSifs (); - newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); - Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), - dataTxVector, preamble, m_phy->GetFrequency()); + if (m_txParams.MustWaitBasicBlockAck ()) + { + newDuration += GetSifs (); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK); + } + else if (m_txParams.MustWaitCompressedBlockAck ()) + { + newDuration += GetSifs (); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); + } + else if (m_txParams.MustWaitAck ()) + { + newDuration += GetSifs (); + newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + } + if (m_txParams.HasNextPacket ()) + { + newDuration += GetSifs (); + newDuration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); + if (m_txParams.MustWaitCompressedBlockAck ()) + { + newDuration += GetSifs (); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode()); + newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK); + } + else if (m_txParams.MustWaitAck ()) + { + newDuration += GetSifs (); + newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + } + } + + Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr),dataTxVector, preamble, m_phy->GetFrequency(), 0, 0); duration -= txDuration; duration -= GetSifs (); @@ -1727,9 +2029,12 @@ MacLow::SendDataAfterCts (Mac48Address source, Time duration, WifiMode txMode) NS_ASSERT (duration >= MicroSeconds (0)); m_currentHdr.SetDuration (duration); - m_currentPacket->AddHeader (m_currentHdr); - WifiMacTrailer fcs; - m_currentPacket->AddTrailer (fcs); + if (!m_ampdu) + { + m_currentPacket->AddHeader (m_currentHdr); + WifiMacTrailer fcs; + m_currentPacket->AddTrailer (fcs); + } ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector,preamble); m_currentPacket = 0; @@ -1797,6 +2102,53 @@ MacLow::SendAckAfterData (Mac48Address source, Time duration, WifiMode dataTxMod ForwardDown (packet, &ack, ackTxVector, preamble); } +bool +MacLow::IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize) +{ + return ((seq - winstart+ 4096) % 4096) < winsize; +} + +bool +MacLow::ReceiveMpdu (Ptr packet, WifiMacHeader hdr) + { + if (m_stationManager->HasHtSupported ()) + { + Mac48Address originator = hdr.GetAddr2 (); + uint8_t tid = 0; + if (hdr.IsQosData ()) + tid = hdr.GetQosTid (); + uint16_t seqNumber = hdr.GetSequenceNumber (); + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid)); + if (it != m_bAckAgreements.end ()) + { + //Implement HT immediate Block Ack support for HT Delayed Block Ack is not added yet + if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence (), seqNumber)) + { + StoreMpduIfNeeded (packet, hdr); + if (!IsInWindow(hdr.GetSequenceNumber (), (*it).second.first.GetStartingSequence (), (*it).second.first.GetBufferSize ())) + { + uint16_t delta = (seqNumber - (*it).second.first.GetWinEnd()+ 4096) % 4096; + if (delta > 1) + { + (*it).second.first.SetWinEnd (seqNumber); + int16_t winEnd = (*it).second.first.GetWinEnd (); + int16_t bufferSize = (*it).second.first.GetBufferSize (); + uint16_t sum = ((uint16_t)(std::abs(winEnd - bufferSize + 1))) % 4096; + (*it).second.first.SetStartingSequence (sum); + RxCompleteBufferedPacketsWithSmallerSequence ((*it).second.first.GetStartingSequence (), originator, tid); + } + } + RxCompleteBufferedPacketsUntilFirstLost (originator, tid); //forwards up packets starting from winstart and set winstart to last +1 + (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1)%4096); + } + return true; + } + return false; + } + else + return StoreMpduIfNeeded (packet,hdr); +} + bool MacLow::StoreMpduIfNeeded (Ptr packet, WifiMacHeader hdr) { @@ -1822,7 +2174,6 @@ MacLow::StoreMpduIfNeeded (Ptr packet, WifiMacHeader hdr) BlockAckCachesI j = m_bAckCaches.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ())); NS_ASSERT (j != m_bAckCaches.end ()); (*j).second.UpdateWithMpdu (&hdr); - return true; } return false; @@ -1894,8 +2245,10 @@ MacLow::RxCompleteBufferedPacketsWithSmallerSequence (uint16_t seq, Mac48Address { uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096; uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence); - uint16_t guard = (*it).second.second.begin ()->second.GetSequenceControl () & 0xfff0; BufferedPacketI last = (*it).second.second.begin (); + uint16_t guard; + if (last != (*it).second.second.end ()) + guard = (*it).second.second.begin ()->second.GetSequenceControl () & 0xfff0; BufferedPacketI i = (*it).second.second.begin (); for (; i != (*it).second.second.end () @@ -1977,7 +2330,6 @@ MacLow::RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_ (*it).second.second.erase ((*it).second.second.begin (), lastComplete); } } - void MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate, Time duration, WifiMode blockAckReqTxMode) @@ -1994,11 +2346,7 @@ MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Addre hdr.SetNoRetry (); hdr.SetNoMoreFragments (); - WifiTxVector blockAckTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode); - WifiTxVector blockAckReqTxVector; - blockAckReqTxVector.SetMode(blockAckReqTxMode); - blockAckReqTxVector.SetNss(1); - blockAckReqTxVector.SetStbc(false); + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode); m_currentPacket = packet; m_currentHdr = hdr; @@ -2029,7 +2377,7 @@ MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Addre if (!immediate) { - StartDataTxTimers (blockAckTxVector); + StartDataTxTimers (blockAckReqTxVector); } NS_ASSERT (duration >= MicroSeconds (0)); @@ -2039,14 +2387,35 @@ MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Addre packet->AddHeader (hdr); WifiMacTrailer fcs; packet->AddTrailer (fcs); - WifiPreamble preamble; - if (blockAckTxVector.GetMode().GetModulationClass () == WIFI_MOD_CLASS_HT) + WifiPreamble preamble; + if (blockAckReqTxVector.GetMode().GetModulationClass () == WIFI_MOD_CLASS_HT) preamble= WIFI_PREAMBLE_HT_MF; else preamble=WIFI_PREAMBLE_LONG; - ForwardDown (packet, &hdr, blockAckTxVector,preamble); + ForwardDown (packet, &hdr, blockAckReqTxVector, preamble); m_currentPacket = 0; } +void +MacLow::SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator, Time duration, WifiMode blockAckReqTxMode) +{ + NS_LOG_FUNCTION (this); + CtrlBAckResponseHeader blockAck; + uint16_t seqNumber = 0; + BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid)); + NS_ASSERT (i != m_bAckCaches.end ()); + seqNumber = (*i).second.GetWinStart (); + + bool immediate = true; + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid)); + blockAck.SetStartingSequence (seqNumber); + blockAck.SetTidInfo (tid); + immediate = (*it).second.first.IsImmediateBlockAck (); + blockAck.SetType (COMPRESSED_BLOCK_ACK); + NS_LOG_DEBUG ("Got Implicit block Ack Req with seq " << seqNumber); + (*i).second.FillBlockAckBitmap (&blockAck); + + SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode); +} void MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator, @@ -2054,7 +2423,7 @@ MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Ma { NS_LOG_FUNCTION (this); CtrlBAckResponseHeader blockAck; - uint8_t tid; + uint8_t tid = 0; bool immediate = false; if (!reqHdr.IsMultiTid ()) { @@ -2076,12 +2445,27 @@ MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Ma BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid)); NS_ASSERT (i != m_bAckCaches.end ()); (*i).second.FillBlockAckBitmap (&blockAck); + NS_LOG_DEBUG ("Got block Ack Req with seq " << reqHdr.GetStartingSequence ()); - /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac - * See 9.10.3 in IEEE 802.11e standard. - */ - RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid); - RxCompleteBufferedPacketsUntilFirstLost (originator, tid); + if (!m_stationManager->HasHtSupported()) + { + /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac + * See 9.10.3 in IEEE 802.11e standard. + */ + RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid); + RxCompleteBufferedPacketsUntilFirstLost (originator, tid); + } + else + { + if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence(), reqHdr.GetStartingSequence ())) + { + (*it).second.first.SetStartingSequence(reqHdr.GetStartingSequence ()); + (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1) % 4096); + RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid); + RxCompleteBufferedPacketsUntilFirstLost (originator, tid); + (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1) % 4096); + } + } } else { @@ -2104,7 +2488,6 @@ MacLow::ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement) NS_ASSERT (agreement.m_inactivityEvent.IsRunning ()); agreement.m_inactivityEvent.Cancel (); Time timeout = MicroSeconds (1024 * agreement.GetTimeout ()); - AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ()); //std::map::iterator it = m_edcaListeners.find (ac); //NS_ASSERT (it != m_edcaListeners.end ()); @@ -2123,4 +2506,311 @@ MacLow::RegisterBlockAckListenerForAc (enum AcIndex ac, MacLowBlockAckEventListe m_edcaListeners.insert (std::make_pair (ac, listener)); } +void +MacLow::SetMpduAggregator (Ptr aggregator) +{ + m_mpduAggregator = aggregator; +} + +void +MacLow::DeaggregateAmpduAndReceive (Ptr aggregatedPacket, double rxSnr, WifiMode txMode, WifiPreamble preamble) +{ + m_currentMode = txMode; + AmpduTag ampdu; + bool normalAck = false; + bool ampduSubframe = false; + if (aggregatedPacket->RemovePacketTag(ampdu)) + { + ampduSubframe = true; + MpduAggregator::DeaggregatedMpdus packets = MpduAggregator::Deaggregate (aggregatedPacket); + MpduAggregator::DeaggregatedMpdusCI n = packets.begin (); + + WifiMacHeader firsthdr; + (*n).first->PeekHeader(firsthdr); + NS_LOG_DEBUG ("duration/id=" << firsthdr.GetDuration ()); + NotifyNav ((*n).first,firsthdr, txMode, preamble); + if (firsthdr.GetAddr1 () == m_self) + { + m_receivedAtLeastOneMpdu = true; + if (firsthdr.IsAck () || firsthdr.IsBlockAck () || firsthdr.IsBlockAckReq ()) + ReceiveOk ((*n).first, rxSnr, txMode, preamble, ampduSubframe); + else if (firsthdr.IsData () || firsthdr.IsQosData ()) + { + NS_LOG_DEBUG ("Deaagregate packet with sequence=" << firsthdr.GetSequenceNumber ()); + ReceiveOk ((*n).first, rxSnr, txMode, preamble, ampduSubframe); + if (firsthdr.IsQosAck ()) + { + NS_LOG_DEBUG ("Normal Ack"); + normalAck = true; + } + } + else + NS_FATAL_ERROR ("Received A-MPDU with invalid first MPDU type"); + } + + if (normalAck && (ampdu.GetNoOfMpdus () == 1)) + { + //send block Ack + if (firsthdr.IsBlockAckReq ()) + { + NS_FATAL_ERROR ("Sending a BlockAckReq with QosPolicy equal to Normal Ack"); + } + uint8_t tid = firsthdr.GetQosTid (); + AgreementsI it = m_bAckAgreements.find (std::make_pair (firsthdr.GetAddr2 (), tid)); + if (it != m_bAckAgreements.end ()) + { + NS_ASSERT (m_sendAckEvent.IsExpired ()); + /* See section 11.5.3 in IEEE 802.11 for mean of this timer */ + ResetBlockAckInactivityTimerIfNeeded (it->second.first); + NS_LOG_DEBUG ("rx A-MPDU/sendImmediateBlockAck from=" << firsthdr.GetAddr2 ()); + m_sendAckEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendBlockAckAfterAmpdu, this, + firsthdr.GetQosTid(), + firsthdr.GetAddr2 (), + firsthdr.GetDuration (), + txMode); + } + else + { + NS_LOG_DEBUG ("There's not a valid agreement for this block ack request."); + } + m_receivedAtLeastOneMpdu = false; + } + } + else + { + ReceiveOk (aggregatedPacket,rxSnr, txMode, preamble, ampduSubframe); + } +} + +bool +MacLow::StopAggregation(Ptr peekedPacket, WifiMacHeader peekedHdr, Ptr aggregatedPacket, uint16_t size) const +{ + WifiPreamble preamble; + WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); + if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ())) + preamble = WIFI_PREAMBLE_HT_GF; + else + preamble = WIFI_PREAMBLE_HT_MF; + + if (peekedPacket == 0) + return true; + + //An HT STA shall not transmit a PPDU that has a duration that is greater than aPPDUMaxTime (10 milliseconds) + if(m_phy->CalculateTxDuration (aggregatedPacket->GetSize () + peekedPacket->GetSize () + peekedHdr.GetSize () +WIFI_MAC_FCS_LENGTH,dataTxVector, preamble, m_phy->GetFrequency(), 0, 0) > MilliSeconds(10)) + return true; + + if (!m_mpduAggregator->CanBeAggregated (peekedPacket->GetSize () + peekedHdr.GetSize () + WIFI_MAC_FCS_LENGTH, aggregatedPacket, size)) + return true; + + return false; +} + +Ptr +MacLow::AggregateToAmpdu (Ptr packet, const WifiMacHeader hdr) +{ + NS_ASSERT (m_aggregateQueue->GetSize () == 0); + bool isAmpdu = false; + Ptr newPacket; + WifiMacHeader peekedHdr; + newPacket = packet->Copy(); + //missing hdr.IsAck() since we have no means of knowing the Tid of the Ack yet + if (hdr.IsQosData() || hdr.IsBlockAck()|| hdr.IsBlockAckReq()) + { + Time tstamp; + uint8_t tid = GetTid (packet, hdr); + Ptr queue; + AcIndex ac = QosUtilsMapTidToAc (tid); + //since a blockack agreement always preceeds mpdu aggregation there should always exist blockAck listener + std::map::const_iterator listenerIt= m_edcaListeners.find(ac); + NS_ASSERT (listenerIt != m_edcaListeners.end ()); + queue = listenerIt->second->GetQueue(); + + if (!hdr.GetAddr1 ().IsBroadcast () && m_mpduAggregator!= 0) + { + //Have to make sure that their exist a block Ack agreement before sending an AMPDU (BlockAck Manager) + if (listenerIt->second->GetBlockAckAgreementExists (hdr.GetAddr1(), tid)) + { + /* here is performed mpdu aggregation */ + /* MSDU aggregation happened in edca if the user asked for it so m_currentPacket may contains a normal packet or a A-MSDU*/ + Ptr currentAggregatedPacket = Create (); + peekedHdr = hdr; + uint16_t startingSequenceNumber = 0; + uint16_t currentSequenceNumber = 0; + uint8_t qosPolicy = 0; + uint16_t blockAckSize = 0; + bool aggregated = false; + int i = 0; + Ptr aggPacket = newPacket->Copy (); + + if (!hdr.IsBlockAckReq()) + { + if (!hdr.IsBlockAck()) + { + startingSequenceNumber = peekedHdr.GetSequenceNumber(); + peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); + } + currentSequenceNumber = peekedHdr.GetSequenceNumber(); + newPacket->AddHeader (peekedHdr); + WifiMacTrailer fcs; + newPacket->AddTrailer (fcs); + + aggregated=m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket); + + if (aggregated) + { + NS_LOG_DEBUG ("Adding packet with Sequence number " << peekedHdr.GetSequenceNumber()<<" to A-MPDU"); + i++; + m_sentMpdus++; + m_aggregateQueue->Enqueue (aggPacket, peekedHdr); + } + } + else if (hdr.IsBlockAckReq()) + { + blockAckSize = packet->GetSize() + hdr.GetSize() + WIFI_MAC_FCS_LENGTH; + qosPolicy = 3; //if the last subrame is block ack req then set ack policy of all frames to blockack + CtrlBAckRequestHeader blockAckReq; + packet->PeekHeader (blockAckReq); + startingSequenceNumber = blockAckReq.GetStartingSequence (); + } + aggregated = false; + bool retry = false; + //looks for other packets to the same destination with the same Tid need to extend that to include MSDUs + Ptr peekedPacket = listenerIt->second->PeekNextPacketInBaQueue (peekedHdr, peekedHdr.GetAddr1 (), tid, &tstamp); + if (peekedPacket == 0) + { + peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid, + WifiMacHeader::ADDR1, + hdr.GetAddr1 (), &tstamp); + currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr); + } + else + { + retry = true; + currentSequenceNumber = peekedHdr.GetSequenceNumber(); + } + + while (IsInWindow (currentSequenceNumber, startingSequenceNumber, 64) && !StopAggregation (peekedPacket, peekedHdr, currentAggregatedPacket, blockAckSize)) +//&& listenerIt->second->GetNOutstandingPackets (hdr.GetAddr1(), tid) < 63 + { + //for now always send AMPDU with normal ACK + if (retry == false) + { + currentSequenceNumber = listenerIt->second->GetNextSequenceNumberfor (&peekedHdr); + peekedHdr.SetSequenceNumber (currentSequenceNumber); + peekedHdr.SetFragmentNumber (0); + peekedHdr.SetNoMoreFragments (); + peekedHdr.SetNoRetry (); + } + if (qosPolicy == 0) + peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); + else + peekedHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); + + newPacket = peekedPacket->Copy (); + Ptr aggPacket = newPacket->Copy (); + + newPacket->AddHeader (peekedHdr); + WifiMacTrailer fcs; + newPacket->AddTrailer (fcs); + aggregated = m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket); + if (aggregated) + { + m_aggregateQueue->Enqueue (aggPacket, peekedHdr); + if (i == 1 && hdr.IsQosData ()) + { + listenerIt->second->CompleteMpduTx (packet, hdr, tstamp); + } + NS_LOG_DEBUG ("Adding packet with Sequence number " << peekedHdr.GetSequenceNumber()<<" to A-MPDU"); + i++; + isAmpdu = true; + m_sentMpdus++; + listenerIt->second->CompleteMpduTx (peekedPacket, peekedHdr, tstamp); + if (retry) + listenerIt->second->RemoveFromBaQueue(tid, hdr.GetAddr1 (), peekedHdr.GetSequenceNumber ()); + else + queue->Remove (peekedPacket); + newPacket = 0; + } + else + break; + if (retry == true) + { + peekedPacket = listenerIt->second->PeekNextPacketInBaQueue(peekedHdr, hdr.GetAddr1(), tid, &tstamp); + if (peekedPacket == 0) + { + //I reached the first packet that I added to this A-MPDU + retry = false; + peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid, + WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp); + if (peekedPacket != 0) + { + //find what will the sequence number be so that we don't send more than 64 packets apart + currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr); + } + } + else + currentSequenceNumber = peekedHdr.GetSequenceNumber(); + } + else + { + peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid, + WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp); + if (peekedPacket != 0) + { + //find what will the sequence number be so that we don't send more than 64 packets apart + currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr); + } + } + } + if (isAmpdu) + { + if (hdr.IsBlockAckReq()) + { + newPacket = packet->Copy(); + peekedHdr = hdr; + Ptr aggPacket = newPacket->Copy(); + m_aggregateQueue->Enqueue (aggPacket, peekedHdr); + newPacket->AddHeader (peekedHdr); + WifiMacTrailer fcs; + newPacket->AddTrailer (fcs); + m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket); + } + if (qosPolicy==0) + { + listenerIt->second->CompleteTransfer(hdr.GetAddr1 (),tid); + } + //Add packet tag + AmpduTag ampdutag; + ampdutag.SetAmpdu (true); + ampdutag.SetNoOfMpdus(i); + newPacket = currentAggregatedPacket; + newPacket->AddPacketTag(ampdutag); + currentAggregatedPacket = 0; + NS_LOG_DEBUG ("tx unicast A-MPDU"); + listenerIt->second->SetAmpdu(true); + } + else + { + uint32_t queueSize = m_aggregateQueue->GetSize (); + NS_ASSERT (queueSize <= 2); //since it is not an A-MPDU then only 2 packets should have been added to the queue no more + if (queueSize >= 1) + { + //remove any packets that we added to the aggregate queue + FlushAggregateQueue (); + } + } + } + } + } + return newPacket; +} + +void +MacLow::FlushAggregateQueue (void) +{ + NS_LOG_DEBUG("Flush aggregate queue"); + m_aggregateQueue->Flush (); +} + } // namespace ns3 diff --git a/src/wifi/model/mac-low.h b/src/wifi/model/mac-low.h index a41328ca7..030dbbcdb 100644 --- a/src/wifi/model/mac-low.h +++ b/src/wifi/model/mac-low.h @@ -42,12 +42,14 @@ #include "qos-utils.h" #include "block-ack-cache.h" #include "wifi-tx-vector.h" +#include "mpdu-aggregator.h" namespace ns3 { class WifiPhy; class WifiMac; class EdcaTxopN; +class WifiMacQueue; /** * \ingroup wifi @@ -90,6 +92,7 @@ public: /** * \param blockAck Block ack response header * \param source Address of block ack sender + * \param txMode mode of block ack response * * Invoked when ns3::MacLow receives a block ack frame. * Block ack frame is received after a block ack request @@ -99,7 +102,7 @@ public: * queue that intends to be notified by MacLow of reception * of a block ack must redefine this function. */ - virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source); + virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode); /** * ns3::MacLow did not receive an expected BLOCK_ACK within * BlockAckTimeout. This method is used only for immediate @@ -117,15 +120,13 @@ public: * with the "next" data to send. */ virtual void StartNext (void) = 0; - /** * Invoked if this transmission was canceled * one way or another. When this method is invoked, * you can assume that the packet has not been passed * down the stack to the PHY. */ - virtual void Cancel (void) = 0; - + virtual void Cancel (void) = 0; /** * Invoked upon the end of the transmission of a frame that does not * require an ACK (e.g., broadcast and multicast frames). @@ -205,6 +206,72 @@ public: * \param tid */ virtual void BlockAckInactivityTimeout (Mac48Address originator, uint8_t tid) = 0; + /** + * Returns the EDCA queue to check if there are packets that can be aggregated with a Block Ack + */ + virtual Ptr GetQueue (void) = 0; + /** + * \param address address of peer station involved in block ack mechanism. + * \param tid traffic ID of transmitted packet. + * + * Calls CompleteAmpduTransfer that resets the status of OriginatorBlockAckAgreement after the transfer + * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled) + */ + virtual void CompleteTransfer (Mac48Address address, uint8_t tid); + virtual void SetAmpdu (bool ampdu); + /** + * This function stores an MPDU (part of an A-MPDU) in blockackagreement (i.e. the sender is waiting + * for a blockack containing the sequence number of this MPDU). + * It also calls NotifyMpdu transmission that updates the status of OriginatorBlockAckAgreement. + */ + virtual void CompleteMpduTx (Ptr packet, WifiMacHeader hdr, Time tstamp); + /** + * Return the next sequence number for the given header. + * + * \param hdr Wi-Fi header + * \return the next sequence number + */ + virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr); + /** + * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged). + * + * \param hdr Wi-Fi header + * \return the next sequence number + */ + virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr); + /* + * Peek in retransmit queue and get the next packet without removing it from the queue + */ + virtual Ptr PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp); + /** + * Remove a packet after you peek in the retransmit queue and get it + */ + virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber); + /** + * \param recipient address of the peer station + * \param tid traffic ID. + * \return true if a block ack agreement exists, false otherwise + * + * Checks if a block ack agreement exists with station addressed by + * recipient for tid tid. + */ + virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid) = 0; + /** + * \param recipient address of peer station involved in block ack mechanism. + * \param tid traffic ID. + * \return the number of packets buffered for a specified agreement + * + * Returns number of packets buffered for a specified agreement. + */ + virtual uint32_t GetNOutstandingPackets (Mac48Address recipient, uint8_t tid); + /** + * \param recipient address of peer station involved in block ack mechanism. + * \param tid traffic ID. + * \return the number of packets for a specific agreement that need retransmission + * + * Returns number of packets for a specific agreement that need retransmission. + */ + virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const; }; /** @@ -276,7 +343,6 @@ public: * the current transmission + SIFS. */ void EnableNextData (uint32_t size); - /** * \param durationId the value to set in the duration/Id field of * the outgoing packet. @@ -285,7 +351,6 @@ public: * packet's durationId field to this value. */ void EnableOverrideDurationId (Time durationId); - /** * Do not wait for Ack after data transmission. Typically * used for Broadcast and multicast frames. @@ -305,7 +370,6 @@ public: * calling WifiPhy::Send. */ void DisableOverrideDurationId (void); - /** * \returns true if must wait for ACK after data transmission, * false otherwise. @@ -441,7 +505,12 @@ public: * \param manager WifiRemoteStationManager associated with this MacLow */ void SetWifiRemoteStationManager (Ptr manager); - + /** + * Set up MpduAggregator associated with this MacLow. + * + * \param aggregator MpduAggregator associated with this MacLow + */ + void SetMpduAggregator (Ptr aggregator); /** * Set MAC address of this MacLow. * @@ -631,11 +700,12 @@ public: * \param rxSnr snr of packet received * \param txMode transmission mode of packet received * \param preamble type of preamble used for the packet received + * \param ampduSubframe true if this MPDU is part of an A-MPDU * * This method is typically invoked by the lower PHY layer to notify * the MAC layer that a packet was successfully received. */ - void ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamble preamble); + void ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamble preamble, bool ampduSubframe); /** * \param packet packet received. * \param rxSnr snr of packet received. @@ -693,6 +763,43 @@ public: * associated to this AC. */ void RegisterBlockAckListenerForAc (enum AcIndex ac, MacLowBlockAckEventListener *listener); + /** + * \param packet the packet to be aggregated. If the aggregation is succesfull, it corresponds either to the first data packet that will be aggregated or to the BAR that will be piggybacked at the end of the A-MPDU. + * \param hdr the WifiMacHeader for the packet. + * \return the A-MPDU packet if aggregation is successfull, the input packet otherwise + * + * This function adds the packets that will be added to an A-MPDU to an aggregate queue + * + */ + Ptr AggregateToAmpdu (Ptr packet, const WifiMacHeader hdr); + /** + * \param aggregatedPacket which is the current A-MPDU + * \param rxSnr snr of packet received + * \param txMode transmission mode of packet received + * \param preamble type of preamble used for the packet received + * + * This function de-aggregates an A-MPDU and decide if each MPDU is received correctly or not + * + */ + void DeaggregateAmpduAndReceive (Ptr aggregatedPacket, double rxSnr, WifiMode txMode, WifiPreamble preamble); + /** + * \param peekedPacket the packet to be aggregated + * \param peekedHdr the WifiMacHeader for the packet. + * \param aggregatedPacket the current A-MPDU + * \param size the size of a piggybacked block ack request + * \return false if the given packet can be added to an A-MPDU, true otherwise + * + * This function decides if a given packet can be added to an A-MPDU or not + * + */ + bool StopAggregation (Ptr peekedPacket, WifiMacHeader peekedHdr, Ptr aggregatedPacket, uint16_t size) const; + /** + * + * This function is called to flush the aggregate queue, which is used for A-MPDU + * + */ + void FlushAggregateQueue (void); + protected: /** * Return a TXVECTOR for the DATA frame given the destination. @@ -745,7 +852,7 @@ private: */ uint32_t GetSize (Ptr packet, const WifiMacHeader *hdr) const; /** - * Forward the packet down to WifiPhy for transmission. + * Forward the packet down to WifiPhy for transmission. This is called for the entire A-MPDu when MPDU aggregation is used. * * \param packet * \param hdr @@ -754,6 +861,15 @@ private: */ void ForwardDown (Ptr packet, const WifiMacHeader *hdr, WifiTxVector txVector, WifiPreamble preamble); + /** + * Forward the packet down to WifiPhy for transmission. This is called for each MPDU when MPDU aggregation is used. + * + * \param packet + * \param hdr + * \param txVector + * \param preamble + */ + void SendPacket (Ptr packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType); /** * Return a TXVECTOR for the RTS frame given the destination. * The function consults WifiRemoteStationManager, which controls the rate @@ -797,7 +913,6 @@ private: * \return TXVECTOR for the Block ACK */ WifiTxVector GetBlockAckTxVector (Mac48Address to, WifiMode dataTxMode) const; - /** * Return a TXVECTOR for the CTS-to-self frame. * The function consults WifiRemoteStationManager, which controls the rate @@ -808,7 +923,6 @@ private: * \return TXVECTOR for the CTS-to-self operation */ WifiTxVector GetCtsToSelfTxVector (Ptr packet, const WifiMacHeader *hdr) const; - /** * Return a TXVECTOR for the CTS frame given the destination and the mode of the RTS * used by the sender. @@ -831,7 +945,6 @@ private: * \return TXVECTOR for the Block ACK */ WifiTxVector GetAckTxVectorForData (Mac48Address to, WifiMode dataTxMode) const; - /** * Return the time required to transmit the CTS (including preamble and FCS). * @@ -864,8 +977,16 @@ private: * \return the time required to transmit the ACK (including preamble and FCS) */ Time GetAckDuration (Mac48Address to, WifiTxVector dataTxVector) const; + /** + * Return the time required to transmit the Block ACK to the specified address + * given the TXVECTOR of the BAR (including preamble and FCS). + * + * \param to + * \param dataTxVector + * \param type the Block ACK type + * \return the time required to transmit the Block ACK (including preamble and FCS) + */ Time GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const; - /** * Check if CTS-to-self mechanism should be used for the current packet. * @@ -924,7 +1045,6 @@ private: * CTS timer should be resetted. */ void NotifyCtsTimeoutResetNow (); - /** * Reset NAV after CTS was missed when the NAV was * setted with RTS. @@ -932,7 +1052,6 @@ private: * \param rtsEndRxTime */ void NavCounterResetCtsMissed (Time rtsEndRxTime); - /* Event handlers */ /** * Event handler when normal ACK timeout occurs. @@ -997,7 +1116,6 @@ private: * A transmission that does not require an ACK has completed. */ void EndTxNoAck (void); - /** * Send RTS to begin RTS-CTS-DATA-ACK transaction. */ @@ -1014,7 +1132,16 @@ private: * \param dataTxVector */ void StartDataTxTimers (WifiTxVector dataTxVector); + virtual void DoDispose (void); + + /** + * \param packet packet to check + * \param hdr 802.11 header for packet to check + * + * Returns Tid of different packet types + */ + uint8_t GetTid(Ptr packet, const WifiMacHeader hdr) const; /** * \param originator Address of peer participating in Block Ack mechanism. * \param tid TID for which Block Ack was created. @@ -1037,7 +1164,20 @@ private: * See section 9.10.4 in IEEE 802.11 standard for more details. */ void RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_t tid); - /* + /** + * \param seq MPDU sequence number + * \param winstart sequence number window start + * \param winsize the size of the sequence number window (currently default is 64) + * This method checks if the MPDU's sequence number is inside the scoreboard boundaries or not + */ + bool IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize); + /** + * This method updates the reorder buffer and the scoreboard when an MPDU is received in an HT station + * and sotres the MPDU if needed when an MPDU is received in an non-HT Station (implements HT + * immediate block Ack) + */ + bool ReceiveMpdu (Ptr packet, WifiMacHeader hdr); + /** * This method checks if exists a valid established block ack agreement. * If there is, store the packet without pass it up to WifiMac. The packet is buffered * in order of increasing sequence control field. All comparison are performed @@ -1055,6 +1195,12 @@ private: */ void SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator, Time duration, WifiMode blockAckReqTxMode); + /** + * Invoked after an A-MPDU has been received. Looks for corresponding + * block ack agreement and creates block ack bitmap on a received packets basis. + */ + void SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator, + Time duration, WifiMode blockAckReqTxMode); /** * This method creates block ack frame with header equals to blockAck and start its transmission. * @@ -1088,6 +1234,14 @@ private: * \param phy the WifiPhy this MacLow is connected to */ void RemovePhyMacLowListener (Ptr phy); + /** + * Checks if the given packet will be aggregated to an A-MPDU or not + * + * \param packet packet to check whether it can be aggregated in an A-MPDU + * \param hdr 802.11 header for packet to check whether it can be aggregated in an A-MPDU + * + */ + bool IsAmpdu (Ptr packet, const WifiMacHeader hdr); Ptr m_phy; //!< Pointer to WifiPhy (actually send/receives frames) Ptr m_stationManager; //!< Pointer to WifiRemoteStationManager (rate control) @@ -1116,6 +1270,8 @@ private: EventId m_navCounterResetCtsMissed; //!< Event to reset NAV when CTS is not received EventId m_waitRifsEvent; //!< Wait for RIFS event + Ptr m_mpduAggregator; //!< + Ptr m_currentPacket; //!< Current packet transmitted/to be transmitted WifiMacHeader m_currentHdr; //!< Header of the current packet MacLowTransmissionParameters m_txParams; //!< Transmission parameters of the current packet @@ -1135,6 +1291,7 @@ private: Time m_lastNavDuration; //!< The duration of the latest NAV bool m_promisc; //!< Flag if the device is operating in promiscuous mode + bool m_ampdu; //!< Flag if the current transmission involves an A-MPDU class PhyMacLowListener * m_phyMacLowListener; //!< Listener needed to monitor when a channel switching occurs. @@ -1158,7 +1315,11 @@ private: typedef std::map QueueListeners; QueueListeners m_edcaListeners; - bool m_ctsToSelfSupported; + bool m_ctsToSelfSupported; //!< Flag whether CTS-to-self is supported + uint8_t m_sentMpdus; //!< Number of transmitted MPDUs in an A-MPDU that have not been acknowledged yet + Ptr m_aggregateQueue; //!< Queue used for MPDU aggregation + WifiMode m_currentMode; //!< mode used for the current packet transmission + bool m_receivedAtLeastOneMpdu; //!< Flag whether an MPDU has already been successfully received while receiving an A-MPDU }; } // namespace ns3 diff --git a/src/wifi/model/mac-tx-middle.cc b/src/wifi/model/mac-tx-middle.cc index 5b0fd8efc..e5fe6fa7d 100644 --- a/src/wifi/model/mac-tx-middle.cc +++ b/src/wifi/model/mac-tx-middle.cc @@ -18,6 +18,7 @@ * * Author: Mathieu Lacage * Author: Mirko Banchi + * Author: Ghada Badawy */ #include "ns3/assert.h" @@ -77,6 +78,31 @@ MacTxMiddle::GetNextSequenceNumberfor (const WifiMacHeader *hdr) } return retval; } +uint16_t +MacTxMiddle::PeekNextSequenceNumberfor (const WifiMacHeader *hdr) +{ + uint16_t retval; + if (hdr->IsQosData () + && !hdr->GetAddr1 ().IsGroup ()) + { + uint8_t tid = hdr->GetQosTid (); + NS_ASSERT (tid < 16); + std::map::iterator it = m_qosSequences.find (hdr->GetAddr1 ()); + if (it != m_qosSequences.end ()) + { + retval = it->second[tid]; + } + else + { + retval = 0; + } + } + else + { + retval = m_sequence; + } + return retval; +} uint16_t MacTxMiddle::GetNextSeqNumberByTidAndAddress (uint8_t tid, Mac48Address addr) const diff --git a/src/wifi/model/mac-tx-middle.h b/src/wifi/model/mac-tx-middle.h index 0581faa50..39c8e2cd7 100644 --- a/src/wifi/model/mac-tx-middle.h +++ b/src/wifi/model/mac-tx-middle.h @@ -49,6 +49,14 @@ public: * \return the next sequence number */ uint16_t GetNextSequenceNumberfor (const WifiMacHeader *hdr); + /** + * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged). + * This functions is used for A-MPDU aggregation. + * + * \param hdr Wi-Fi header + * \return the next sequence number + */ + uint16_t PeekNextSequenceNumberfor (const WifiMacHeader *hdr); /** * Return the next sequence number for the Traffic ID and destination. * diff --git a/src/wifi/model/minstrel-wifi-manager.cc b/src/wifi/model/minstrel-wifi-manager.cc index c23ec8f78..748630f32 100644 --- a/src/wifi/model/minstrel-wifi-manager.cc +++ b/src/wifi/model/minstrel-wifi-manager.cc @@ -142,7 +142,7 @@ MinstrelWifiManager::SetupPhy (Ptr phy) WifiMode mode = phy->GetMode (i); WifiTxVector txVector; txVector.SetMode(mode); - AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency())); + AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency(), 0, 0)); } WifiRemoteStationManager::SetupPhy (phy); } diff --git a/src/wifi/model/mpdu-aggregator.cc b/src/wifi/model/mpdu-aggregator.cc new file mode 100644 index 000000000..c250fb967 --- /dev/null +++ b/src/wifi/model/mpdu-aggregator.cc @@ -0,0 +1,77 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#include "ns3/log.h" + +#include "mpdu-aggregator.h" +#include "wifi-mac-header.h" + +NS_LOG_COMPONENT_DEFINE ("MpduAggregator"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (MpduAggregator); + +TypeId +MpduAggregator::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::MpduAggregator") + .SetParent () + ; + return tid; +} + +MpduAggregator::DeaggregatedMpdus +MpduAggregator::Deaggregate (Ptr aggregatedPacket) +{ + NS_LOG_FUNCTION_NOARGS (); + DeaggregatedMpdus set; + + AmpduSubframeHeader hdr; + Ptr extractedMpdu = Create (); + uint32_t maxSize = aggregatedPacket->GetSize (); + uint16_t extractedLength; + uint32_t padding; + uint32_t deserialized = 0; + + while (deserialized < maxSize) + { + deserialized += aggregatedPacket->RemoveHeader (hdr); + extractedLength = hdr.GetLength (); + extractedMpdu = aggregatedPacket->CreateFragment (0, static_cast (extractedLength)); + aggregatedPacket->RemoveAtStart (extractedLength); + deserialized += extractedLength; + + padding = (4 - (extractedLength % 4 )) % 4; + + if (padding > 0 && deserialized < maxSize) + { + aggregatedPacket->RemoveAtStart (padding); + deserialized += padding; + } + + std::pair, AmpduSubframeHeader> packetHdr (extractedMpdu, hdr); + set.push_back (packetHdr); + } + NS_LOG_INFO ("Deaggreated A-MPDU: extracted " << set.size () << " MPDUs"); + return set; +} + + +} // namespace ns3 diff --git a/src/wifi/model/mpdu-aggregator.h b/src/wifi/model/mpdu-aggregator.h new file mode 100644 index 000000000..8dc6cb37a --- /dev/null +++ b/src/wifi/model/mpdu-aggregator.h @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#ifndef MPDU_AGGREGATOR_H +#define MPDU_AGGREGATOR_H + +#include "ns3/ptr.h" +#include "ns3/packet.h" +#include "ns3/object.h" + +#include "ampdu-subframe-header.h" + +#include + +namespace ns3 { + +class WifiMacHeader; + +/** + * \brief Abstract class that concrete mpdu aggregators have to implement + * \ingroup wifi + */ +class MpduAggregator : public Object +{ +public: + /** + * A list of deaggregated packets and their A-MPDU subframe headers. + */ + typedef std::list, AmpduSubframeHeader> > DeaggregatedMpdus; + /** + * A constant iterator for a list of deaggregated packets and their A-MPDU subframe headers. + */ + typedef std::list, AmpduSubframeHeader> >::const_iterator DeaggregatedMpdusCI; + + static TypeId GetTypeId (void); + /** + * \param packet Packet we have to insert into aggregatedPacket. + * \param aggregatedPacket Packet that will contain packet, if aggregation is possible. + * \return true if packet can be aggregated to aggregatedPacket, false otherwise. + * + * Adds packet to aggregatedPacket. In concrete aggregator's implementation is + * specified how and if packet can be added to aggregatedPacket. + */ + virtual bool Aggregate (Ptr packet, Ptr aggregatedPacket) = 0; + /** + * Adds A-MPDU subframe header and padding to each MPDU that is part of an A-MPDU before it is sent. + */ + virtual void AddHeaderAndPad (Ptr packet,bool last) = 0; + /** + * \param packetSize size of the packet we want to insert into aggregatedPacket. + * \param aggregatedPacket packet that will contain the packet of size packetSize, if aggregation is possible. + * \param blockAckSize size of the piggybacked block ack request + * \return true if the packet of size packetSize can be aggregated to aggregatedPacket, false otherwise. + * + * This method is used to determine if a packet could be aggregated to an A-MPDU without exceeding the maximum packet size. + */ + virtual bool CanBeAggregated (uint32_t packetSize, Ptr aggregatedPacket, uint8_t blockAckSize) = 0; + /** + * \return padding that must be added to the end of an aggregated packet + * + * Calculates how much padding must be added to the end of an aggregated packet, after that a new packet is added. + * Each A-MPDU subframe is padded so that its length is multiple of 4 octets. + */ + virtual uint32_t CalculatePadding (Ptr packet) = 0; + /** + * Deaggregates an A-MPDU by removing the A-MPDU subframe header and padding. + * + * \return list of deaggragted packets and their A-MPDU subframe headers + */ + static DeaggregatedMpdus Deaggregate (Ptr aggregatedPacket); +}; + +} // namespace ns3 + +#endif /* MPDU_AGGREGATOR_H */ diff --git a/src/wifi/model/mpdu-standard-aggregator.cc b/src/wifi/model/mpdu-standard-aggregator.cc new file mode 100644 index 000000000..96cd40ce7 --- /dev/null +++ b/src/wifi/model/mpdu-standard-aggregator.cc @@ -0,0 +1,128 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#include "ns3/log.h" +#include "ns3/uinteger.h" + +#include "ampdu-subframe-header.h" +#include "mpdu-standard-aggregator.h" + +NS_LOG_COMPONENT_DEFINE ("MpduStandardAggregator"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (MpduStandardAggregator); + +TypeId +MpduStandardAggregator::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::MpduStandardAggregator") + .SetParent () + .AddConstructor () + .AddAttribute ("MaxAmpduSize", "Max length in bytes of an A-MPDU", + UintegerValue (65535), + MakeUintegerAccessor (&MpduStandardAggregator::m_maxAmpduLength), + MakeUintegerChecker ()) + ; + return tid; +} + +MpduStandardAggregator::MpduStandardAggregator () +{ +} + +MpduStandardAggregator::~MpduStandardAggregator () +{ +} + +bool +MpduStandardAggregator::Aggregate (Ptr packet, Ptr aggregatedPacket) +{ + NS_LOG_FUNCTION (this); + Ptr currentPacket; + AmpduSubframeHeader currentHdr; + + uint32_t padding = CalculatePadding (aggregatedPacket); + uint32_t actualSize = aggregatedPacket->GetSize (); + + if ((4 + packet->GetSize () + actualSize + padding) <= m_maxAmpduLength) + { + if (padding) + { + Ptr pad = Create (padding); + aggregatedPacket->AddAtEnd (pad); + } + currentHdr.SetCrc (1); + currentHdr.SetSig (); + currentHdr.SetLength (packet->GetSize ()); + currentPacket = packet->Copy (); + + currentPacket->AddHeader (currentHdr); + aggregatedPacket->AddAtEnd (currentPacket); + return true; + } + return false; +} + +void +MpduStandardAggregator::AddHeaderAndPad (Ptr packet, bool last) +{ + NS_LOG_FUNCTION (this); + AmpduSubframeHeader currentHdr; + //This is called to prepare packets from the aggregte queue to be sent so no need to check total size since it has already been + //done before when deciding how many packets to add to the queue + currentHdr.SetCrc (1); + currentHdr.SetSig (); + currentHdr.SetLength (packet->GetSize ()); + packet->AddHeader (currentHdr); + uint32_t padding = CalculatePadding (packet); + + if (padding && !last) + { + Ptr pad = Create (padding); + packet->AddAtEnd (pad); + } +} + +bool +MpduStandardAggregator::CanBeAggregated (uint32_t packetSize, Ptr aggregatedPacket, uint8_t blockAckSize) +{ + uint32_t padding = CalculatePadding (aggregatedPacket); + uint32_t actualSize = aggregatedPacket->GetSize (); + if (blockAckSize > 0) + { + blockAckSize = blockAckSize + 4 + padding; + } + if ((4 + packetSize + actualSize + padding + blockAckSize) <= m_maxAmpduLength) + { + return true; + } + else + { + return false; + } +} + +uint32_t +MpduStandardAggregator::CalculatePadding (Ptr packet) +{ + return (4 - (packet->GetSize () % 4 )) % 4; +} + +} // namespace ns3 diff --git a/src/wifi/model/mpdu-standard-aggregator.h b/src/wifi/model/mpdu-standard-aggregator.h new file mode 100644 index 000000000..f7c8b4c7d --- /dev/null +++ b/src/wifi/model/mpdu-standard-aggregator.h @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Ghada Badawy + */ +#ifndef MPDU_STANDARD_AGGREGATOR_H +#define MPDU_STANDARD_AGGREGATOR_H + +#include "mpdu-aggregator.h" + +namespace ns3 { + +/** + * \ingroup wifi + * Standard MPDU aggregator + * + */ +class MpduStandardAggregator : public MpduAggregator +{ +public: + static TypeId GetTypeId (void); + MpduStandardAggregator (); + ~MpduStandardAggregator (); + /** + * \param packet packet we have to insert into aggregatedPacket. + * \param aggregatedPacket packet that will contain packet, if aggregation is possible. + * \return true if packet can be aggregated to aggregatedPacket, false otherwise. + * + * This method performs an MPDU aggregation. + * Returns true if packet can be aggregated to aggregatedPacket, false otherwise. + */ + virtual bool Aggregate (Ptr packet, Ptr aggregatedPacket); + /** + * Adds A-MPDU subframe header and padding to each MPDU that is part of an A-MPDU before it is sent. + */ + virtual void AddHeaderAndPad (Ptr packet, bool last); + /** + * \param packetSize size of the packet we want to insert into aggregatedPacket. + * \param aggregatedPacket packet that will contain the packet of size packetSize, if aggregation is possible. + * \param blockAckSize size of the piggybacked block ack request + * \return true if the packet of size packetSize can be aggregated to aggregatedPacket, false otherwise. + * + * This method is used to determine if a packet could be aggregated to an A-MPDU without exceeding the maximum packet size. + */ + virtual bool CanBeAggregated (uint32_t packetSize, Ptr aggregatedPacket, uint8_t blockAckSize); + /** + * \return padding that must be added to the end of an aggregated packet + * + * Calculates how much padding must be added to the end of an aggregated packet, after that a new packet is added. + * Each A-MPDU subframe is padded so that its length is multiple of 4 octets. + */ + virtual uint32_t CalculatePadding (Ptr packet); + +private: + uint32_t m_maxAmpduLength; //!< Maximum length in bytes of A-MPDUs +}; + +} // namespace ns3 + +#endif /* MPDU_STANDARD_AGGREGATOR_H */ diff --git a/src/wifi/model/wifi-mac-queue.cc b/src/wifi/model/wifi-mac-queue.cc index d7575eeec..9f01c21b1 100644 --- a/src/wifi/model/wifi-mac-queue.cc +++ b/src/wifi/model/wifi-mac-queue.cc @@ -188,7 +188,7 @@ WifiMacQueue::DequeueByTidAndAddress (WifiMacHeader *hdr, uint8_t tid, Ptr WifiMacQueue::PeekByTidAndAddress (WifiMacHeader *hdr, uint8_t tid, - WifiMacHeader::AddressType type, Mac48Address dest) + WifiMacHeader::AddressType type, Mac48Address dest, Time *timestamp) { Cleanup (); if (!m_queue.empty ()) @@ -202,6 +202,7 @@ WifiMacQueue::PeekByTidAndAddress (WifiMacHeader *hdr, uint8_t tid, && it->hdr.GetQosTid () == tid) { *hdr = it->hdr; + *timestamp=it->tstamp; return it->packet; } } diff --git a/src/wifi/model/wifi-mac-queue.h b/src/wifi/model/wifi-mac-queue.h index 01295b3d7..3bc0f1015 100644 --- a/src/wifi/model/wifi-mac-queue.h +++ b/src/wifi/model/wifi-mac-queue.h @@ -135,12 +135,14 @@ public: * \param tid the given TID * \param type the given address type * \param addr the given destination + * \param timestamp * \return packet */ Ptr PeekByTidAndAddress (WifiMacHeader *hdr, uint8_t tid, WifiMacHeader::AddressType type, - Mac48Address addr); + Mac48Address addr, + Time *timestamp); /** * If exists, removes packet from queue and returns true. Otherwise it * takes no effects and return false. Deletion of the packet is @@ -205,6 +207,7 @@ public: * \return the current queue size */ uint32_t GetSize (void); + protected: /** * Clean up the queue by removing packets that exceeded the maximum delay. diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index c3e153f07..d21966bed 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -107,6 +107,8 @@ WifiPhy::GetTypeId (void) WifiPhy::WifiPhy () { NS_LOG_FUNCTION (this); + m_totalAmpduSize = 0; + m_totalAmpduNumSymbols = 0; } WifiPhy::~WifiPhy () @@ -114,8 +116,6 @@ WifiPhy::~WifiPhy () NS_LOG_FUNCTION (this); } -//Added by Ghada to support 11n - //return the L-SIG WifiMode WifiPhy::GetMFPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble) @@ -131,7 +131,7 @@ WifiPhy::GetMFPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble) } } -Time +Time WifiPhy::GetPlcpHtTrainingSymbolDuration (WifiPreamble preamble, WifiTxVector txvector) { uint8_t Ndltf, Neltf; @@ -160,7 +160,7 @@ WifiPhy::GetPlcpHtTrainingSymbolDuration (WifiPreamble preamble, WifiTxVector tx case WIFI_PREAMBLE_HT_MF: return MicroSeconds(4 + (4 * Ndltf) + (4 * Neltf)); case WIFI_PREAMBLE_HT_GF: - return MicroSeconds((4 * Ndltf) + (4 * Neltf)); + return MicroSeconds((4 * Ndltf) + (4 * Neltf)); default: // no training for non HT return MicroSeconds(0); @@ -183,9 +183,7 @@ WifiPhy::GetPlcpHtSigHeaderDuration (WifiMode payloadMode, WifiPreamble preamble // no HT-SIG for non HT return MicroSeconds(0); } - } -//end added by Ghada WifiMode WifiPhy::GetPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble) @@ -294,6 +292,7 @@ WifiPhy::GetPlcpHeaderDuration (WifiMode payloadMode, WifiPreamble preamble) case WIFI_PREAMBLE_HT_MF: // L-SIG return MicroSeconds(4); + case WIFI_PREAMBLE_NONE: case WIFI_PREAMBLE_HT_GF: //L-SIG return MicroSeconds(0); @@ -348,8 +347,16 @@ WifiPhy::GetPlcpPreambleDuration (WifiMode payloadMode, WifiPreamble preamble) } } case WIFI_MOD_CLASS_HT: - { //IEEE 802.11n Figure 20.1 the training symbols before L_SIG or HT_SIG - return MicroSeconds(16); + { + switch (preamble) + { + case WIFI_PREAMBLE_NONE: + //A-MPDU support since MPDUs inside an A-MPDU are sent without a preamble + return MicroSeconds(0); + default: + //IEEE 802.11n Figure 20.1 the training symbols before L_SIG or HT_SIG + return MicroSeconds(16); + } } case WIFI_MOD_CLASS_ERP_OFDM: return MicroSeconds(16); @@ -372,7 +379,7 @@ WifiPhy::GetPlcpPreambleDuration (WifiMode payloadMode, WifiPreamble preamble) } Time -WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double frequency) +WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag) { WifiMode payloadMode=txvector.GetMode(); @@ -406,7 +413,47 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double freque double numDataBitsPerSymbol = payloadMode.GetDataRate () * symbolDuration.GetNanoSeconds() / 1e9; // (Section 18.3.5.4 "Pad bits (PAD)" Equation 18-11; IEEE Std 802.11-2012) - uint32_t numSymbols = lrint (ceil ((16 + size * 8.0 + 6.0) / numDataBitsPerSymbol)); + uint32_t numSymbols; + + if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE) + { + //First packet in an A-MPDU + numSymbols= ceil((16 + size * 8.0 + 6) / (numDataBitsPerSymbol)); + if (incFlag == 1) + { + m_totalAmpduSize += size; + m_totalAmpduNumSymbols += numSymbols; + } + } + else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE) + { + //consecutive packets in an A-MPDU + numSymbols= ((size * 8.0) / (numDataBitsPerSymbol)); + if (incFlag == 1) + { + m_totalAmpduSize += size; + m_totalAmpduNumSymbols += numSymbols; + } + } + else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE) + { + //last packet in an A-MPDU + uint32_t totalAmpduSize = m_totalAmpduSize + size; + numSymbols = lrint (ceil((16 + totalAmpduSize * 8.0 + 6) / (numDataBitsPerSymbol))); + numSymbols -= m_totalAmpduNumSymbols; + if (incFlag == 1) + { + m_totalAmpduSize = 0; + m_totalAmpduNumSymbols = 0; + } + } + else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE) + { + //Not an A-MPDU + numSymbols = lrint (ceil ((16 + size * 8.0 + 6.0) / (numDataBitsPerSymbol))); + } + else + NS_FATAL_ERROR ("Wrong combination of preamble and packet type"); // Add signal extension for ERP PHY if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM) @@ -460,9 +507,49 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double freque //check tables 20-35 and 20-36 in the standard to get cases when nes =2 double Nes=1; // IEEE Std 802.11n, section 20.3.11, equation (20-32) - uint32_t numSymbols = lrint (m_Stbc*ceil ((16 + size * 8.0 + 6.0*Nes) / (m_Stbc* numDataBitsPerSymbol))); + uint32_t numSymbols; + if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE) + { + //First packet in an A-MPDU + numSymbols = ceil(m_Stbc*(16 + size * 8.0 + 6*Nes) / (m_Stbc* numDataBitsPerSymbol)); + if (incFlag == 1) + { + m_totalAmpduSize += size; + m_totalAmpduNumSymbols += numSymbols; + } + } + else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE) + { + //consecutive packets in an A-MPDU + numSymbols = m_Stbc* ((size * 8.0 ) / (m_Stbc* numDataBitsPerSymbol)); + if (incFlag == 1) + { + m_totalAmpduSize += size; + m_totalAmpduNumSymbols += numSymbols; + } + } + else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE) + { + //last packet in an A-MPDU + uint32_t totalAmpduSize = m_totalAmpduSize+size; + numSymbols = lrint (m_Stbc* ceil((16 + totalAmpduSize * 8.0 + 6*Nes) / (m_Stbc* numDataBitsPerSymbol))); + NS_ASSERT (m_totalAmpduNumSymbols <= numSymbols); + numSymbols -= m_totalAmpduNumSymbols; + if (incFlag == 1) + { + m_totalAmpduSize = 0; + m_totalAmpduNumSymbols = 0; + } + } + else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE) + //Not an A-MPDU + { + numSymbols = lrint (m_Stbc*ceil ((16 + size * 8.0 + 6.0*Nes) / (m_Stbc* numDataBitsPerSymbol))); + } + else + NS_FATAL_ERROR ("Wrong combination of preamble and packet type"); - if (frequency >= 2400 && frequency <= 2500) //at 2.4 GHz + if (frequency >= 2400 && frequency <= 2500 && ((packetType == 0 && preamble != WIFI_PREAMBLE_NONE) || (packetType == 2 && preamble == WIFI_PREAMBLE_NONE))) //at 2.4 GHz { return Time (numSymbols * symbolDuration) + MicroSeconds(6); } @@ -470,6 +557,7 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double freque { return Time (numSymbols * symbolDuration); } + } case WIFI_MOD_CLASS_DSSS: // (Section 17.2.3.6 "Long PLCP LENGTH field"; IEEE Std 802.11-2012) @@ -485,19 +573,17 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double freque } Time -WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency) +WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag) { - WifiMode payloadMode = txvector.GetMode (); + WifiMode payloadMode=txvector.GetMode(); Time duration = GetPlcpPreambleDuration (payloadMode, preamble) + GetPlcpHeaderDuration (payloadMode, preamble) + GetPlcpHtSigHeaderDuration (payloadMode, preamble) + GetPlcpHtTrainingSymbolDuration (preamble, txvector) - + GetPayloadDuration (size, txvector, frequency); + + GetPayloadDuration (size, txvector, preamble, frequency, packetType, incFlag); return duration; } - - void WifiPhy::NotifyTxBegin (Ptr packet) { diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index ff05c71ab..5d0d7069d 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -209,8 +209,9 @@ public: * this packet, and txPowerLevel, a power level to use to send this packet. The real transmission * power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels * \param preamble the type of preamble to use to send this packet. + * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU */ - virtual void SendPacket (Ptr packet, WifiTxVector txvector, enum WifiPreamble preamble) = 0; + virtual void SendPacket (Ptr packet, WifiTxVector txvector, enum WifiPreamble preamble, uint8_t packetType) = 0; /** * \param listener the new listener @@ -288,10 +289,12 @@ public: * \param txvector the transmission parameters used for this packet * \param preamble the type of preamble to use for this packet. * \param frequency the channel center frequency (MHz) + * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU + * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time. * \return the total amount of time this PHY will stay busy for * the transmission of these bytes. */ - static Time CalculateTxDuration (uint32_t size, WifiTxVector txvector, enum WifiPreamble preamble, double frequency); + Time CalculateTxDuration (uint32_t size, WifiTxVector txvector, enum WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag); /** * \param preamble the type of preamble @@ -307,7 +310,7 @@ public: * \return the WifiMode used for the transmission of the HT-SIG in Mixed Format and greenfield format PLCP header */ static WifiMode GetMFPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble); - /** + /** * \param payloadMode the WifiMode use for the transmission of the payload * \param preamble the type of preamble * @@ -315,6 +318,7 @@ public: */ static Time GetPlcpHtSigHeaderDuration (WifiMode payloadMode, WifiPreamble preamble); + /** * \param payloadMode the WifiMode use for the transmission of the payload * \param preamble the type of preamble @@ -342,11 +346,14 @@ public: /** * \param size the number of bytes in the packet to send * \param txvector the transmission parameters used for this packet + * \param preamble the type of preamble to use for this packet. * \param frequency the channel center frequency (MHz) + * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU + * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time * * \return the duration of the payload */ - static Time GetPayloadDuration (uint32_t size, WifiTxVector txvector, double frequency); + Time GetPayloadDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag); /** * The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used @@ -1214,7 +1221,9 @@ private: * \see class CallBackTraceSource */ TracedCallback, uint16_t, uint16_t, uint32_t, bool,uint8_t> m_phyMonitorSniffTxTrace; - + + uint32_t m_totalAmpduNumSymbols; //!< Number of symbols previously transmitted for the MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU + uint32_t m_totalAmpduSize; //!< Total size of the previously transmitted MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU }; /** diff --git a/src/wifi/model/wifi-preamble.h b/src/wifi/model/wifi-preamble.h index c8e80bffb..116bcb59e 100644 --- a/src/wifi/model/wifi-preamble.h +++ b/src/wifi/model/wifi-preamble.h @@ -31,7 +31,8 @@ enum WifiPreamble WIFI_PREAMBLE_LONG, WIFI_PREAMBLE_SHORT, WIFI_PREAMBLE_HT_MF, - WIFI_PREAMBLE_HT_GF + WIFI_PREAMBLE_HT_GF, + WIFI_PREAMBLE_NONE }; } // namespace ns3 diff --git a/src/wifi/model/wifi-remote-station-manager.h b/src/wifi/model/wifi-remote-station-manager.h index f28a4bec0..64a463f93 100644 --- a/src/wifi/model/wifi-remote-station-manager.h +++ b/src/wifi/model/wifi-remote-station-manager.h @@ -646,7 +646,7 @@ public: */ uint32_t GetNumberOfTransmitAntennas (const WifiRemoteStation *station) const; /** - * Return the Number of extension spatial streams (Ness) the station has. + * \returns the number of Ness the station has. * * \param station the station being queried * \return the number of Ness the station has diff --git a/src/wifi/model/yans-wifi-channel.cc b/src/wifi/model/yans-wifi-channel.cc index a7ab6acd0..a600e81bc 100644 --- a/src/wifi/model/yans-wifi-channel.cc +++ b/src/wifi/model/yans-wifi-channel.cc @@ -76,7 +76,7 @@ YansWifiChannel::SetPropagationDelayModel (Ptr delay) void YansWifiChannel::Send (Ptr sender, Ptr packet, double txPowerDbm, - WifiTxVector txVector, WifiPreamble preamble) const + WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, Time duration) const { Ptr senderMobility = sender->GetMobility ()->GetObject (); NS_ASSERT (senderMobility != 0); @@ -107,18 +107,25 @@ YansWifiChannel::Send (Ptr sender, Ptr packet, double { dstNode = dstNetDevice->GetObject ()->GetNode ()->GetId (); } + + double *atts = new double[3]; + *atts = rxPowerDbm; + *(atts+1)= packetType; + *(atts+2)= duration.GetNanoSeconds(); + Simulator::ScheduleWithContext (dstNode, delay, &YansWifiChannel::Receive, this, - j, copy, rxPowerDbm, txVector, preamble); + j, copy, atts, txVector, preamble); } } } void -YansWifiChannel::Receive (uint32_t i, Ptr packet, double rxPowerDbm, +YansWifiChannel::Receive (uint32_t i, Ptr packet, double *atts, WifiTxVector txVector, WifiPreamble preamble) const { - m_phyList[i]->StartReceivePacket (packet, rxPowerDbm, txVector, preamble); + m_phyList[i]->StartReceivePacket (packet, *atts, txVector, preamble,*(atts+1), NanoSeconds(*(atts+2))); + delete[] atts; } uint32_t diff --git a/src/wifi/model/yans-wifi-channel.h b/src/wifi/model/yans-wifi-channel.h index e8b92584c..57981c20e 100644 --- a/src/wifi/model/yans-wifi-channel.h +++ b/src/wifi/model/yans-wifi-channel.h @@ -27,6 +27,7 @@ #include "wifi-mode.h" #include "wifi-preamble.h" #include "wifi-tx-vector.h" +#include "ns3/nstime.h" namespace ns3 { @@ -81,6 +82,8 @@ public: * \param txPowerDbm the tx power associated to the packet * \param txVector the TXVECTOR associated to the packet * \param preamble the preamble associated to the packet + * \param packetType the type of packet, used for A-MPDU to say whether it's the last MPDU or not + * \param duration the transmission duration associated to the packet * * This method should not be invoked by normal users. It is * currently invoked only from WifiPhy::Send. YansWifiChannel @@ -88,7 +91,7 @@ public: * e.g. PHYs that are operating on the same channel. */ void Send (Ptr sender, Ptr packet, double txPowerDbm, - WifiTxVector txVector, WifiPreamble preamble) const; + WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, Time duration) const; /** * Assign a fixed random variable stream number to the random variables @@ -115,11 +118,11 @@ private: * * \param i index of the corresponding YansWifiPhy in the PHY list * \param packet the packet being sent - * \param rxPowerDbm the received power of the packet + * \param atts a vector containing the received power in dBm and the packet type * \param txVector the TXVECTOR of the packet * \param preamble the type of preamble being used to send the packet */ - void Receive (uint32_t i, Ptr packet, double rxPowerDbm, + void Receive (uint32_t i, Ptr packet, double *atts, WifiTxVector txVector, WifiPreamble preamble) const; diff --git a/src/wifi/model/yans-wifi-phy.cc b/src/wifi/model/yans-wifi-phy.cc index 0fcb82f3e..13bdaa2a6 100644 --- a/src/wifi/model/yans-wifi-phy.cc +++ b/src/wifi/model/yans-wifi-phy.cc @@ -36,6 +36,7 @@ #include "ns3/net-device.h" #include "ns3/trace-source-accessor.h" #include "ns3/boolean.h" +#include "ampdu-tag.h" #include namespace ns3 { @@ -168,9 +169,11 @@ YansWifiPhy::GetTypeId (void) } YansWifiPhy::YansWifiPhy () - : m_channelNumber (1), + : m_initialized (false), + m_channelNumber (1), m_endRxEvent (), - m_channelStartingFrequency (0) + m_channelStartingFrequency (0), + m_mpdusNum(0) { NS_LOG_FUNCTION (this); m_random = CreateObject (); @@ -194,6 +197,13 @@ YansWifiPhy::DoDispose (void) m_state = 0; } +void +YansWifiPhy::DoInitialize () +{ + NS_LOG_FUNCTION (this); + m_initialized = true; +} + void YansWifiPhy::ConfigureStandard (enum WifiPhyStandard standard) { @@ -373,7 +383,7 @@ YansWifiPhy::SetChannel (Ptr channel) void YansWifiPhy::SetChannelNumber (uint16_t nch) { - if (Simulator::Now () == Seconds (0)) + if (!m_initialized) { // this is not channel switch, this is initialization NS_LOG_DEBUG ("start at channel " << nch); @@ -507,12 +517,14 @@ void YansWifiPhy::StartReceivePacket (Ptr packet, double rxPowerDbm, WifiTxVector txVector, - enum WifiPreamble preamble) + enum WifiPreamble preamble, + uint8_t packetType, Time rxDuration) { - NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode()<< preamble); + NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode()<< preamble << (uint32_t)packetType); + AmpduTag ampduTag; rxPowerDbm += m_rxGainDb; double rxPowerW = DbmToW (rxPowerDbm); - Time rxDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency()); + //Time rxDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency(), packetType, 1); WifiMode txMode = txVector.GetMode(); Time endRx = Simulator::Now () + rxDuration; @@ -572,6 +584,33 @@ YansWifiPhy::StartReceivePacket (Ptr packet, { if (IsModeSupported (txMode) || IsMcsSupported(txMode)) { + if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0) + { + //received the first MPDU in an MPDU + m_mpdusNum = ampduTag.GetNoOfMpdus()-1; + } + else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0) + { + //received the other MPDUs that are part of the A-MPDU + if (ampduTag.GetNoOfMpdus() < m_mpdusNum) + { + NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetNoOfMpdus()); + m_mpdusNum = ampduTag.GetNoOfMpdus(); + } + else + m_mpdusNum--; + } + else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 ) + { + NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum); + m_mpdusNum = 0; + } + else if (preamble == WIFI_PREAMBLE_NONE && m_mpdusNum == 0) + { + NS_LOG_DEBUG ("drop packet because no preamble has been received"); + NotifyRxDrop (packet); + goto maybeCcaBusy; + } NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)"); // sync to signal m_state->SwitchToRx (rxDuration); @@ -619,9 +658,9 @@ maybeCcaBusy: } void -YansWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, WifiPreamble preamble) +YansWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType) { - NS_LOG_FUNCTION (this << packet << txVector.GetMode() << preamble << (uint32_t)txVector.GetTxPowerLevel()); + NS_LOG_FUNCTION (this << packet << txVector.GetMode() << preamble << (uint32_t)txVector.GetTxPowerLevel() << (uint32_t)packetType); /* Transmission can happen if: * - we are syncing on a packet. It is the responsability of the * MAC layer to avoid doing this but the PHY does nothing to @@ -637,7 +676,7 @@ YansWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, WifiPr return; } - Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency()); + Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency(), packetType, 1); if (m_state->IsStateRx ()) { m_endRxEvent.Cancel (); @@ -656,7 +695,7 @@ YansWifiPhy::SendPacket (Ptr packet, WifiTxVector txVector, WifiPr bool isShortPreamble = (WIFI_PREAMBLE_SHORT == preamble); NotifyMonitorSniffTx (packet, (uint16_t)GetChannelFrequencyMhz (), GetChannelNumber (), dataRate500KbpsUnits, isShortPreamble, txVector.GetTxPowerLevel()); m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel()), txVector, preamble); - m_channel->Send (this, packet, GetPowerDbm ( txVector.GetTxPowerLevel()) + m_txGainDb, txVector, preamble); + m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel()) + m_txGainDb, txVector, preamble, packetType, txDuration); } uint32_t diff --git a/src/wifi/model/yans-wifi-phy.h b/src/wifi/model/yans-wifi-phy.h index f3f13edbc..967f3424e 100644 --- a/src/wifi/model/yans-wifi-phy.h +++ b/src/wifi/model/yans-wifi-phy.h @@ -106,11 +106,15 @@ public: * \param rxPowerDbm the receive power in dBm * \param txVector the TXVECTOR of the arriving packet * \param preamble the preamble of the arriving packet + * \param packetType The type of the received packet (values: 0 not an A-MPDU, 1 corresponds to any packets in an A-MPDU except the last one, 2 is the last packet in an A-MPDU) + * \param rxDuration the duration needed for the reception of the arriving packet */ void StartReceivePacket (Ptr packet, double rxPowerDbm, WifiTxVector txVector, - WifiPreamble preamble); + WifiPreamble preamble, + uint8_t packetType, + Time rxDuration); /** * Sets the RX loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver. @@ -251,7 +255,7 @@ public: virtual uint32_t GetNTxPower (void) const; virtual void SetReceiveOkCallback (WifiPhy::RxOkCallback callback); virtual void SetReceiveErrorCallback (WifiPhy::RxErrorCallback callback); - virtual void SendPacket (Ptr packet, WifiTxVector txvector, enum WifiPreamble preamble); + virtual void SendPacket (Ptr packet, WifiTxVector txvector, enum WifiPreamble preamble, uint8_t packetType); virtual void RegisterListener (WifiPhyListener *listener); virtual void UnregisterListener (WifiPhyListener *listener); virtual void SetSleepMode (void); @@ -463,6 +467,9 @@ private: void EndReceive (Ptr packet, Ptr event); private: + virtual void DoInitialize (void); + + bool m_initialized; //!< Flag for runtime initialization double m_edThresholdW; //!< Energy detection threshold in watts double m_ccaMode1ThresholdW; //!< Clear channel assessment (CCA) threshold in watts double m_txGainDb; //!< Transmission gain (dB) @@ -532,7 +539,7 @@ private: Ptr m_state; //!< Pointer to WifiPhyStateHelper InterferenceHelper m_interference; //!< Pointer to InterferenceHelper Time m_channelSwitchDelay; //!< Time required to switch between channel - + uint16_t m_mpdusNum; //!< carries the number of expected mpdus that are part of an A-MPDU }; } // namespace ns3 diff --git a/src/wifi/test/tx-duration-test.cc b/src/wifi/test/tx-duration-test.cc index 992ef09bc..57a0789bd 100644 --- a/src/wifi/test/tx-duration-test.cc +++ b/src/wifi/test/tx-duration-test.cc @@ -23,7 +23,7 @@ #include #include #include "ns3/interference-helper.h" -#include "ns3/wifi-phy.h" +#include "ns3/yans-wifi-phy.h" using namespace ns3; @@ -50,7 +50,7 @@ private: * * @return true if values correspond, false otherwise */ - bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint32_t knownDurationMicroSeconds); + bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, uint32_t knownDurationMicroSeconds); /** * Check if the overall tx duration returned by InterferenceHelper @@ -63,7 +63,7 @@ private: * * @return true if values correspond, false otherwise */ - bool CheckTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, double knownDurationMicroSeconds); + bool CheckTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, double knownDurationMicroSeconds); }; @@ -79,17 +79,18 @@ TxDurationTest::~TxDurationTest () } bool -TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint32_t knownDurationMicroSeconds) +TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, uint32_t knownDurationMicroSeconds) { WifiTxVector txVector; txVector.SetMode (payloadMode); double testedFrequency = CHANNEL_1_MHZ; + Ptr phy = CreateObject (); if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT) { testedFrequency = CHANNEL_36_MHZ; } - double calculatedDurationMicroSeconds = WifiPhy::GetPayloadDuration (size, txVector, testedFrequency).GetMicroSeconds(); + double calculatedDurationMicroSeconds = (double)phy->GetPayloadDuration (size, txVector, preamble, testedFrequency, 0, 0).GetMicroSeconds();; if (calculatedDurationMicroSeconds != knownDurationMicroSeconds) { std::cerr << " size=" << size @@ -103,7 +104,7 @@ TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint3 { // Durations vary depending on frequency; test also 2.4 GHz (bug 1971) testedFrequency = CHANNEL_1_MHZ; - calculatedDurationMicroSeconds = WifiPhy::GetPayloadDuration (size, txVector, testedFrequency).GetMicroSeconds(); + calculatedDurationMicroSeconds = (double)phy->GetPayloadDuration (size, txVector, preamble, testedFrequency, 0, 0).GetMicroSeconds();; if (calculatedDurationMicroSeconds != knownDurationMicroSeconds + 6) { std::cerr << " size=" << size @@ -126,12 +127,13 @@ TxDurationTest::CheckTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamb txVector.SetStbc(0); txVector.SetNess(0); double testedFrequency = CHANNEL_1_MHZ; + Ptr phy = CreateObject (); if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT) { testedFrequency = CHANNEL_36_MHZ; } - double calculatedDurationMicroSeconds = ((double)WifiPhy::CalculateTxDuration (size, txVector, preamble, testedFrequency).GetNanoSeconds ())/1000; + double calculatedDurationMicroSeconds = ((double)phy->CalculateTxDuration (size, txVector, preamble, testedFrequency, 0, 0).GetNanoSeconds ())/1000; if (calculatedDurationMicroSeconds != knownDurationMicroSeconds) { std::cerr << " size=" << size @@ -146,7 +148,7 @@ TxDurationTest::CheckTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamb { // Durations vary depending on frequency; test also 2.4 GHz (bug 1971) testedFrequency = CHANNEL_1_MHZ; - calculatedDurationMicroSeconds = ((double)WifiPhy::CalculateTxDuration (size, txVector, preamble, testedFrequency).GetNanoSeconds ())/1000; + calculatedDurationMicroSeconds = ((double)phy->CalculateTxDuration (size, txVector, preamble, testedFrequency, 0, 0).GetNanoSeconds ())/1000; if (calculatedDurationMicroSeconds != knownDurationMicroSeconds + 6) { std::cerr << " size=" << size @@ -169,10 +171,10 @@ TxDurationTest::DoRun (void) // IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK" retval = retval - && CheckPayloadDuration (1023, WifiPhy::GetDsssRate11Mbps (), 744) - && CheckPayloadDuration (1024, WifiPhy::GetDsssRate11Mbps (), 745) - && CheckPayloadDuration (1025, WifiPhy::GetDsssRate11Mbps (), 746) - && CheckPayloadDuration (1026, WifiPhy::GetDsssRate11Mbps (), 747); + && CheckPayloadDuration (1023, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 744) + && CheckPayloadDuration (1024, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 745) + && CheckPayloadDuration (1025, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 746) + && CheckPayloadDuration (1026, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 747); NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b CCK duration failed"); @@ -242,16 +244,16 @@ TxDurationTest::DoRun (void) //802.11n durations retval = retval - && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,228) + && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,228) && CheckTxDuration (76, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,48) && CheckTxDuration (14, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,40) - && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,220) + && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,220) && CheckTxDuration (76, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,40) && CheckTxDuration (14, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,32) - && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,1746) + && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,1746) && CheckTxDuration (76, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,126) && CheckTxDuration (14, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,57.6) - && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,1738) + && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,1738) && CheckTxDuration (76, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,118) && CheckTxDuration (14, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,49.6) && CheckTxDuration (1536, WifiPhy::GetOfdmRate65MbpsBW20MHzShGi (), WIFI_PREAMBLE_HT_MF,226.8) diff --git a/src/wifi/wscript b/src/wifi/wscript index 5b3217517..965be0676 100644 --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -65,6 +65,10 @@ def build(bld): 'model/wifi-tx-vector.cc', 'model/parf-wifi-manager.cc', 'model/aparf-wifi-manager.cc', + 'model/ampdu-subframe-header.cc', + 'model/mpdu-aggregator.cc', + 'model/mpdu-standard-aggregator.cc', + 'model/ampdu-tag.cc', 'helper/ht-wifi-mac-helper.cc', 'helper/athstats-helper.cc', 'helper/wifi-helper.cc', @@ -145,6 +149,10 @@ def build(bld): 'model/parf-wifi-manager.h', 'model/aparf-wifi-manager.h', 'model/wifi-tx-vector.h', + 'model/ampdu-subframe-header.h', + 'model/mpdu-aggregator.h', + 'model/mpdu-standard-aggregator.h', + 'model/ampdu-tag.h', 'helper/ht-wifi-mac-helper.h', 'helper/athstats-helper.h', 'helper/wifi-helper.h',