--- a/src/devices/wifi/dcf-manager-test.cc Mon Nov 23 13:52:51 2009 +0100 +++ a/src/devices/wifi/dcf-manager-test.cc Mon Nov 23 18:16:11 2009 +0100 @@ -30,7 +30,7 @@ class DcfStateTest : public DcfState { public: DcfStateTest (DcfManagerTest *test, uint32_t i); - void QueueTx (uint64_t txTime, uint64_t expectedGrantTime); + void QueueTx (uint64_t txTime, uint64_t expectedGrantTime, uint32_t nBackoffSlots); private: friend class DcfManagerTest; virtual void DoNotifyAccessGranted (void); @@ -38,8 +38,13 @@ private: virtual void DoNotifyCollision (void); virtual void DoNotifyChannelSwitching (void); - typedef std::pair ExpectedGrant; - typedef std::list ExpectedGrants; + struct ExpectedGrant { + uint64_t m_txTime; + uint64_t m_expectedGrantTime; + uint32_t m_nBackoffSlots; + }; + typedef std::list ExpectedGrants; + struct ExpectedCollision { uint64_t at; uint32_t nSlots; @@ -80,14 +85,14 @@ private: void AddNavReset (uint64_t at, uint64_t duration); void AddNavStart (uint64_t at, uint64_t duration); void AddAckTimeoutReset (uint64_t at); - void AddAccessRequest (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t from); - void AddAccessRequestWithAckTimeout (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t from); + void AddAccessRequest (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, + uint32_t nBackoffSlots, uint32_t from); + void AddAccessRequestWithAckTimeout (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, + uint32_t nBackoffSlots, uint32_t from); ///\param ackDelay is delay of the ack after txEnd - void AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from); - void DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, DcfStateTest *state); + void AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, + uint32_t nBackoffSlots, uint32_t ackDelay, uint32_t from); + void DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, uint32_t nBackoffSlots, DcfStateTest *state); void AddCcaBusyEvt (uint64_t at, uint64_t duration); void AddSwitchingEvt (uint64_t at, uint64_t duration); void AddRxStartEvt (uint64_t at, uint64_t duration); @@ -105,9 +110,13 @@ DcfStateTest::DcfStateTest (DcfManagerTe : m_test (test), m_i(i) {} void -DcfStateTest::QueueTx (uint64_t txTime, uint64_t expectedGrantTime) +DcfStateTest::QueueTx (uint64_t txTime, uint64_t expectedGrantTime, uint32_t nBackoffSlots) { - m_expectedGrants.push_back (std::make_pair (txTime, expectedGrantTime)); + struct ExpectedGrant grant; + grant.m_txTime = txTime; + grant.m_expectedGrantTime = expectedGrantTime; + grant.m_nBackoffSlots = nBackoffSlots; + m_expectedGrants.push_back (grant); } void DcfStateTest::DoNotifyAccessGranted (void) @@ -140,11 +149,12 @@ DcfManagerTest::NotifyAccessGranted (uin { DcfStateTest *state = m_dcfStates[i]; NS_TEST_EXPECT_MSG_EQ (state->m_expectedGrants.empty (), false, "Have expected grants"); - std::pair expected = state->m_expectedGrants.front (); + struct DcfStateTest::ExpectedGrant expected = state->m_expectedGrants.front (); state->m_expectedGrants.pop_front (); - NS_TEST_EXPECT_MSG_EQ (Simulator::Now (), MicroSeconds (expected.second), "Expected access grant is now"); - m_dcfManager->NotifyTxStartNow (MicroSeconds (expected.first)); - m_dcfManager->NotifyAckTimeoutStartNow (MicroSeconds (m_ackTimeoutValue + expected.first)); + NS_TEST_EXPECT_MSG_EQ (Simulator::Now (), MicroSeconds (expected.m_expectedGrantTime), "Expected access grant is now"); + m_dcfManager->NotifyTxStartNow (MicroSeconds (expected.m_txTime)); + state->StartBackoffNow (expected.m_nBackoffSlots); + m_dcfManager->NotifyAckTimeoutStartNow (MicroSeconds (m_ackTimeoutValue + expected.m_txTime)); } void DcfManagerTest::AddTxEvt (uint64_t at, uint64_t duration) @@ -179,9 +189,9 @@ DcfManagerTest::NotifyChannelSwitching ( DcfStateTest *state = m_dcfStates[i]; if (!state->m_expectedGrants.empty ()) { - std::pair expected = state->m_expectedGrants.front (); + struct DcfStateTest::ExpectedGrant expected = state->m_expectedGrants.front (); state->m_expectedGrants.pop_front (); - NS_TEST_EXPECT_MSG_EQ (Simulator::Now (), MicroSeconds (expected.second), "Expected grant is now"); + NS_TEST_EXPECT_MSG_EQ (Simulator::Now (), MicroSeconds (expected.m_expectedGrantTime), "Expected grant is now"); } } @@ -287,33 +297,35 @@ DcfManagerTest::AddAckTimeoutReset (uint &DcfManager::NotifyAckTimeoutResetNow, m_dcfManager); } void -DcfManagerTest::AddAccessRequest (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t from) +DcfManagerTest::AddAccessRequest (uint64_t at, uint64_t txTime, + uint64_t expectedGrantTime, uint32_t nBackoffSlots, + uint32_t from) { - AddAccessRequestWithSuccessfullAck (at, txTime, expectedGrantTime, 0, from); + AddAccessRequestWithSuccessfullAck (at, txTime, expectedGrantTime, 0, nBackoffSlots, from); } void -DcfManagerTest::AddAccessRequestWithAckTimeout (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t from) +DcfManagerTest::AddAccessRequestWithAckTimeout (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, + uint32_t nBackoffSlots, uint32_t from) { Simulator::Schedule (MicroSeconds (at) - Now (), &DcfManagerTest::DoAccessRequest, this, - txTime, expectedGrantTime, m_dcfStates[from]); + txTime, expectedGrantTime, nBackoffSlots, m_dcfStates[from]); } void -DcfManagerTest::AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime, - uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from) +DcfManagerTest::AddAccessRequestWithSuccessfullAck (uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, + uint32_t ackDelay, uint32_t nBackoffSlots, uint32_t from) { NS_ASSERT(ackDelay < m_ackTimeoutValue); Simulator::Schedule (MicroSeconds (at) - Now (), &DcfManagerTest::DoAccessRequest, this, - txTime, expectedGrantTime, m_dcfStates[from]); + txTime, expectedGrantTime, nBackoffSlots, m_dcfStates[from]); AddAckTimeoutReset (expectedGrantTime + txTime + ackDelay); } void -DcfManagerTest::DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, DcfStateTest *state) +DcfManagerTest::DoAccessRequest (uint64_t txTime, uint64_t expectedGrantTime, uint32_t nBackoffSlots, + DcfStateTest *state) { - state->QueueTx (txTime, expectedGrantTime); + state->QueueTx (txTime, expectedGrantTime, nBackoffSlots); m_dcfManager->RequestAccess (state); } void @@ -348,8 +360,8 @@ DcfManagerTest::DoRun (void) // StartTest (1, 3, 10); AddDcfState (1); - AddAccessRequest (1, 1, 4, 0); - AddAccessRequest (10, 2, 10, 0); + AddAccessRequest (1, 1, 4, 1, 0); + AddAccessRequest (10, 2, 10, 0, 0); EndTest (); // Check that receiving inside SIFS shall be cancelled properly: // 0 3 4 5 8 9 12 13 14 @@ -357,10 +369,10 @@ DcfManagerTest::DoRun (void) // StartTest (1, 3, 10); AddDcfState (1); - AddAccessRequest (1, 1, 4, 0); + AddAccessRequest (1, 1, 4, 1, 0); AddRxInsideSifsEvt (6, 10); AddTxEvt(8, 1); - AddAccessRequest (14, 2, 14, 0); + AddAccessRequest (14, 2, 14, 0, 0); EndTest (); @@ -377,7 +389,7 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddRxOkEvt (20, 40); AddRxOkEvt (80, 20); - AddAccessRequest (30, 2, 118, 0); + AddAccessRequest (30, 2, 118, 4, 0); ExpectCollision (30, 4, 0); // backoff: 4 slots EndTest (); @@ -390,9 +402,10 @@ DcfManagerTest::DoRun (void) StartTest (4, 6 , 10); AddDcfState (1); AddRxOkEvt (20, 40); - AddAccessRequest (30, 2, 70, 0); + AddAccessRequest (30, 2, 70, 0, 0); ExpectCollision (30, 0, 0); // backoff: 0 slots EndTest (); + // Test shows when two frames are received without interval between // them: // 20 60 100 106 110 112 @@ -404,11 +417,37 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddRxOkEvt (20, 40); AddRxOkEvt (60, 40); - AddAccessRequest (30, 2, 110, 0); + AddAccessRequest (30, 2, 110, 0, 0); ExpectCollision (30, 0, 0); // backoff: 0 slots EndTest (); + // Test case where two packets are queued at DcaTxop, the first send starts + // immediately and the second is also immediately indicated but has to wait + // for its backoff. + // + // 20 60 66 70 80 + // | tx | sifs | aifs | tx | + // |20: request access for both packets + StartTest (4, 6 , 10); + AddDcfState (1); + AddAccessRequest (20, 40, 20, 0, 0); + AddAccessRequest (20, 10, 70, 0, 0); + EndTest (); + + // Test case where two packets are queued at DcaTxop, the first send starts + // immediately and the second is also immediately indicated but has to wait + // for its backoff. + // + // 20 60 66 70 78 88 + // | tx | sifs | aifs | backoff | tx | + // |20: request access for both packets + StartTest (4, 6 , 10); + AddDcfState (1); + AddAccessRequest (20, 40, 20, 2, 0); + AddAccessRequest (20, 10, 78, 0, 0); + EndTest (); + // The test below is subject to some discussion because I am // not sure I understand the intent of the spec here. // i.e., what happens if you make a request to get access @@ -425,7 +464,7 @@ DcfManagerTest::DoRun (void) StartTest (4, 6 , 10); AddDcfState (1); AddRxOkEvt (20, 40); - AddAccessRequest (62, 2, 70, 0); + AddAccessRequest (62, 2, 70, 0, 0); EndTest (); @@ -438,7 +477,7 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (1); AddRxErrorEvt (20, 40); - AddAccessRequest (30, 2, 96, 0); + AddAccessRequest (30, 2, 96, 4, 0); ExpectCollision (30, 4, 0); // backoff: 4 slots EndTest (); @@ -451,7 +490,7 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (1); AddRxErrorEvt (20, 40); - AddAccessRequest (30, 2, 101, 0); + AddAccessRequest (30, 2, 101, 4, 0); ExpectCollision (30, 4, 0); // backoff: 4 slots AddRxOkEvt (69, 6); EndTest (); @@ -468,10 +507,10 @@ DcfManagerTest::DoRun (void) AddDcfState (1); // high priority DCF AddDcfState (3); // low priority DCF AddRxOkEvt (20, 40); - AddAccessRequest (30, 10, 78, 0); + AddAccessRequest (30, 10, 78, 2, 0); ExpectCollision (30, 2, 0); // backoff: 2 slot - AddAccessRequest (40, 2, 110, 1); + AddAccessRequest (40, 2, 110, 0, 1); ExpectCollision (40, 0, 1); // backoff: 0 slot ExpectInternalCollision (78, 1, 1); // backoff: 1 slot EndTest (); @@ -486,8 +525,8 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (2); // high priority DCF AddDcfState (0); // low priority DCF - AddAccessRequestWithAckTimeout (20, 20, 20, 0); - AddAccessRequest (50, 10, 66, 1); + AddAccessRequestWithAckTimeout (20, 20, 20, 0, 0); + AddAccessRequest (50, 10, 66, 0, 1); EndTest (); // Test of AckTimeout handling: @@ -502,8 +541,8 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (2); // high priority DCF AddDcfState (0); // low priority DCF - AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 0); - AddAccessRequest (41, 10, 48, 1); + AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 0, 0); + AddAccessRequest (41, 10, 48, 0, 1); EndTest (); //Repeat the same but with one queue: @@ -512,8 +551,8 @@ DcfManagerTest::DoRun (void) // ^ request access StartTest (4, 6, 10); AddDcfState (2); - AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 0); - AddAccessRequest (41, 10, 56, 0); + AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 0, 0); + AddAccessRequest (41, 10, 56, 0, 0); EndTest (); //Repeat the same when ack was delayed: @@ -523,9 +562,10 @@ DcfManagerTest::DoRun (void) // ^ request access StartTest (4, 6, 10); AddDcfState (2); - AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 0); - AddAccessRequest (39, 10, 64, 0); - ExpectCollision (39, 2, 0); // backoff: 2 slot + AddAccessRequestWithSuccessfullAck (20, 20, 20, 2, 2, 0); + AddAccessRequest (39, 10, 64, 0, 0); + // this situation is not supposed to fire an internal or external collison. + // ExpectCollision (39, 2, 0); // backoff: 2 slot EndTest (); // @@ -539,7 +579,7 @@ DcfManagerTest::DoRun (void) AddNavStart (60, 15); AddRxOkEvt (66, 5); AddNavStart (71, 0); - AddAccessRequest (30, 10, 93, 0); + AddAccessRequest (30, 10, 93, 0, 0); ExpectCollision (30, 2, 0); // backoff: 2 slot EndTest (); @@ -554,7 +594,7 @@ DcfManagerTest::DoRun (void) AddNavStart (60, 15); AddRxOkEvt (66, 5); AddNavReset (71, 2); - AddAccessRequest (30, 10, 91, 0); + AddAccessRequest (30, 10, 91, 0, 0); ExpectCollision (30, 2, 0); // backoff: 2 slot EndTest (); @@ -562,7 +602,7 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (2); AddRxOkEvt (20, 40); - AddAccessRequest (80, 10, 80, 0); + AddAccessRequest (80, 10, 80, 0, 0); EndTest (); @@ -570,7 +610,7 @@ DcfManagerTest::DoRun (void) AddDcfState (2); AddRxOkEvt (20, 40); AddRxOkEvt (78, 8); - AddAccessRequest (30, 50, 108, 0); + AddAccessRequest (30, 50, 108, 0, 0); ExpectCollision (30, 3, 0); // backoff: 3 slots EndTest (); @@ -584,7 +624,7 @@ DcfManagerTest::DoRun (void) StartTest (1, 3, 10); AddDcfState (1); AddSwitchingEvt(0,20); - AddAccessRequest (21, 1, 24, 0); + AddAccessRequest (21, 1, 24, 0, 0); EndTest (); // 20 40 50 53 54 55 @@ -596,7 +636,7 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddSwitchingEvt(20,20); AddCcaBusyEvt(30,20); - AddAccessRequest (45, 1, 54, 0); + AddAccessRequest (45, 1, 54, 0, 0); EndTest (); // 20 30 50 53 54 55 @@ -608,7 +648,7 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddRxStartEvt (20,40); AddSwitchingEvt(30,20); - AddAccessRequest (51, 1, 54, 0); + AddAccessRequest (51, 1, 54, 0, 0); EndTest (); // 20 30 50 53 54 55 @@ -620,7 +660,7 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddCcaBusyEvt (20,40); AddSwitchingEvt(30,20); - AddAccessRequest (51, 1, 54, 0); + AddAccessRequest (51, 1, 54, 0, 0); EndTest (); // 20 30 50 53 54 55 @@ -632,7 +672,7 @@ DcfManagerTest::DoRun (void) AddDcfState (1); AddNavStart (20,40); AddSwitchingEvt(30,20); - AddAccessRequest (51, 1, 54, 0); + AddAccessRequest (51, 1, 54, 0, 0); EndTest (); // 20 40 50 55 58 59 60 @@ -642,10 +682,10 @@ DcfManagerTest::DoRun (void) // StartTest (1, 3, 10); AddDcfState (1); - AddAccessRequestWithAckTimeout (20, 20, 20, 0); - AddAccessRequest (45, 1, 50, 0); + AddAccessRequestWithAckTimeout (20, 20, 20, 0, 0); + AddAccessRequest (45, 1, 50, 0, 0); AddSwitchingEvt(50,5); - AddAccessRequest (56, 1, 59, 0); + AddAccessRequest (56, 1, 59, 0, 0); EndTest (); // 20 60 66 70 74 78 80 100 106 110 112 @@ -656,12 +696,12 @@ DcfManagerTest::DoRun (void) StartTest (4, 6, 10); AddDcfState (1); AddRxOkEvt(20,40); - AddAccessRequest (30, 2, 80, 0); + AddAccessRequest (30, 2, 80, 4, 0); ExpectCollision(30, 4, 0); // backoff: 4 slots AddSwitchingEvt(80,20); - AddAccessRequest (101, 2, 110, 0); + AddAccessRequest (101, 2, 110, 0, 0); EndTest (); - + return GetErrorStatus (); } --- a/src/devices/wifi/dcf-manager.cc Mon Nov 23 13:52:51 2009 +0100 +++ a/src/devices/wifi/dcf-manager.cc Mon Nov 23 18:16:11 2009 +0100 @@ -42,6 +42,7 @@ namespace ns3 { DcfState::DcfState () : m_backoffSlots (0), m_backoffStart (Seconds (0.0)), + m_backoffElapsed (true), m_cwMin (0), m_cwMax (0), m_cw (0), @@ -101,6 +102,10 @@ DcfState::UpdateBackoffSlotsNow (uint32_ m_backoffSlots -= nSlots; m_backoffStart = backoffUpdateBound; MY_DEBUG ("update slots="<GetBackoffSlots () == 0 && - IsBusy ()) + if (state->IsBackoffElapsed() && IsBusy ()) { MY_DEBUG ("medium is busy: collision"); /* someone else has accessed the medium. --- a/src/devices/wifi/dcf-manager.h Mon Nov 23 13:52:51 2009 +0100 +++ a/src/devices/wifi/dcf-manager.h Mon Nov 23 18:16:11 2009 +0100 @@ -80,6 +80,10 @@ public: */ void StartBackoffNow (uint32_t nSlots); /** + * Returns true if the backoff procedure elapsed. + */ + bool IsBackoffElapsed (void) const; + /** * \returns the current value of the CW variable. The initial value is * minCW. */ @@ -146,6 +150,7 @@ private: // time at which a backoff was started or the time at which // the backoff counter was last updated. Time m_backoffStart; + bool m_backoffElapsed; uint32_t m_cwMin; uint32_t m_cwMax; uint32_t m_cw;