wifi: (fixes #2470) Protect ADDBA handshake

This commit is contained in:
Sébastien Deronne
2018-11-10 19:37:36 +01:00
parent a6e4169bee
commit b3ce7e5628
13 changed files with 554 additions and 75 deletions

View File

@@ -56,6 +56,11 @@ us a note on ns-developers mailing list.</p>
<ul>
<li>The attributes <b>RegularWifiMac::HtSupported</b>, <b>RegularWifiMac::VhtSupported</b>, <b>RegularWifiMac::HeSupported</b>, <b>RegularWifiMac::RifsSupported</b>, <b>WifiPhy::ShortGuardEnabled</b>, <b>WifiPhy::GuardInterval</b> and <b>WifiPhy::GreenfieldEnabled</b> have been deprecated. Intead, it is advised to use <b>WifiNetDevice::HtConfiguration</b>, <b>WifiNetDevice::VhtConfiguration</b> and <b>WifiNetDevice::HeConfiguration</b>.
</li>
<li>A new attribute <b>WifiPhy::PostReceptionErrorModel</b> has been added to force specific packet drops.
</li>
</li>
<li>New attributes <b>QosTxop::AddBaResponseTimeout</b> and <b>QosTxop::FailedAddBaTimeout</b> 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.
</li>
</ul>
<h2>Changes to existing API:</h2>
<ul>
@@ -71,6 +76,7 @@ us a note on ns-developers mailing list.</p>
</ul>
<h2>Changed behavior:</h2>
<ul>
<li>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.</li>
</ul>
<hr>

View File

@@ -27,6 +27,7 @@ New user-visible features
Bugs fixed
----------
- Bug 2470 - wifi: Handshake to setup the Block Ack Agreement is not protected
- Bug 2992 - lte: Send method of the LteUeNetDevice doesn't use protocolNumber parameter
- Bug 2997 - lte: EpcTft::PacketFilter::Matches does not use ipv6 address to match an IP packet
- Bug 2860 - mobility: Set Z coordinate for position-allocation classes

View File

@@ -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<OriginatorBlockAckAgreement, PacketQueue> 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);

View File

@@ -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 <i>recipient</i> station reject block ack setup
* Marks an agreement as rejected. This happens if <i>recipient</i> 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.

View File

@@ -2594,8 +2594,8 @@ MacLow::AggregateToAmpdu (Ptr<const Packet> 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<const Packet> 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);
}

View File

@@ -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

View File

@@ -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 UNSUCCESSFUL,
* \return true if the current state of this agreement is NO_REPLY,
* false otherwise
*/
bool IsUnsuccessful (void) const;
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 REJECTED,
* false otherwise
*/
bool IsRejected (void) const;
/**
* Notifies a packet's transmission with ack policy Block Ack.
*

View File

@@ -52,6 +52,22 @@ QosTxop::GetTypeId (void)
.SetParent<ns3::Txop> ()
.SetGroupName ("Wifi")
.AddConstructor<QosTxop> ()
.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<Packet> 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
{

View File

@@ -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
* <i>recipient</i> for tid <i>tid</i>.
*/
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<uint32_t> m_backoffTrace; //!< backoff trace value
TracedValue<uint32_t> m_cwTrace; //!< CW trace value

View File

@@ -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 <FrameCaptureModel> ())
.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<ErrorModel> ())
.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<ErrorRateModel> rate)
m_interference.SetNumberOfReceiveAntennas (GetNumberOfAntennas ());
}
void
WifiPhy::SetPostReceptionErrorModel (const Ptr<ErrorModel> em)
{
NS_LOG_FUNCTION (this << em);
m_postReceptionErrorModel = em;
}
void
WifiPhy::SetFrameCaptureModel (const Ptr<FrameCaptureModel> model)
{
@@ -2588,7 +2605,14 @@ WifiPhy::EndReceive (Ptr<Packet> 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;

View File

@@ -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<ErrorRateModel> 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<ErrorModel> em);
/**
* Sets the frame capture model.
*
@@ -1777,6 +1790,7 @@ private:
Ptr<Event> m_currentEvent; //!< Hold the current event
Ptr<FrameCaptureModel> m_frameCaptureModel; //!< Frame capture model
Ptr<WifiRadioEnergyModel> m_wifiRadioEnergyModel; //!< Wifi radio energy model
Ptr<ErrorModel> m_postReceptionErrorModel; //!< Error model for receive packet events
Callback<void> m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed
};

View File

@@ -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);
//-----------------------------------------------------------------------------------------------------

View File

@@ -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<NetDevice> 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<const Packet> 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<const Packet> 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<NetDevice> 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<const Packet> p, uint16_t channelFreqMhz, WifiTxVector txVector, MpduInfo aMpdu, SignalNoiseDbm signalNoise)
{
Ptr<Packet> 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<const Packet> p)
{
Ptr<Packet> packet = p->Copy ();
WifiMacHeader hdr;
packet->RemoveHeader (hdr);
if (hdr.IsAction ())
{
m_droppedActionCount++;
}
}
void
Bug2470TestCase::SendPacketBurst (uint32_t numPackets, Ptr<NetDevice> sourceDevice,
Address& destination) const
{
for (uint32_t i = 0; i < numPackets; i++)
{
Ptr<Packet> pkt = Create<Packet> (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<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
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<ReceiveListErrorModel> staPem = CreateObject<ReceiveListErrorModel> ();
std::list<uint32_t> 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<ReceiveListErrorModel> apPem = CreateObject<ReceiveListErrorModel> ();
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