A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
dcf-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2006 INRIA
4  *
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;
8  *
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.
13  *
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
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "ns3/assert.h"
22 #include "ns3/log.h"
23 #include "ns3/simulator.h"
24 #include <cmath>
25 
26 #include "dcf-manager.h"
27 #include "wifi-phy.h"
28 #include "wifi-mac.h"
29 #include "mac-low.h"
30 
31 NS_LOG_COMPONENT_DEFINE ("DcfManager");
32 
33 #define MY_DEBUG(x) \
34  NS_LOG_DEBUG (Simulator::Now () << " " << this << " " << x)
35 
36 namespace ns3 {
37 
38 /****************************************************************
39  * Implement the DCF state holder
40  ****************************************************************/
41 
43  : m_backoffSlots (0),
44  m_backoffStart (Seconds (0.0)),
45  m_cwMin (0),
46  m_cwMax (0),
47  m_cw (0),
48  m_accessRequested (false)
49 {
50 }
51 
53 {
54 }
55 
56 void
57 DcfState::SetAifsn (uint32_t aifsn)
58 {
59  m_aifsn = aifsn;
60 }
61 void
62 DcfState::SetCwMin (uint32_t minCw)
63 {
64  m_cwMin = minCw;
65  ResetCw ();
66 }
67 void
68 DcfState::SetCwMax (uint32_t maxCw)
69 {
70  m_cwMax = maxCw;
71  ResetCw ();
72 }
73 uint32_t
74 DcfState::GetAifsn (void) const
75 {
76  return m_aifsn;
77 }
78 uint32_t
79 DcfState::GetCwMin (void) const
80 {
81  return m_cwMin;
82 }
83 uint32_t
84 DcfState::GetCwMax (void) const
85 {
86  return m_cwMax;
87 }
88 
89 void
91 {
92  m_cw = m_cwMin;
93 }
94 void
96 {
97  // see 802.11-2007, section 9.9.1.5
98  m_cw = std::min ( 2 * (m_cw + 1) - 1, m_cwMax);
99 }
100 void
101 DcfState::UpdateBackoffSlotsNow (uint32_t nSlots, Time backoffUpdateBound)
102 {
103  m_backoffSlots -= nSlots;
104  m_backoffStart = backoffUpdateBound;
105  MY_DEBUG ("update slots=" << nSlots << " slots, backoff=" << m_backoffSlots);
106 }
107 
108 void
109 DcfState::StartBackoffNow (uint32_t nSlots)
110 {
111  NS_ASSERT (m_backoffSlots == 0);
112  MY_DEBUG ("start backoff=" << nSlots << " slots");
113  m_backoffSlots = nSlots;
115 }
116 
117 uint32_t
118 DcfState::GetCw (void) const
119 {
120  return m_cw;
121 }
122 uint32_t
124 {
125  return m_backoffSlots;
126 }
127 Time
129 {
130  return m_backoffStart;
131 }
132 bool
134 {
135  return m_accessRequested;
136 }
137 void
139 {
140  m_accessRequested = true;
141 }
142 void
144 {
146  m_accessRequested = false;
148 }
149 void
151 {
153 }
154 void
156 {
158 }
159 void
161 {
163 }
164 
165 
166 /***************************************************************
167  * Listener for Nav events. Forwards to DcfManager
168  ***************************************************************/
169 
171 {
172 public:
174  : m_dcf (dcf)
175  {
176  }
177  virtual ~LowDcfListener ()
178  {
179  }
180  virtual void NavStart (Time duration)
181  {
182  m_dcf->NotifyNavStartNow (duration);
183  }
184  virtual void NavReset (Time duration)
185  {
186  m_dcf->NotifyNavResetNow (duration);
187  }
188  virtual void AckTimeoutStart (Time duration)
189  {
190  m_dcf->NotifyAckTimeoutStartNow (duration);
191  }
192  virtual void AckTimeoutReset ()
193  {
195  }
196  virtual void CtsTimeoutStart (Time duration)
197  {
198  m_dcf->NotifyCtsTimeoutStartNow (duration);
199  }
200  virtual void CtsTimeoutReset ()
201  {
203  }
204 private:
206 };
207 
208 /***************************************************************
209  * Listener for PHY events. Forwards to DcfManager
210  ***************************************************************/
211 
213 {
214 public:
216  : m_dcf (dcf)
217  {
218  }
219  virtual ~PhyListener ()
220  {
221  }
222  virtual void NotifyRxStart (Time duration)
223  {
224  m_dcf->NotifyRxStartNow (duration);
225  }
226  virtual void NotifyRxEndOk (void)
227  {
229  }
230  virtual void NotifyRxEndError (void)
231  {
233  }
234  virtual void NotifyTxStart (Time duration)
235  {
236  m_dcf->NotifyTxStartNow (duration);
237  }
238  virtual void NotifyMaybeCcaBusyStart (Time duration)
239  {
240  m_dcf->NotifyMaybeCcaBusyStartNow (duration);
241  }
242  virtual void NotifySwitchingStart (Time duration)
243  {
244  m_dcf->NotifySwitchingStartNow (duration);
245  }
246 private:
248 };
249 
250 /****************************************************************
251  * Implement the DCF manager of all DCF state holders
252  ****************************************************************/
253 
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)),
269  m_rxing (false),
270  m_slotTimeUs (0),
271  m_sifs (Seconds (0.0)),
272  m_phyListener (0),
273  m_lowListener (0)
274 {
275 }
276 
278 {
279  delete m_phyListener;
280  delete m_lowListener;
281  m_phyListener = 0;
282  m_lowListener = 0;
283 }
284 
285 void
287 {
288  m_phyListener = new PhyListener (this);
290 }
291 void
293 {
294  m_lowListener = new LowDcfListener (this);
296 }
297 
298 void
300 {
301  m_slotTimeUs = slotTime.GetMicroSeconds ();
302 }
303 void
305 {
306  m_sifs = sifs;
307 }
308 void
310 {
311  m_eifsNoDifs = eifsNoDifs;
312 }
313 Time
315 {
316  return m_eifsNoDifs;
317 }
318 
319 void
321 {
322  m_states.push_back (dcf);
323 }
324 
325 Time
327 {
328  return Max (a, b);
329 }
330 Time
332 {
333  Time retval;
334  retval = Max (a, b);
335  retval = Max (retval, c);
336  return retval;
337 }
338 Time
340 {
341  Time e = Max (a, b);
342  Time f = Max (c, d);
343  Time retval = Max (e, f);
344  return retval;
345 }
346 Time
348 {
349  Time g = Max (a, b);
350  Time h = Max (c, d);
351  Time i = Max (e, f);
352  Time k = Max (g, h);
353  Time retval = Max (k, i);
354  return retval;
355 }
356 
357 Time
358 DcfManager::MostRecent (Time a, Time b, Time c, Time d, Time e, Time f, Time g) const
359 {
360  Time h = Max (a, b);
361  Time i = Max (c, d);
362  Time j = Max (e, f);
363  Time k = Max (h, i);
364  Time l = Max (j, g);
365  Time retval = Max (k, l);
366  return retval;
367 }
368 
369 bool
370 DcfManager::IsBusy (void) const
371 {
372  // PHY busy
373  if (m_rxing)
374  {
375  return true;
376  }
377  Time lastTxEnd = m_lastTxStart + m_lastTxDuration;
378  if (lastTxEnd > Simulator::Now ())
379  {
380  return true;
381  }
382  // NAV busy
383  Time lastNavEnd = m_lastNavStart + m_lastNavDuration;
384  if (lastNavEnd > Simulator::Now ())
385  {
386  return true;
387  }
388  return false;
389 }
390 
391 
392 void
394 {
395  UpdateBackoff ();
396  NS_ASSERT (!state->IsAccessRequested ());
397  state->NotifyAccessRequested ();
402  if (state->GetBackoffSlots () == 0
403  && IsBusy ())
404  {
405  MY_DEBUG ("medium is busy: collision");
406  /* someone else has accessed the medium.
407  * generate a backoff.
408  */
409  state->NotifyCollision ();
410  }
411  DoGrantAccess ();
413 }
414 
415 void
417 {
418  uint32_t k = 0;
419  for (States::const_iterator i = m_states.begin (); i != m_states.end (); k++)
420  {
421  DcfState *state = *i;
422  if (state->IsAccessRequested ()
423  && GetBackoffEndFor (state) <= Simulator::Now () )
424  {
429  MY_DEBUG ("dcf " << k << " needs access. backoff expired. access granted. slots=" << state->GetBackoffSlots ());
430  i++; // go to the next item in the list.
431  k++;
432  std::vector<DcfState *> internalCollisionStates;
433  for (States::const_iterator j = i; j != m_states.end (); j++, k++)
434  {
435  DcfState *otherState = *j;
436  if (otherState->IsAccessRequested ()
437  && GetBackoffEndFor (otherState) <= Simulator::Now ())
438  {
439  MY_DEBUG ("dcf " << k << " needs access. backoff expired. internal collision. slots=" <<
440  otherState->GetBackoffSlots ());
446  internalCollisionStates.push_back (otherState);
447  }
448  }
449 
457  state->NotifyAccessGranted ();
458  for (std::vector<DcfState *>::const_iterator k = internalCollisionStates.begin ();
459  k != internalCollisionStates.end (); k++)
460  {
461  (*k)->NotifyInternalCollision ();
462  }
463  break;
464  }
465  i++;
466  }
467 }
468 
469 void
471 {
472  UpdateBackoff ();
473  DoGrantAccess ();
475 }
476 
477 Time
479 {
480  Time rxAccessStart;
481  if (!m_rxing)
482  {
483  rxAccessStart = m_lastRxEnd + m_sifs;
484  if (!m_lastRxReceivedOk)
485  {
486  rxAccessStart += m_eifsNoDifs;
487  }
488  }
489  else
490  {
491  rxAccessStart = m_lastRxStart + m_lastRxDuration + m_sifs;
492  }
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,
500  busyAccessStart,
501  txAccessStart,
502  navAccessStart,
503  ackTimeoutAccessStart,
504  ctsTimeoutAccessStart,
505  switchingAccessStart
506  );
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;
513 }
514 
515 Time
517 {
518  Time mostRecentEvent = MostRecent (state->GetBackoffStart (),
520 
521  return mostRecentEvent;
522 }
523 
524 Time
526 {
527  return GetBackoffStartFor (state) + MicroSeconds (state->GetBackoffSlots () * m_slotTimeUs);
528 }
529 
530 void
532 {
533  uint32_t k = 0;
534  for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++, k++)
535  {
536  DcfState *state = *i;
537 
538  Time backoffStart = GetBackoffStartFor (state);
539  if (backoffStart <= Simulator::Now ())
540  {
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);
547  }
548  }
549 }
550 
551 void
553 {
558  bool accessTimeoutNeeded = false;
559  Time expectedBackoffEnd = Simulator::GetMaximumSimulationTime ();
560  for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++)
561  {
562  DcfState *state = *i;
563  if (state->IsAccessRequested ())
564  {
565  Time tmp = GetBackoffEndFor (state);
566  if (tmp > Simulator::Now ())
567  {
568  accessTimeoutNeeded = true;
569  expectedBackoffEnd = std::min (expectedBackoffEnd, tmp);
570  }
571  }
572  }
573  if (accessTimeoutNeeded)
574  {
575  MY_DEBUG ("expected backoff end=" << expectedBackoffEnd);
576  Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now ();
578  && Simulator::GetDelayLeft (m_accessTimeout) > expectedBackoffDelay)
579  {
581  }
582  if (m_accessTimeout.IsExpired ())
583  {
584  m_accessTimeout = Simulator::Schedule (expectedBackoffDelay,
586  }
587  }
588 }
589 
590 void
592 {
593  MY_DEBUG ("rx start for=" << duration);
594  UpdateBackoff ();
596  m_lastRxDuration = duration;
597  m_rxing = true;
598 }
599 void
601 {
602  MY_DEBUG ("rx end ok");
604  m_lastRxReceivedOk = true;
605  m_rxing = false;
606 }
607 void
609 {
610  MY_DEBUG ("rx end error");
612  m_lastRxReceivedOk = false;
613  m_rxing = false;
614 }
615 void
617 {
618  if (m_rxing)
619  {
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
622  //ago
626  m_lastRxReceivedOk = true;
627  m_rxing = false;
628  }
629  MY_DEBUG ("tx start for " << duration);
630  UpdateBackoff ();
632  m_lastTxDuration = duration;
633 }
634 void
636 {
637  MY_DEBUG ("busy start for " << duration);
638  UpdateBackoff ();
640  m_lastBusyDuration = duration;
641 }
642 
643 
644 void
646 {
647  Time now = Simulator::Now ();
650 
651  if (m_rxing)
652  {
653  // channel switching during packet reception
656  m_lastRxReceivedOk = true;
657  m_rxing = false;
658  }
659  if (m_lastNavStart + m_lastNavDuration > now)
660  {
662  }
664  {
666  }
667  if (m_lastAckTimeoutEnd > now)
668  {
669  m_lastAckTimeoutEnd = now;
670  }
671  if (m_lastCtsTimeoutEnd > now)
672  {
673  m_lastCtsTimeoutEnd = now;
674  }
675 
676  // Cancel timeout
677  if (m_accessTimeout.IsRunning ())
678  {
680  }
681 
682  // Reset backoffs
683  for (States::iterator i = m_states.begin (); i != m_states.end (); i++)
684  {
685  DcfState *state = *i;
686  uint32_t remainingSlots = state->GetBackoffSlots ();
687  if (remainingSlots > 0)
688  {
689  state->UpdateBackoffSlotsNow (remainingSlots, now);
690  NS_ASSERT (state->GetBackoffSlots () == 0);
691  }
692  state->ResetCw ();
693  state->m_accessRequested = false;
694  state->NotifyChannelSwitching ();
695  }
696 
697  MY_DEBUG ("switching start for " << duration);
699  m_lastSwitchingDuration = duration;
700 
701 }
702 
703 void
705 {
706  MY_DEBUG ("nav reset for=" << duration);
707  UpdateBackoff ();
709  m_lastNavDuration = duration;
710  UpdateBackoff ();
718 }
719 void
721 {
723  MY_DEBUG ("nav start for=" << duration);
724  UpdateBackoff ();
725  Time newNavEnd = Simulator::Now () + duration;
726  Time lastNavEnd = m_lastNavStart + m_lastNavDuration;
727  if (newNavEnd > lastNavEnd)
728  {
730  m_lastNavDuration = duration;
731  }
732 }
733 void
735 {
737  m_lastAckTimeoutEnd = Simulator::Now () + duration;
738 }
739 void
741 {
744 }
745 void
747 {
748  m_lastCtsTimeoutEnd = Simulator::Now () + duration;
749 }
750 void
752 {
755 }
756 } // namespace ns3