diff --git a/CHANGES.html b/CHANGES.html index 4c2613ff5..1570797ed 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -56,6 +56,11 @@ us a note on ns-developers mailing list.

Changes to existing API:

Changed behavior:


diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index 5de56b19a..3b7e1b264 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -104,8 +104,12 @@ BlockAckManager::ExistsAgreementInState (Mac48Address recipient, uint8_t tid, return it->second.first.IsEstablished (); case OriginatorBlockAckAgreement::PENDING: return it->second.first.IsPending (); - case OriginatorBlockAckAgreement::UNSUCCESSFUL: - return it->second.first.IsUnsuccessful (); + case OriginatorBlockAckAgreement::REJECTED: + return it->second.first.IsRejected (); + case OriginatorBlockAckAgreement::NO_REPLY: + return it->second.first.IsNoReply (); + case OriginatorBlockAckAgreement::RESET: + return it->second.first.IsReset (); default: NS_FATAL_ERROR ("Invalid state for block ack agreement"); } @@ -138,6 +142,12 @@ BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Addr agreement.SetState (OriginatorBlockAckAgreement::PENDING); PacketQueue queue; std::pair value (agreement, queue); + if (ExistsAgreement (recipient, reqHdr->GetTid ())) + { + // Delete agreement if it exists and in RESET state + NS_ASSERT (ExistsAgreementInState (recipient, reqHdr->GetTid (), OriginatorBlockAckAgreement::RESET)); + m_agreements.erase (key); + } m_agreements.insert (std::make_pair (key, value)); m_blockPackets (recipient, reqHdr->GetTid ()); } @@ -710,15 +720,31 @@ BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid } void -BlockAckManager::NotifyAgreementUnsuccessful (Mac48Address recipient, uint8_t tid) +BlockAckManager::NotifyAgreementRejected (Mac48Address recipient, uint8_t tid) { NS_LOG_FUNCTION (this << recipient << +tid); AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); NS_ASSERT (it != m_agreements.end ()); - if (it != m_agreements.end ()) - { - it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL); - } + it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED); +} + +void +BlockAckManager::NotifyAgreementNoReply (Mac48Address recipient, uint8_t tid) +{ + NS_LOG_FUNCTION (this << recipient << +tid); + AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (it != m_agreements.end ()); + it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY); + m_unblockPackets (recipient, tid); +} + +void +BlockAckManager::NotifyAgreementReset (Mac48Address recipient, uint8_t tid) +{ + NS_LOG_FUNCTION (this << recipient << +tid); + AgreementsI it = m_agreements.find (std::make_pair (recipient, tid)); + NS_ASSERT (it != m_agreements.end ()); + it->second.first.SetState (OriginatorBlockAckAgreement::RESET); } void @@ -761,7 +787,7 @@ BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, { NS_LOG_FUNCTION (this << recipient << +tid << startingSeq); NS_ASSERT (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING)); - if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid)) + if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid)) { uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) + GetNBufferedPackets (recipient, tid); diff --git a/src/wifi/model/block-ack-manager.h b/src/wifi/model/block-ack-manager.h index 1e0bc2094..b51b8f0a2 100644 --- a/src/wifi/model/block-ack-manager.h +++ b/src/wifi/model/block-ack-manager.h @@ -225,11 +225,27 @@ public: * \param recipient Address of peer station involved in block ack mechanism. * \param tid Traffic ID of transmitted packet. * - * Marks an agreement as unsuccessful. This happens if recipient station reject block ack setup + * Marks an agreement as rejected. This happens if recipient station reject block ack setup * by an ADDBA Response frame with a failure status code. For now we assume that every QoS station accepts * a block ack setup. */ - void NotifyAgreementUnsuccessful (Mac48Address recipient, uint8_t tid); + void NotifyAgreementRejected (Mac48Address recipient, uint8_t tid); + /** + * \param recipient Address of peer station involved in block ack mechanism. + * \param tid Traffic ID of transmitted packet. + * + * Marks an agreement after not receiving response to ADDBA request. During this state + * any packets in queue will be transmitted using normal MPDU. This also unblock + * recipient adress. + */ + void NotifyAgreementNoReply (Mac48Address recipient, uint8_t tid); + /** + * \param recipient Address of peer station involved in block ack mechanism. + * \param tid Traffic ID of transmitted packet. + * + * Set BA agreement to a transitory state to reset it after not receiving response to ADDBA request. + */ + void NotifyAgreementReset (Mac48Address recipient, uint8_t tid); /** * \param recipient Address of peer station involved in block ack mechanism. * \param tid Traffic ID of transmitted packet. diff --git a/src/wifi/model/mac-low.cc b/src/wifi/model/mac-low.cc index 9bbaa4119..648042270 100644 --- a/src/wifi/model/mac-low.cc +++ b/src/wifi/model/mac-low.cc @@ -2594,8 +2594,8 @@ MacLow::AggregateToAmpdu (Ptr packet, const WifiMacHeader hdr) if (!hdr.GetAddr1 ().IsBroadcast () && edcaIt->second->GetMpduAggregator () != 0) { - //Have to make sure that their exist a block Ack agreement before sending an AMPDU (BlockAck Manager) - if (edcaIt->second->GetBaAgreementExists (hdr.GetAddr1 (), tid)) + //Have to make sure that the block ACK agreement is established before sending an AMPDU (BlockAck Manager) + if (edcaIt->second->GetBaAgreementEstablished (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*/ @@ -2849,7 +2849,7 @@ MacLow::AggregateToAmpdu (Ptr packet, const WifiMacHeader hdr) { InsertInTxQueue (packet, peekedHdr, tstamp, tid); } - if (edcaIt->second->GetBaAgreementExists (hdr.GetAddr1 (), tid)) + if (edcaIt->second->GetBaAgreementEstablished (hdr.GetAddr1 (), tid)) { edcaIt->second->CompleteAmpduTransfer (peekedHdr.GetAddr1 (), tid); } diff --git a/src/wifi/model/originator-block-ack-agreement.cc b/src/wifi/model/originator-block-ack-agreement.cc index 30c2e14fd..8288e7ee1 100644 --- a/src/wifi/model/originator-block-ack-agreement.cc +++ b/src/wifi/model/originator-block-ack-agreement.cc @@ -65,9 +65,21 @@ OriginatorBlockAckAgreement::IsInactive (void) const } bool -OriginatorBlockAckAgreement::IsUnsuccessful (void) const +OriginatorBlockAckAgreement::IsRejected (void) const { - return (m_state == UNSUCCESSFUL) ? true : false; + return (m_state == REJECTED) ? true : false; +} + +bool +OriginatorBlockAckAgreement::IsNoReply (void) const +{ + return (m_state == NO_REPLY) ? true : false; +} + +bool +OriginatorBlockAckAgreement::IsReset (void) const +{ + return (m_state == RESET) ? true : false; } void diff --git a/src/wifi/model/originator-block-ack-agreement.h b/src/wifi/model/originator-block-ack-agreement.h index 6895457e7..5dd5dca9b 100644 --- a/src/wifi/model/originator-block-ack-agreement.h +++ b/src/wifi/model/originator-block-ack-agreement.h @@ -28,7 +28,37 @@ namespace ns3 { /** * \ingroup wifi * Maintains the state and information about transmitted MPDUs with ack policy block ack - * for an originator station. + * for an originator station. The state diagram is as follows: + * + \verbatim + -------------- + | REJECTED | + -------------- + ^ + receive ADDBAResponse | + status code = failure | + | + | receive ADDBAResponse + /------------\ send ADDBARequest ---------------- status code = success ---------------- + | START |------------------>| PENDING |------------------------>| ESTABLISHED |----- + \------------/ ---------------- ---------------- | + ^ | / ^ ^ | + | no ADDBAResponse | receive BlockAck / | | | receive BlockAck + | v retryPkts + queuePkts / | | | retryPkts + queuePkts + | ---------------- < / | | | >= + |--------------------------| NO_REPLY | blockAckThreshold / | | | blockAckThreshold + Reset after timeout ---------------- / | | | + v | ----------| + --------------- | + | INACTIVE | | + --------------- | + send a MPDU (Normal Ack) | | + retryPkts + queuePkts | | + >= | | + blockAckThreshold |---------------- + \endverbatim + * + * See also OriginatorBlockAckAgreement::State */ class OriginatorBlockAckAgreement : public BlockAckAgreement { @@ -45,25 +75,6 @@ public: */ OriginatorBlockAckAgreement (Mac48Address recipient, uint8_t tid); ~OriginatorBlockAckAgreement (); - /* receive ADDBAResponse - * send ADDBARequest --------------- status code = success --------------- - * ----------------->| PENDING |------------------------>| ESTABLISHED |----- - * --------------- --------------- | - * | / ^ ^ | - * receive ADDBAResponse | receive BlockAck / | | | receive BlockAck - * status code = failure | retryPkts + queuePkts / | | | retryPkts + queuePkts - * v < / | | | >= - * --------------- blockAckThreshold / | | | blockAckThreshold - * | UNSUCCESSFUL | / | | | - * --------------- v | ----------| - * -------------- | - * | INACTIVE | | - * -------------- | - * send a MPDU (Normal Ack) | | - * retryPkts + queuePkts | | - * >= | | - * blockAckThreshold |---------------- - */ /** * Represents the state for this agreement. * @@ -82,17 +93,18 @@ public: * m_blockAckThreshold (see ns3::BlockAckManager). In these conditions the agreement becomes * INACTIVE until that the number of packets reaches the value of m_blockAckThreshold again. * - * UNSUCCESSFUL (not used for now): - * The agreement's state becomes UNSUCCESSFUL if: + * NO_REPLY + * No reply after an ADDBA request. In this state the originator will send the rest of packets + * in queue using normal MPDU. * - * - its previous state was PENDING and an ADDBAResponse frame wasn't received from - * recipient station within an interval of time defined by m_bAckSetupTimeout attribute - * in ns3::WifiMac. - * - an ADDBAResponse frame is received from recipient and the Status Code field is set - * to failure. + * RESET + * A transient state to mark the agreement for reinitialzation after failed ADDBA request. + * Since it is a temporary state, it is not included in the state diagram above. In this + * state the next transmission will be treated as if the BA agreement is not created yet. * - * In both cases for station addressed by BlockAckAgreement::m_peer and for - * TID BlockAckAgreement::m_tid block ack mechanism won't be used. + * REJECTED (not used for now): + * The agreement's state becomes REJECTED if an ADDBAResponse frame is received from recipient + * and the Status Code field is set to failure. */ /// State enumeration enum State @@ -100,7 +112,9 @@ public: PENDING, ESTABLISHED, INACTIVE, - UNSUCCESSFUL + NO_REPLY, + RESET, + REJECTED }; /** * Set the current state. @@ -130,12 +144,26 @@ public: */ bool IsInactive (void) const; /** - * Check if the current state of this agreement is UNSUCCESSFUL. + * Check if the current state of this agreement is NO_REPLY. + * + * \return true if the current state of this agreement is NO_REPLY, + * false otherwise + */ + bool IsNoReply (void) const; + /** + * Check if the current state of this agreement is RESET. + * + * \return true if the current state of this agreement is RESET, + * false otherwise + */ + bool IsReset (void) const; + /** + * Check if the current state of this agreement is REJECTED. * - * \return true if the current state of this agreement is UNSUCCESSFUL, + * \return true if the current state of this agreement is REJECTED, * false otherwise */ - bool IsUnsuccessful (void) const; + bool IsRejected (void) const; /** * Notifies a packet's transmission with ack policy Block Ack. * diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index 8f71607db..43a827de2 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -52,6 +52,22 @@ QosTxop::GetTypeId (void) .SetParent () .SetGroupName ("Wifi") .AddConstructor () + .AddAttribute ("AddBaResponseTimeout", + "The timeout to wait for ADDBA response after the ACK to " + "ADDBA request is received.", + TimeValue (MilliSeconds (1)), + MakeTimeAccessor (&QosTxop::SetAddBaResponseTimeout, + &QosTxop::GetAddBaResponseTimeout), + MakeTimeChecker ()) + .AddAttribute ("FailedAddBaTimeout", + "The timeout after a failed BA agreement. During this " + "timeout, the originator resumes sending packets using normal " + "MPDU. After that, BA agreement is reset and the originator " + "will retry BA negotiation.", + TimeValue (MilliSeconds (200)), + MakeTimeAccessor (&QosTxop::SetFailedAddBaTimeout, + &QosTxop::GetFailedAddBaTimeout), + MakeTimeChecker ()) .AddTraceSource ("BackoffTrace", "Trace source for backoff values", MakeTraceSourceAccessor (&QosTxop::m_backoffTrace), @@ -106,9 +122,9 @@ QosTxop::DoDispose (void) } bool -QosTxop::GetBaAgreementExists (Mac48Address address, uint8_t tid) const +QosTxop::GetBaAgreementEstablished (Mac48Address address, uint8_t tid) const { - return m_baManager->ExistsAgreement (address, tid); + return m_baManager->ExistsAgreementInState (address, tid, OriginatorBlockAckAgreement::ESTABLISHED); } void @@ -196,7 +212,8 @@ QosTxop::NotifyAccessGranted (void) m_currentPacketTimestamp = item->GetTimeStamp (); if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast () && m_stationManager->GetQosSupported (m_currentHdr.GetAddr1 ()) - && !m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ()) + && (!m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ()) + || m_baManager->ExistsAgreementInState (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid (), OriginatorBlockAckAgreement::RESET)) && SetupBlockAckIfNeeded ()) { return; @@ -442,7 +459,7 @@ QosTxop::MissedCts (void) uint8_t tid = GetTid (m_currentPacket, m_currentHdr); m_low->FlushAggregateQueue (tid); - if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid)) + if (GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), tid)) { NS_LOG_DEBUG ("Transmit Block Ack Request"); CtrlBAckRequestHeader reqHdr; @@ -505,18 +522,29 @@ QosTxop::GotAck (void) WifiActionHeader actionHdr; Ptr p = m_currentPacket->Copy (); p->RemoveHeader (actionHdr); - if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK - && actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_DELBA) + if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK) { - MgtDelBaHeader delBa; - p->PeekHeader (delBa); - if (delBa.IsByOriginator ()) + if (actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_DELBA) { - m_baManager->DestroyAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + MgtDelBaHeader delBa; + p->PeekHeader (delBa); + if (delBa.IsByOriginator ()) + { + m_baManager->DestroyAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + } + else + { + m_low->DestroyBlockAckAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + } } - else + else if (actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST) { - m_low->DestroyBlockAckAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + // Setup addba response timeout + MgtAddBaRequestHeader addBa; + p->PeekHeader (addBa); + Simulator::Schedule (m_addBaResponseTimeout, + &QosTxop::AddBaResponseTimeout, this, + m_currentHdr.GetAddr1 (), addBa.GetTid ()); } } } @@ -567,11 +595,25 @@ QosTxop::MissedAck (void) { m_txFailedCallback (m_currentHdr); } + if (m_currentHdr.IsAction ()) + { + WifiActionHeader actionHdr; + m_currentPacket->PeekHeader (actionHdr); + if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK) + { + uint8_t tid = GetTid (m_currentPacket, m_currentHdr); + if (m_baManager->ExistsAgreementInState (m_currentHdr.GetAddr1 (), tid, OriginatorBlockAckAgreement::PENDING)) + { + NS_LOG_DEBUG ("No ACK after ADDBA request"); + m_baManager->NotifyAgreementNoReply (m_currentHdr.GetAddr1 (), tid); + Simulator::Schedule (m_failedAddBaTimeout, &QosTxop::ResetBa, this, m_currentHdr.GetAddr1 (), tid); + } + } + } if (GetAmpduExist (m_currentHdr.GetAddr1 ()) || m_currentHdr.IsQosData ()) { uint8_t tid = GetTid (m_currentPacket, m_currentHdr); - - if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid)) + if (GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), tid)) { //send Block ACK Request in order to shift WinStart at the receiver NS_LOG_DEBUG ("Transmit Block Ack Request"); @@ -955,7 +997,7 @@ QosTxop::NeedFragmentation (void) const || GetAmpduExist (m_currentHdr.GetAddr1 ()) || (m_stationManager->GetHtSupported () && m_currentHdr.IsQosData () - && GetBaAgreementExists (m_currentHdr.GetAddr1 (), GetTid (m_currentPacket, m_currentHdr)) + && GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), GetTid (m_currentPacket, m_currentHdr)) && GetMpduAggregator ()->GetMaxAmpduSize () >= m_currentPacket->GetSize ())) { //MSDU is not fragmented when it is transmitted using an HT-immediate or @@ -1238,7 +1280,7 @@ QosTxop::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address r else { NS_LOG_DEBUG ("discard ADDBA response" << recipient); - m_baManager->NotifyAgreementUnsuccessful (recipient, tid); + m_baManager->NotifyAgreementRejected (recipient, tid); } } RestartAccessIfNeeded (); @@ -1559,6 +1601,55 @@ QosTxop::BaTxFailed (const WifiMacHeader &hdr) } } +void +QosTxop::AddBaResponseTimeout (Mac48Address recipient, uint8_t tid) +{ + NS_LOG_FUNCTION (this << recipient << +tid); + // If agreement is still pending, ADDBA response is not received + if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING)) + { + m_baManager->NotifyAgreementNoReply (recipient, tid); + Simulator::Schedule (m_failedAddBaTimeout, &QosTxop::ResetBa, this, m_currentHdr.GetAddr1 (), tid); + m_backoffTrace = m_rng->GetInteger (0, GetCw ()); + StartBackoffNow (m_backoffTrace); + RestartAccessIfNeeded (); + } +} + +void +QosTxop::ResetBa (Mac48Address recipient, uint8_t tid) +{ + NS_LOG_FUNCTION (this << recipient << +tid); + NS_ASSERT (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::NO_REPLY)); + m_baManager->NotifyAgreementReset (recipient, tid); +} + +void +QosTxop::SetAddBaResponseTimeout (Time addBaResponseTimeout) +{ + NS_LOG_FUNCTION (this << addBaResponseTimeout); + m_addBaResponseTimeout = addBaResponseTimeout; +} + +Time +QosTxop::GetAddBaResponseTimeout (void) const +{ + return m_addBaResponseTimeout; +} + +void +QosTxop::SetFailedAddBaTimeout (Time failedAddBaTimeout) +{ + NS_LOG_FUNCTION (this << failedAddBaTimeout); + m_failedAddBaTimeout = failedAddBaTimeout; +} + +Time +QosTxop::GetFailedAddBaTimeout (void) const +{ + return m_failedAddBaTimeout; +} + bool QosTxop::IsQosTxop (void) const { diff --git a/src/wifi/model/qos-txop.h b/src/wifi/model/qos-txop.h index 7a48c036a..810d81a02 100644 --- a/src/wifi/model/qos-txop.h +++ b/src/wifi/model/qos-txop.h @@ -147,12 +147,12 @@ public: * \param address recipient address of the peer station * \param tid traffic ID. * - * \return true if a block ack agreement exists, false otherwise. + * \return true if a block ack agreement is established, false otherwise. * - * Checks if a block ack agreement exists with station addressed by + * Checks if a block ack agreement is established with station addressed by * recipient for tid tid. */ - bool GetBaAgreementExists (Mac48Address address, uint8_t tid) const; + bool GetBaAgreementEstablished (Mac48Address address, uint8_t tid) const; /** * \param recipient address of peer station involved in block ack mechanism. * \param tid Ttraffic ID of transmitted packet. @@ -349,6 +349,31 @@ public: * \param enableAmpdu flag whether A-MPDU is used or not. */ void SetAmpduExist (Mac48Address dest, bool enableAmpdu); + /** + * Set the timeout to wait for ADDBA response. + * + * \param addBaResponseTimeout the timeout to wait for ADDBA response + */ + void SetAddBaResponseTimeout (Time addBaResponseTimeout); + /** + * Get the timeout for ADDBA response. + * + * \returns the timeout to wait for ADDBA response + */ + Time GetAddBaResponseTimeout (void) const; + /** + * Set the timeout for failed BA agreement. During the timeout period, + * all packets will be transmitted using normal MPDU. + * + * \param failedAddBaTimeout the timeout for failed BA agreement + */ + void SetFailedAddBaTimeout (Time failedAddBaTimeout); + /** + * Get the timeout for failed BA agreement. + * + * \returns the timeout for failed BA agreement + */ + Time GetFailedAddBaTimeout (void) const; /** * Return the next sequence number for the given header. @@ -533,6 +558,20 @@ private: * \returns the TXOP fragment offset */ uint32_t GetTxopFragmentOffset (uint32_t fragmentNumber) const; + /** + * Callback when ADDBA response is not received after timeout. + * + * \param recipient MAC address of recipient + * \param tid traffic ID + */ + void AddBaResponseTimeout (Mac48Address recipient, uint8_t tid); + /** + * Reset BA agreement after BA negotiation failed. + * + * \param recipient MAC address of recipient + * \param tid traffic ID + */ + void ResetBa (Mac48Address recipient, uint8_t tid); void DoDispose (void); void DoInitialize (void); @@ -551,6 +590,8 @@ private: Time m_startTxop; //!< the start TXOP time bool m_isAccessRequestedForRts; //!< flag whether access is requested to transmit a RTS frame bool m_currentIsFragmented; //!< flag whether current packet is fragmented + Time m_addBaResponseTimeout; //!< timeout for ADDBA response + Time m_failedAddBaTimeout; //!< timeout after failed BA agreement TracedValue m_backoffTrace; //!< backoff trace value TracedValue m_cwTrace; //!< CW trace value diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index f7e6b2848..79f9028f3 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -24,6 +24,7 @@ #include "ns3/pointer.h" #include "ns3/mobility-model.h" #include "ns3/random-variable-stream.h" +#include "ns3/error-model.h" #include "wifi-phy.h" #include "wifi-phy-tag.h" #include "ampdu-tag.h" @@ -298,6 +299,14 @@ WifiPhy::GetTypeId (void) PointerValue (), MakePointerAccessor (&WifiPhy::m_frameCaptureModel), MakePointerChecker ()) + .AddAttribute ("PostReceptionErrorModel", + "An optional packet error model can be added to the receive " + "packet process after any propagation-based (SNR-based) error " + "models have been applied. Typically this is used to force " + "specific packet drops, for testing purposes.", + PointerValue (), + MakePointerAccessor (&WifiPhy::m_postReceptionErrorModel), + MakePointerChecker ()) .AddTraceSource ("PhyTxBegin", "Trace source indicating a packet " "has begun transmitting over the channel medium", @@ -387,6 +396,7 @@ WifiPhy::DoDispose (void) m_mobility = 0; m_state = 0; m_wifiRadioEnergyModel = 0; + m_postReceptionErrorModel = 0; m_deviceRateSet.clear (); m_deviceMcsSet.clear (); } @@ -718,6 +728,13 @@ WifiPhy::SetErrorRateModel (const Ptr rate) m_interference.SetNumberOfReceiveAntennas (GetNumberOfAntennas ()); } +void +WifiPhy::SetPostReceptionErrorModel (const Ptr em) +{ + NS_LOG_FUNCTION (this << em); + m_postReceptionErrorModel = em; +} + void WifiPhy::SetFrameCaptureModel (const Ptr model) { @@ -2588,7 +2605,14 @@ WifiPhy::EndReceive (Ptr packet, WifiPreamble preamble, MpduType mpdutyp NS_LOG_DEBUG ("mode=" << (event->GetPayloadMode ().GetDataRate (event->GetTxVector ())) << ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << packet->GetSize ()); - if (m_random->GetValue () > snrPer.per) + // + // There are two error checks: PER and receive error model check. + // PER check models is typical for Wi-Fi and is based on signal modulation; + // Receive error model is optional, if we have an error model and + // it indicates that the packet is corrupt, drop the packet. + // + if (m_random->GetValue () > snrPer.per && + !(m_postReceptionErrorModel && m_postReceptionErrorModel->IsCorrupt (packet))) { NotifyRxEnd (packet); SignalNoiseDbm signalNoise; diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 3bf8b7066..2fda0c88a 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -41,6 +41,7 @@ class WifiPhyStateHelper; class FrameCaptureModel; class WifiRadioEnergyModel; class UniformRandomVariable; +class ErrorModel; /// SignalNoiseDbm structure struct SignalNoiseDbm @@ -1409,6 +1410,18 @@ public: * \param rate the error rate model */ void SetErrorRateModel (const Ptr rate); + /** + * Attach a receive ErrorModel to the WifiPhy. + * + * The WifiPhy may optionally include an ErrorModel in + * the packet receive chain. The error model is additive + * to any modulation-based error model based on SNR, and + * is typically used to force specific packet losses or + * for testing purposes. + * + * \param em Ptr to the ErrorModel. + */ + void SetPostReceptionErrorModel (const Ptr em); /** * Sets the frame capture model. * @@ -1777,6 +1790,7 @@ private: Ptr m_currentEvent; //!< Hold the current event Ptr m_frameCaptureModel; //!< Frame capture model Ptr m_wifiRadioEnergyModel; //!< Wifi radio energy model + Ptr m_postReceptionErrorModel; //!< Error model for receive packet events Callback m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed }; diff --git a/src/wifi/test/wifi-aggregation-test.cc b/src/wifi/test/wifi-aggregation-test.cc index 507c000f2..6ac3e6c84 100644 --- a/src/wifi/test/wifi-aggregation-test.cc +++ b/src/wifi/test/wifi-aggregation-test.cc @@ -128,6 +128,7 @@ AmpduAggregationTest::DoRun (void) reqHdr.SetTimeout (0); reqHdr.SetStartingSequence (0); m_mac->GetBEQueue ()->m_baManager->CreateAgreement (&reqHdr, hdr.GetAddr1 ()); + m_mac->GetBEQueue ()->m_baManager->NotifyAgreementEstablished (hdr.GetAddr1 (), 0, 0); //----------------------------------------------------------------------------------------------------- diff --git a/src/wifi/test/wifi-test.cc b/src/wifi/test/wifi-test.cc index 73f69ad15..614fe9606 100644 --- a/src/wifi/test/wifi-test.cc +++ b/src/wifi/test/wifi-test.cc @@ -34,6 +34,7 @@ #include "ns3/pointer.h" #include "ns3/rng-seed-manager.h" #include "ns3/config.h" +#include "ns3/error-model.h" #include "ns3/packet-socket-server.h" #include "ns3/packet-socket-client.h" #include "ns3/packet-socket-helper.h" @@ -605,8 +606,6 @@ Bug730TestCase::DoRun (void) { m_received = 0; - Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2304")); - NodeContainer wifiStaNode; wifiStaNode.Create (1); @@ -899,7 +898,6 @@ SetChannelFrequencyTest::DoRun () NS_TEST_ASSERT_MSG_EQ (phySta->GetChannelWidth (), 40, "802.11 5GHz configuration"); NS_TEST_ASSERT_MSG_EQ (phySta->GetFrequency (), 5220, "802.11 5GHz configuration"); } - // modify cases 13 and 14 to avoid Config::SetDefault () { // case 13 WifiHelper wifi; @@ -1268,9 +1266,6 @@ Bug2483TestCase::SendPacketBurst (uint8_t numPackets, Ptr sourceDevic void Bug2483TestCase::DoRun (void) { - Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("500")); // so as to force RTS/CTS for data frames - Config::SetDefault ("ns3::WifiPhy::CcaMode1Threshold", DoubleValue (-62.0)); - uint16_t channelWidth = 40; // at least 40 MHz expected here NodeContainer wifiStaNode; @@ -1295,12 +1290,14 @@ Bug2483TestCase::DoRun (void) spectrumPhy.Set ("ChannelWidth", UintegerValue (channelWidth)); spectrumPhy.Set ("TxPowerStart", DoubleValue (10)); spectrumPhy.Set ("TxPowerEnd", DoubleValue (10)); + spectrumPhy.Set ("CcaMode1Threshold", DoubleValue (-62.0)); WifiHelper wifi; wifi.SetStandard (WIFI_PHY_STANDARD_80211ac); wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("VhtMcs8"), - "ControlMode", StringValue ("VhtMcs8")); + "ControlMode", StringValue ("VhtMcs8"), + "RtsCtsThreshold", StringValue ("500")); // so as to force RTS/CTS for data frames WifiMacHelper mac; mac.SetType ("ns3::StaWifiMac"); @@ -1700,6 +1697,227 @@ StaWifiMacScanningTestCase::DoRun (void) } } +//----------------------------------------------------------------------------- +/** + * Make sure that the ADDBA handshake process is protected. + * + * The scenario considers an access point and a station. It utilizes + * ReceiveListErrorModel to drop by force ADDBA request on STA or ADDBA + * response on AP. The AP sends 5 packets of each 1000 bytes (thus generating + * BA agreement), 2 times during the test at 0.5s and 0.8s. We only drop the + * first ADDBA request/response of the first BA negotiation. Therefore, we + * expect that the packets still in queue after the failed BA agreement will be + * sent with normal MPDU, and packets queued after that should be sent with + * A-MPDU. + * + * This test consider 2 cases: + * + * 1. ADDBA request packets are blocked on receive at STA, triggering + * transmission failure at AP + * 2. ADDBA response packets are blocked on receive at AP, STA stops + * retransmission of ADDBA response + * + * See \bugid{2470} + */ + +class Bug2470TestCase : public TestCase +{ +public: + Bug2470TestCase (); + virtual ~Bug2470TestCase (); + virtual void DoRun (void); + +private: + /** + * Callback when packet is received + * \param context node context + * \param p the received packet + * \param channelFreqMhz the channel frequency in MHz + * \param txVector the TX vector + * \param aMpdu the A-MPDU info + * \param signalNoise the signal noise in dBm + */ + void RxCallback (std::string context, Ptr p, uint16_t channelFreqMhz, WifiTxVector txVector, MpduInfo aMpdu, SignalNoiseDbm signalNoise); + /** + * Callback when packet is dropped + * \param context node context + * \param p the received packet + */ + void RxDropCallback (std::string context, Ptr p); + /** + * Triggers the arrival of a burst of 1000 Byte-long packets in the source device + * \param numPackets number of packets in burst + * \param sourceDevice pointer to the source NetDevice + * \param destination address of the destination device + */ + void SendPacketBurst (uint32_t numPackets, Ptr sourceDevice, Address& destination) const; + /** + * Run subtest for this test suite + * \param apErrorModel ErrorModel used for AP + * \param staErrorModel ErrorModel used for STA + */ + void RunSubtest (PointerValue apErrorModel, PointerValue staErrorModel); + + uint8_t m_receivedNormalMpduCount; ///< Count received normal MPDU packets on STA + uint8_t m_receivedAmpduCount; ///< Count received A-MPDU packets on STA + uint8_t m_droppedActionCount; ///< Count dropped ADDBA request/response +}; + +Bug2470TestCase::Bug2470TestCase () + : TestCase ("Test case for Bug 2470"), + m_receivedNormalMpduCount (0), + m_receivedAmpduCount (0), + m_droppedActionCount (0) +{ +} + +Bug2470TestCase::~Bug2470TestCase () +{ +} + +void +Bug2470TestCase::RxCallback (std::string context, Ptr p, uint16_t channelFreqMhz, WifiTxVector txVector, MpduInfo aMpdu, SignalNoiseDbm signalNoise) +{ + Ptr packet = p->Copy (); + if (aMpdu.type != MpduType::NORMAL_MPDU) + { + m_receivedAmpduCount++; + } + else + { + WifiMacHeader hdr; + packet->RemoveHeader (hdr); + if (hdr.IsData ()) + { + m_receivedNormalMpduCount++; + } + } +} + +void +Bug2470TestCase::RxDropCallback (std::string context, Ptr p) +{ + Ptr packet = p->Copy (); + WifiMacHeader hdr; + packet->RemoveHeader (hdr); + if (hdr.IsAction ()) + { + m_droppedActionCount++; + } +} + +void +Bug2470TestCase::SendPacketBurst (uint32_t numPackets, Ptr sourceDevice, + Address& destination) const +{ + for (uint32_t i = 0; i < numPackets; i++) + { + Ptr pkt = Create (1000); // 1000 dummy bytes of data + sourceDevice->Send (pkt, destination, 0); + } +} + +void +Bug2470TestCase::RunSubtest (PointerValue apErrorModel, PointerValue staErrorModel) +{ + RngSeedManager::SetSeed (1); + RngSeedManager::SetRun (1); + + NodeContainer wifiApNode, wifiStaNode; + wifiApNode.Create (1); + wifiStaNode.Create (1); + + YansWifiPhyHelper phy = YansWifiPhyHelper::Default (); + YansWifiChannelHelper channel = YansWifiChannelHelper::Default (); + phy.SetChannel (channel.Create ()); + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211n_5GHZ); + wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode", StringValue ("HtMcs7"), + "ControlMode", StringValue ("HtMcs7")); + + WifiMacHelper mac; + NetDeviceContainer apDevice; + phy.Set ("PostReceptionErrorModel", apErrorModel); + mac.SetType ("ns3::ApWifiMac", "EnableBeaconJitter", BooleanValue (false)); + apDevice = wifi.Install (phy, mac, wifiApNode); + + NetDeviceContainer staDevice; + phy.Set ("PostReceptionErrorModel", staErrorModel); + mac.SetType ("ns3::StaWifiMac"); + staDevice = wifi.Install (phy, mac, wifiStaNode); + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (1.0, 0.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiApNode); + mobility.Install (wifiStaNode); + + Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/MonitorSnifferRx", MakeCallback (&Bug2470TestCase::RxCallback, this)); + Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/PhyRxDrop", MakeCallback (&Bug2470TestCase::RxDropCallback, this)); + + Simulator::Schedule (Seconds (0.5), &Bug2470TestCase::SendPacketBurst, this, 5, apDevice.Get (0), staDevice.Get (0)->GetAddress ()); + Simulator::Schedule (Seconds (0.8), &Bug2470TestCase::SendPacketBurst, this, 5, apDevice.Get (0), staDevice.Get (0)->GetAddress ()); + + Simulator::Stop (Seconds (1.0)); + Simulator::Run (); + Simulator::Destroy (); +} + +void +Bug2470TestCase::DoRun (void) +{ + // Create ReceiveListErrorModel to corrupt ADDBA req packet. We use ReceiveListErrorModel + // instead of ListErrorModel since packet UID is incremented between simulations. But + // problem may occur because of random stream, therefore we suppress usage of RNG as + // much as possible (i.e., removing beacon jitter). + Ptr staPem = CreateObject (); + std::list blackList; + // Block ADDBA request 6 times (== maximum number of MAC frame transmissions in the addba response timeout interval) + blackList.push_back (8); + blackList.push_back (9); + blackList.push_back (10); + blackList.push_back (11); + blackList.push_back (12); + blackList.push_back (13); + staPem->SetList (blackList); + + { + RunSubtest (PointerValue (), PointerValue (staPem)); + NS_TEST_ASSERT_MSG_EQ (m_droppedActionCount, 6, "ADDBA request packet is not dropped correctly"); + // There are two sets of 5 packets to be transmitted. The first 5 packets should be sent by normal + // MPDU because of failed ADDBA handshake. For the second set, the first packet should be sent by + // normal MPDU, and the rest with A-MPDU. In total we expect to receive 2 normal MPDU packets and + // 8 A-MPDU packets. + NS_TEST_ASSERT_MSG_EQ (m_receivedNormalMpduCount, 2, "Receiving incorrect number of normal MPDU packet on subtest 1"); + NS_TEST_ASSERT_MSG_EQ (m_receivedAmpduCount, 8, "Receiving incorrect number of A-MPDU packet on subtest 1"); + } + + m_receivedNormalMpduCount = 0; + m_receivedAmpduCount = 0; + m_droppedActionCount = 0; + Ptr apPem = CreateObject (); + blackList.clear (); + // Block ADDBA request 3 times (== maximum number of MAC frame transmissions in the addba response timeout interval) + blackList.push_back (4); + blackList.push_back (5); + blackList.push_back (6); + apPem->SetList (blackList); + + { + RunSubtest (PointerValue (apPem), PointerValue ()); + NS_TEST_ASSERT_MSG_EQ (m_droppedActionCount, 3, "ADDBA response packet is not dropped correctly"); + // Similar to subtest 1, we also expect to receive 6 normal MPDU packets and 4 A-MPDU packets. + NS_TEST_ASSERT_MSG_EQ (m_receivedNormalMpduCount, 6, "Receiving incorrect number of normal MPDU packet on subtest 2"); + NS_TEST_ASSERT_MSG_EQ (m_receivedAmpduCount, 4, "Receiving incorrect number of A-MPDU packet on subtest 2"); + } +} + /** * \ingroup wifi-test * \ingroup tests @@ -1725,6 +1943,7 @@ WifiTestSuite::WifiTestSuite () AddTestCase (new Bug2483TestCase, TestCase::QUICK); //Bug 2483 AddTestCase (new Bug2831TestCase, TestCase::QUICK); //Bug 2831 AddTestCase (new StaWifiMacScanningTestCase, TestCase::QUICK); //Bug 2399 + AddTestCase (new Bug2470TestCase, TestCase::QUICK); //Bug 2470 } static WifiTestSuite g_wifiTestSuite; ///< the test suite