1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3
* Copyright (c) 2005,2006 INRIA
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation;
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
21
#include "ns3/assert.h"
23
#include "ns3/simulator.h"
26
#include "dcf-manager.h"
31
NS_LOG_COMPONENT_DEFINE ("DcfManager");
34
NS_LOG_DEBUG (Simulator::Now () << " " << this << " " << x)
38
/****************************************************************
39
* Implement the DCF state holder
40
****************************************************************/
44
m_backoffStart (Seconds (0.0)),
48
m_accessRequested (false)
52
DcfState::~DcfState ()
57
DcfState::SetAifsn (uint32_t aifsn)
62
DcfState::SetCwMin (uint32_t minCw)
68
DcfState::SetCwMax (uint32_t maxCw)
74
DcfState::GetAifsn (void) const
79
DcfState::GetCwMin (void) const
84
DcfState::GetCwMax (void) const
90
DcfState::ResetCw (void)
95
DcfState::UpdateFailedCw (void)
97
// see 802.11-2007, section 9.9.1.5
98
m_cw = std::min ( 2 * (m_cw + 1) - 1, m_cwMax);
101
DcfState::UpdateBackoffSlotsNow (uint32_t nSlots, Time backoffUpdateBound)
103
m_backoffSlots -= nSlots;
104
m_backoffStart = backoffUpdateBound;
105
MY_DEBUG ("update slots=" << nSlots << " slots, backoff=" << m_backoffSlots);
109
DcfState::StartBackoffNow (uint32_t nSlots)
111
NS_ASSERT (m_backoffSlots == 0);
112
MY_DEBUG ("start backoff=" << nSlots << " slots");
113
m_backoffSlots = nSlots;
114
m_backoffStart = Simulator::Now ();
118
DcfState::GetCw (void) const
123
DcfState::GetBackoffSlots (void) const
125
return m_backoffSlots;
128
DcfState::GetBackoffStart (void) const
130
return m_backoffStart;
133
DcfState::IsAccessRequested (void) const
135
return m_accessRequested;
138
DcfState::NotifyAccessRequested (void)
140
m_accessRequested = true;
143
DcfState::NotifyAccessGranted (void)
145
NS_ASSERT (m_accessRequested);
146
m_accessRequested = false;
147
DoNotifyAccessGranted ();
150
DcfState::NotifyCollision (void)
152
DoNotifyCollision ();
155
DcfState::NotifyInternalCollision (void)
157
DoNotifyInternalCollision ();
160
DcfState::NotifyChannelSwitching (void)
162
DoNotifyChannelSwitching ();
166
/***************************************************************
167
* Listener for Nav events. Forwards to DcfManager
168
***************************************************************/
170
class LowDcfListener : public ns3::MacLowDcfListener
173
LowDcfListener (ns3::DcfManager *dcf)
177
virtual ~LowDcfListener ()
180
virtual void NavStart (Time duration)
182
m_dcf->NotifyNavStartNow (duration);
184
virtual void NavReset (Time duration)
186
m_dcf->NotifyNavResetNow (duration);
188
virtual void AckTimeoutStart (Time duration)
190
m_dcf->NotifyAckTimeoutStartNow (duration);
192
virtual void AckTimeoutReset ()
194
m_dcf->NotifyAckTimeoutResetNow ();
196
virtual void CtsTimeoutStart (Time duration)
198
m_dcf->NotifyCtsTimeoutStartNow (duration);
200
virtual void CtsTimeoutReset ()
202
m_dcf->NotifyCtsTimeoutResetNow ();
205
ns3::DcfManager *m_dcf;
208
/***************************************************************
209
* Listener for PHY events. Forwards to DcfManager
210
***************************************************************/
212
class PhyListener : public ns3::WifiPhyListener
215
PhyListener (ns3::DcfManager *dcf)
219
virtual ~PhyListener ()
222
virtual void NotifyRxStart (Time duration)
224
m_dcf->NotifyRxStartNow (duration);
226
virtual void NotifyRxEndOk (void)
228
m_dcf->NotifyRxEndOkNow ();
230
virtual void NotifyRxEndError (void)
232
m_dcf->NotifyRxEndErrorNow ();
234
virtual void NotifyTxStart (Time duration)
236
m_dcf->NotifyTxStartNow (duration);
238
virtual void NotifyMaybeCcaBusyStart (Time duration)
240
m_dcf->NotifyMaybeCcaBusyStartNow (duration);
242
virtual void NotifySwitchingStart (Time duration)
244
m_dcf->NotifySwitchingStartNow (duration);
247
ns3::DcfManager *m_dcf;
250
/****************************************************************
251
* Implement the DCF manager of all DCF state holders
252
****************************************************************/
254
DcfManager::DcfManager ()
255
: m_lastAckTimeoutEnd (MicroSeconds (0)),
256
m_lastCtsTimeoutEnd (MicroSeconds (0)),
257
m_lastNavStart (MicroSeconds (0)),
258
m_lastNavDuration (MicroSeconds (0)),
259
m_lastRxStart (MicroSeconds (0)),
260
m_lastRxDuration (MicroSeconds (0)),
261
m_lastRxReceivedOk (true),
262
m_lastRxEnd (MicroSeconds (0)),
263
m_lastTxStart (MicroSeconds (0)),
264
m_lastTxDuration (MicroSeconds (0)),
265
m_lastBusyStart (MicroSeconds (0)),
266
m_lastBusyDuration (MicroSeconds (0)),
267
m_lastSwitchingStart (MicroSeconds (0)),
268
m_lastSwitchingDuration (MicroSeconds (0)),
271
m_sifs (Seconds (0.0)),
277
DcfManager::~DcfManager ()
279
delete m_phyListener;
280
delete m_lowListener;
286
DcfManager::SetupPhyListener (Ptr<WifiPhy> phy)
288
m_phyListener = new PhyListener (this);
289
phy->RegisterListener (m_phyListener);
292
DcfManager::SetupLowListener (Ptr<MacLow> low)
294
m_lowListener = new LowDcfListener (this);
295
low->RegisterDcfListener (m_lowListener);
299
DcfManager::SetSlot (Time slotTime)
301
m_slotTimeUs = slotTime.GetMicroSeconds ();
304
DcfManager::SetSifs (Time sifs)
309
DcfManager::SetEifsNoDifs (Time eifsNoDifs)
311
m_eifsNoDifs = eifsNoDifs;
314
DcfManager::GetEifsNoDifs () const
320
DcfManager::Add (DcfState *dcf)
322
m_states.push_back (dcf);
326
DcfManager::MostRecent (Time a, Time b) const
331
DcfManager::MostRecent (Time a, Time b, Time c) const
335
retval = Max (retval, c);
339
DcfManager::MostRecent (Time a, Time b, Time c, Time d) const
343
Time retval = Max (e, f);
347
DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f) const
353
Time retval = Max (k, i);
358
DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const
365
Time retval = Max (k, l);
370
DcfManager::IsBusy (void) const
377
Time lastTxEnd = m_lastTxStart + m_lastTxDuration;
378
if (lastTxEnd > Simulator::Now ())
383
Time lastNavEnd = m_lastNavStart + m_lastNavDuration;
384
if (lastNavEnd > Simulator::Now ())
393
DcfManager::RequestAccess (DcfState *state)
396
NS_ASSERT (!state->IsAccessRequested ());
397
state->NotifyAccessRequested ();
399
* If there is a collision, generate a backoff
400
* by notifying the collision to the user.
402
if (state->GetBackoffSlots () == 0
405
MY_DEBUG ("medium is busy: collision");
406
/* someone else has accessed the medium.
407
* generate a backoff.
409
state->NotifyCollision ();
412
DoRestartAccessTimeoutIfNeeded ();
416
DcfManager::DoGrantAccess (void)
419
for (States::const_iterator i = m_states.begin (); i != m_states.end (); k++)
421
DcfState *state = *i;
422
if (state->IsAccessRequested ()
423
&& GetBackoffEndFor (state) <= Simulator::Now () )
426
* This is the first dcf we find with an expired backoff and which
427
* needs access to the medium. i.e., it has data to send.
429
MY_DEBUG ("dcf " << k << " needs access. backoff expired. access granted. slots=" << state->GetBackoffSlots ());
430
i++; // go to the next item in the list.
432
std::vector<DcfState *> internalCollisionStates;
433
for (States::const_iterator j = i; j != m_states.end (); j++, k++)
435
DcfState *otherState = *j;
436
if (otherState->IsAccessRequested ()
437
&& GetBackoffEndFor (otherState) <= Simulator::Now ())
439
MY_DEBUG ("dcf " << k << " needs access. backoff expired. internal collision. slots=" <<
440
otherState->GetBackoffSlots ());
442
* all other dcfs with a lower priority whose backoff
443
* has expired and which needed access to the medium
444
* must be notified that we did get an internal collision.
446
internalCollisionStates.push_back (otherState);
451
* Now, we notify all of these changes in one go. It is necessary to
452
* perform first the calculations of which states are colliding and then
453
* only apply the changes because applying the changes through notification
454
* could change the global state of the manager, and, thus, could change
455
* the result of the calculations.
457
state->NotifyAccessGranted ();
458
for (std::vector<DcfState *>::const_iterator k = internalCollisionStates.begin ();
459
k != internalCollisionStates.end (); k++)
461
(*k)->NotifyInternalCollision ();
470
DcfManager::AccessTimeout (void)
474
DoRestartAccessTimeoutIfNeeded ();
478
DcfManager::GetAccessGrantStart (void) const
483
rxAccessStart = m_lastRxEnd + m_sifs;
484
if (!m_lastRxReceivedOk)
486
rxAccessStart += m_eifsNoDifs;
491
rxAccessStart = m_lastRxStart + m_lastRxDuration + m_sifs;
493
Time busyAccessStart = m_lastBusyStart + m_lastBusyDuration + m_sifs;
494
Time txAccessStart = m_lastTxStart + m_lastTxDuration + m_sifs;
495
Time navAccessStart = m_lastNavStart + m_lastNavDuration + m_sifs;
496
Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + m_sifs;
497
Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + m_sifs;
498
Time switchingAccessStart = m_lastSwitchingStart + m_lastSwitchingDuration + m_sifs;
499
Time accessGrantedStart = MostRecent (rxAccessStart,
503
ackTimeoutAccessStart,
504
ctsTimeoutAccessStart,
507
NS_LOG_INFO ("access grant start=" << accessGrantedStart <<
508
", rx access start=" << rxAccessStart <<
509
", busy access start=" << busyAccessStart <<
510
", tx access start=" << txAccessStart <<
511
", nav access start=" << navAccessStart);
512
return accessGrantedStart;
516
DcfManager::GetBackoffStartFor (DcfState *state)
518
Time mostRecentEvent = MostRecent (state->GetBackoffStart (),
519
GetAccessGrantStart () + MicroSeconds (state->GetAifsn () * m_slotTimeUs));
521
return mostRecentEvent;
525
DcfManager::GetBackoffEndFor (DcfState *state)
527
return GetBackoffStartFor (state) + MicroSeconds (state->GetBackoffSlots () * m_slotTimeUs);
531
DcfManager::UpdateBackoff (void)
534
for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++, k++)
536
DcfState *state = *i;
538
Time backoffStart = GetBackoffStartFor (state);
539
if (backoffStart <= Simulator::Now ())
541
uint32_t nus = (Simulator::Now () - backoffStart).GetMicroSeconds ();
542
uint32_t nIntSlots = nus / m_slotTimeUs;
543
uint32_t n = std::min (nIntSlots, state->GetBackoffSlots ());
544
MY_DEBUG ("dcf " << k << " dec backoff slots=" << n);
545
Time backoffUpdateBound = backoffStart + MicroSeconds (n * m_slotTimeUs);
546
state->UpdateBackoffSlotsNow (n, backoffUpdateBound);
552
DcfManager::DoRestartAccessTimeoutIfNeeded (void)
555
* Is there a DcfState which needs to access the medium, and,
556
* if there is one, how many slots for AIFS+backoff does it require ?
558
bool accessTimeoutNeeded = false;
559
Time expectedBackoffEnd = Simulator::GetMaximumSimulationTime ();
560
for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++)
562
DcfState *state = *i;
563
if (state->IsAccessRequested ())
565
Time tmp = GetBackoffEndFor (state);
566
if (tmp > Simulator::Now ())
568
accessTimeoutNeeded = true;
569
expectedBackoffEnd = std::min (expectedBackoffEnd, tmp);
573
if (accessTimeoutNeeded)
575
MY_DEBUG ("expected backoff end=" << expectedBackoffEnd);
576
Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now ();
577
if (m_accessTimeout.IsRunning ()
578
&& Simulator::GetDelayLeft (m_accessTimeout) > expectedBackoffDelay)
580
m_accessTimeout.Cancel ();
582
if (m_accessTimeout.IsExpired ())
584
m_accessTimeout = Simulator::Schedule (expectedBackoffDelay,
585
&DcfManager::AccessTimeout, this);
591
DcfManager::NotifyRxStartNow (Time duration)
593
MY_DEBUG ("rx start for=" << duration);
595
m_lastRxStart = Simulator::Now ();
596
m_lastRxDuration = duration;
600
DcfManager::NotifyRxEndOkNow (void)
602
MY_DEBUG ("rx end ok");
603
m_lastRxEnd = Simulator::Now ();
604
m_lastRxReceivedOk = true;
608
DcfManager::NotifyRxEndErrorNow (void)
610
MY_DEBUG ("rx end error");
611
m_lastRxEnd = Simulator::Now ();
612
m_lastRxReceivedOk = false;
616
DcfManager::NotifyTxStartNow (Time duration)
620
//this may be caused only if PHY has started to receive a packet
621
//inside SIFS, so, we check that lastRxStart was maximum a SIFS
623
NS_ASSERT (Simulator::Now () - m_lastRxStart <= m_sifs);
624
m_lastRxEnd = Simulator::Now ();
625
m_lastRxDuration = m_lastRxEnd - m_lastRxStart;
626
m_lastRxReceivedOk = true;
629
MY_DEBUG ("tx start for " << duration);
631
m_lastTxStart = Simulator::Now ();
632
m_lastTxDuration = duration;
635
DcfManager::NotifyMaybeCcaBusyStartNow (Time duration)
637
MY_DEBUG ("busy start for " << duration);
639
m_lastBusyStart = Simulator::Now ();
640
m_lastBusyDuration = duration;
645
DcfManager::NotifySwitchingStartNow (Time duration)
647
Time now = Simulator::Now ();
648
NS_ASSERT (m_lastTxStart + m_lastTxDuration <= now);
649
NS_ASSERT (m_lastSwitchingStart + m_lastSwitchingDuration <= now);
653
// channel switching during packet reception
654
m_lastRxEnd = Simulator::Now ();
655
m_lastRxDuration = m_lastRxEnd - m_lastRxStart;
656
m_lastRxReceivedOk = true;
659
if (m_lastNavStart + m_lastNavDuration > now)
661
m_lastNavDuration = now - m_lastNavStart;
663
if (m_lastBusyStart + m_lastBusyDuration > now)
665
m_lastBusyDuration = now - m_lastBusyStart;
667
if (m_lastAckTimeoutEnd > now)
669
m_lastAckTimeoutEnd = now;
671
if (m_lastCtsTimeoutEnd > now)
673
m_lastCtsTimeoutEnd = now;
677
if (m_accessTimeout.IsRunning ())
679
m_accessTimeout.Cancel ();
683
for (States::iterator i = m_states.begin (); i != m_states.end (); i++)
685
DcfState *state = *i;
686
uint32_t remainingSlots = state->GetBackoffSlots ();
687
if (remainingSlots > 0)
689
state->UpdateBackoffSlotsNow (remainingSlots, now);
690
NS_ASSERT (state->GetBackoffSlots () == 0);
693
state->m_accessRequested = false;
694
state->NotifyChannelSwitching ();
697
MY_DEBUG ("switching start for " << duration);
698
m_lastSwitchingStart = Simulator::Now ();
699
m_lastSwitchingDuration = duration;
704
DcfManager::NotifyNavResetNow (Time duration)
706
MY_DEBUG ("nav reset for=" << duration);
708
m_lastNavStart = Simulator::Now ();
709
m_lastNavDuration = duration;
712
* If the nav reset indicates an end-of-nav which is earlier
713
* than the previous end-of-nav, the expected end of backoff
714
* might be later than previously thought so, we might need
715
* to restart a new access timeout.
717
DoRestartAccessTimeoutIfNeeded ();
720
DcfManager::NotifyNavStartNow (Time duration)
722
NS_ASSERT (m_lastNavStart < Simulator::Now ());
723
MY_DEBUG ("nav start for=" << duration);
725
Time newNavEnd = Simulator::Now () + duration;
726
Time lastNavEnd = m_lastNavStart + m_lastNavDuration;
727
if (newNavEnd > lastNavEnd)
729
m_lastNavStart = Simulator::Now ();
730
m_lastNavDuration = duration;
734
DcfManager::NotifyAckTimeoutStartNow (Time duration)
736
NS_ASSERT (m_lastAckTimeoutEnd < Simulator::Now ());
737
m_lastAckTimeoutEnd = Simulator::Now () + duration;
740
DcfManager::NotifyAckTimeoutResetNow ()
742
m_lastAckTimeoutEnd = Simulator::Now ();
743
DoRestartAccessTimeoutIfNeeded ();
746
DcfManager::NotifyCtsTimeoutStartNow (Time duration)
748
m_lastCtsTimeoutEnd = Simulator::Now () + duration;
751
DcfManager::NotifyCtsTimeoutResetNow ()
753
m_lastCtsTimeoutEnd = Simulator::Now ();
754
DoRestartAccessTimeoutIfNeeded ();