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.
- The attributes RegularWifiMac::HtSupported, RegularWifiMac::VhtSupported, RegularWifiMac::HeSupported, RegularWifiMac::RifsSupported, WifiPhy::ShortGuardEnabled, WifiPhy::GuardInterval and WifiPhy::GreenfieldEnabled have been deprecated. Intead, it is advised to use WifiNetDevice::HtConfiguration, WifiNetDevice::VhtConfiguration and WifiNetDevice::HeConfiguration.
+- A new attribute WifiPhy::PostReceptionErrorModel has been added to force specific packet drops.
+
+
+- New attributes QosTxop::AddBaResponseTimeout and QosTxop::FailedAddBaTimeout have been added to set the timeout to wait for an ADDBA response after the ACK to the ADDBA request is received and to set the timeout after a failed BA agreement, respectively.
+
Changes to existing API:
@@ -71,6 +76,7 @@ us a note on ns-developers mailing list.
Changed behavior:
+ - The wifi ADDBA handshake process is now protected with the use of two timeouts who makes sure we do not end up in a blocked situation. If the handshake process is not established, packets that are in the queue are sent as normal MPDUs. Once handshake is successfully established, A-MPDUs can be transmitted.
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