wifi: Update backoff before checking for immediate access

This commit is contained in:
Stefano Avallone
2020-02-21 16:13:13 +01:00
parent bdf4fafe5c
commit d1d8558d65
17 changed files with 73 additions and 53 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -242,6 +242,56 @@ ChannelAccessManager::IsBusy (void) const
return false;
}
bool
ChannelAccessManager::NeedBackoffUponAccess (Ptr<Txop> txop)
{
NS_LOG_FUNCTION (this << txop);
// the Txop might have a stale value of remaining backoff slots
UpdateBackoff ();
/*
* From section 10.3.4.2 "Basic access" of IEEE 802.11-2016:
*
* A STA may transmit an MPDU when it is operating under the DCF access
* method, either in the absence of a PC, or in the CP of the PCF access
* method, when the STA determines that the medium is idle when a frame is
* queued for transmission, and remains idle for a period of a DIFS, or an
* EIFS (10.3.2.3.7) from the end of the immediately preceding medium-busy
* event, whichever is the greater, and the backoff timer is zero. Otherwise
* the random backoff procedure described in 10.3.4.3 shall be followed.
*
* From section 10.22.2.2 "EDCA backoff procedure" of IEEE 802.11-2016:
*
* The backoff procedure shall be invoked by an EDCAF when any of the following
* events occurs:
* a) An MA-UNITDATA.request primitive is received that causes a frame with that AC
* to be queued for transmission such that one of the transmit queues associated
* with that AC has now become non-empty and any other transmit queues
* associated with that AC are empty; the medium is busy on the primary channel
*/
if (!txop->HasFramesToTransmit () && !txop->GetLow ()->IsCfPeriod () && txop->GetBackoffSlots () == 0)
{
if (!IsBusy ())
{
// medium idle. If this is a DCF, use immediate access (we can transmit
// in a DIFS if the medium remains idle). If this is an EDCAF, update
// the backoff start time kept by the EDCAF to the current time in order
// to correctly align the backoff start time at the next slot boundary
// (performed by the next call to ChannelAccessManager::RequestAccess())
Time delay = (txop->IsQosTxop () ? Seconds (0)
: m_sifs + txop->GetAifsn () * m_slot);
txop->UpdateBackoffSlotsNow (0, Simulator::Now () + delay);
}
else
{
// medium busy, backoff is neeeded
return true;
}
}
return false;
}
void
ChannelAccessManager::RequestAccess (Ptr<Txop> state, bool isCfPeriod)
{

View File

@@ -112,6 +112,15 @@ public:
*/
void Add (Ptr<Txop> dcf);
/**
* Determine if a new backoff needs to be generated when a packet is queued
* for transmission.
*
* \param txop the Txop requesting to generate a backoff
* \return true if backoff needs to be generated, false otherwise
*/
bool NeedBackoffUponAccess (Ptr<Txop> txop);
/**
* \param state a Txop
* \param isCfPeriod flag whether it is called during the CF period

View File

@@ -312,50 +312,6 @@ Txop::HasFramesToTransmit (void)
return ret;
}
void
Txop::GenerateBackoffUponAccessIfNeeded (void)
{
NS_LOG_FUNCTION (this);
/*
* From section 10.3.4.2 "Basic access" of IEEE 802.11-2016:
*
* A STA may transmit an MPDU when it is operating under the DCF access
* method, either in the absence of a PC, or in the CP of the PCF access
* method, when the STA determines that the medium is idle when a frame is
* queued for transmission, and remains idle for a period of a DIFS, or an
* EIFS (10.3.2.3.7) from the end of the immediately preceding medium-busy
* event, whichever is the greater, and the backoff timer is zero. Otherwise
* the random backoff procedure described in 10.3.4.3 shall be followed.
*
* From section 10.22.2.2 "EDCA backoff procedure" of IEEE 802.11-2016:
*
* The backoff procedure shall be invoked by an EDCAF when any of the following
* events occurs:
* a) An MA-UNITDATA.request primitive is received that causes a frame with that AC
* to be queued for transmission such that one of the transmit queues associated
* with that AC has now become non-empty and any other transmit queues
* associated with that AC are empty; the medium is busy on the primary channel
*/
if (!HasFramesToTransmit () && !m_low->IsCfPeriod () && m_backoffSlots == 0)
{
if (!m_channelAccessManager->IsBusy ())
{
// medium idle. If this is a DCF, use immediate access (we can transmit
// in a DIFS if the medium remains idle). If this is an EDCAF, update
// the backoff start time kept by the EDCAF to the current time in order
// to correctly align the backoff start time at the next slot boundary
// (performed by the next call to ChannelAccessManager::RequestAccess())
Time delay = (IsQosTxop () ? Seconds (0) : m_low->GetSifs () + GetAifsn () * m_low->GetSlotTime ());
UpdateBackoffSlotsNow (0, Simulator::Now () + delay);
}
else
{
// medium busy, generate backoff
GenerateBackoff ();
}
}
}
void
Txop::Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr)
{
@@ -365,7 +321,10 @@ Txop::Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr)
SocketPriorityTag priorityTag;
packetCopy->RemovePacketTag (priorityTag);
m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr, packetCopy);
GenerateBackoffUponAccessIfNeeded ();
if (m_channelAccessManager->NeedBackoffUponAccess (this))
{
GenerateBackoff ();
}
m_queue->Enqueue (Create<WifiMacQueueItem> (packetCopy, hdr));
StartAccessIfNeeded ();
}

View File

@@ -376,10 +376,6 @@ protected:
* \return true if the DCF has frames to transmit.
*/
virtual bool HasFramesToTransmit (void);
/**
* Generate a new backoff, if needed, when a packet is queued for transmission.
*/
virtual void GenerateBackoffUponAccessIfNeeded (void);
/**
* Generate a new backoff now.
*/

View File

@@ -679,7 +679,10 @@ void
ChannelAccessManagerTest<TxopType>::DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime,
Ptr<TxopTest<TxopType>> state)
{
state->GenerateBackoffUponAccessIfNeeded ();
if (m_ChannelAccessManager->NeedBackoffUponAccess (state))
{
state->GenerateBackoff ();
}
state->QueueTx (txTime, expectedGrantTime);
m_ChannelAccessManager->RequestAccess (state);
}

View File

@@ -460,7 +460,6 @@ DcfImmediateAccessBroadcastTestCase::NotifyPhyTxBegin (Ptr<const Packet> p, doub
{
if (m_numSentPackets == 0)
{
NS_ASSERT_MSG (Simulator::Now () == Time (Seconds (1)), "Packet 0 not transmitted at 1 second");
m_numSentPackets++;
m_firstTransmissionTime = Simulator::Now ();
}
@@ -536,13 +535,17 @@ DcfImmediateAccessBroadcastTestCase::DoRun (void)
Simulator::Run ();
Simulator::Destroy ();
// First packet is transmitted a DIFS after the packet is queued. A DIFS
// is 2 slots (2 * 9 = 18 us) plus a SIFS (16 us), i.e., 34 us
Time expectedFirstTransmissionTime = Seconds (1.0) + MicroSeconds (34);
//First packet has 1408 us of transmit time. Slot time is 9 us.
//Backoff is 1 slots. SIFS is 16 us. DIFS is 2 slots = 18 us.
//Should send next packet at 1408 us + (1 * 9 us) + 16 us + (2 * 9) us
//1451 us after the first one.
uint32_t expectedWait1 = 1408 + (1 * 9) + 16 + (2 * 9);
Time expectedSecondTransmissionTime = MicroSeconds (expectedWait1) + MilliSeconds (1000);
NS_TEST_ASSERT_MSG_EQ (m_firstTransmissionTime, MilliSeconds (1000), "The first transmission time not correct!");
Time expectedSecondTransmissionTime = expectedFirstTransmissionTime + MicroSeconds (expectedWait1);
NS_TEST_ASSERT_MSG_EQ (m_firstTransmissionTime, expectedFirstTransmissionTime, "The first transmission time not correct!");
NS_TEST_ASSERT_MSG_EQ (m_secondTransmissionTime, expectedSecondTransmissionTime, "The second transmission time not correct!");
}