A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
sta-wifi-mac.cc
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006, 2009 INRIA
4  * Copyright (c) 2009 MIRKO BANCHI
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  * Author: Mirko Banchi <mk.banchi@gmail.com>
21  */
22 #include "sta-wifi-mac.h"
23 
24 #include "ns3/log.h"
25 #include "ns3/simulator.h"
26 #include "ns3/string.h"
27 #include "ns3/pointer.h"
28 #include "ns3/boolean.h"
29 #include "ns3/trace-source-accessor.h"
30 
31 #include "qos-tag.h"
32 #include "mac-low.h"
33 #include "dcf-manager.h"
34 #include "mac-rx-middle.h"
35 #include "mac-tx-middle.h"
36 #include "wifi-mac-header.h"
37 #include "msdu-aggregator.h"
38 #include "amsdu-subframe-header.h"
39 #include "mgt-headers.h"
40 
41 NS_LOG_COMPONENT_DEFINE ("StaWifiMac");
42 
43 
44 /*
45  * The state machine for this STA is:
46  -------------- -----------
47  | Associated | <-------------------- -------> | Refused |
48  -------------- \ / -----------
49  \ \ /
50  \ ----------------- -----------------------------
51  \-> | Beacon Missed | --> | Wait Association Response |
52  ----------------- -----------------------------
53  \ ^
54  \ |
55  \ -----------------------
56  \-> | Wait Probe Response |
57  -----------------------
58  */
59 
60 namespace ns3 {
61 
62 NS_OBJECT_ENSURE_REGISTERED (StaWifiMac);
63 
64 TypeId
65 StaWifiMac::GetTypeId (void)
66 {
67  static TypeId tid = TypeId ("ns3::StaWifiMac")
68  .SetParent<RegularWifiMac> ()
69  .AddConstructor<StaWifiMac> ()
70  .AddAttribute ("ProbeRequestTimeout", "The interval between two consecutive probe request attempts.",
71  TimeValue (Seconds (0.05)),
72  MakeTimeAccessor (&StaWifiMac::m_probeRequestTimeout),
73  MakeTimeChecker ())
74  .AddAttribute ("AssocRequestTimeout", "The interval between two consecutive assoc request attempts.",
75  TimeValue (Seconds (0.5)),
76  MakeTimeAccessor (&StaWifiMac::m_assocRequestTimeout),
77  MakeTimeChecker ())
78  .AddAttribute ("MaxMissedBeacons",
79  "Number of beacons which much be consecutively missed before "
80  "we attempt to restart association.",
81  UintegerValue (10),
82  MakeUintegerAccessor (&StaWifiMac::m_maxMissedBeacons),
83  MakeUintegerChecker<uint32_t> ())
84  .AddAttribute ("ActiveProbing", "If true, we send probe requests. If false, we don't. NOTE: if more than one STA in your simulation is using active probing, you should enable it at a different simulation time for each STA, otherwise all the STAs will start sending probes at the same time resulting in collisions. See bug 1060 for more info.",
85  BooleanValue (false),
86  MakeBooleanAccessor (&StaWifiMac::SetActiveProbing),
87  MakeBooleanChecker ())
88  .AddTraceSource ("Assoc", "Associated with an access point.",
89  MakeTraceSourceAccessor (&StaWifiMac::m_assocLogger))
90  .AddTraceSource ("DeAssoc", "Association with an access point lost.",
91  MakeTraceSourceAccessor (&StaWifiMac::m_deAssocLogger))
92  ;
93  return tid;
94 }
95 
96 StaWifiMac::StaWifiMac ()
97  : m_state (BEACON_MISSED),
98  m_probeRequestEvent (),
99  m_assocRequestEvent (),
100  m_beaconWatchdogEnd (Seconds (0.0))
101 {
102  NS_LOG_FUNCTION (this);
103 
104  // Let the lower layers know that we are acting as a non-AP STA in
105  // an infrastructure BSS.
106  SetTypeOfStation (STA);
107 }
108 
109 StaWifiMac::~StaWifiMac ()
110 {
111  NS_LOG_FUNCTION (this);
112 }
113 
114 void
116 {
117  NS_LOG_FUNCTION (this << missed);
118  m_maxMissedBeacons = missed;
119 }
120 
121 void
123 {
124  NS_LOG_FUNCTION (this << timeout);
125  m_probeRequestTimeout = timeout;
126 }
127 
128 void
130 {
131  NS_LOG_FUNCTION (this << timeout);
132  m_assocRequestTimeout = timeout;
133 }
134 
135 void
137 {
138  NS_LOG_FUNCTION (this);
139  TryToEnsureAssociated ();
140 }
141 
142 void
143 StaWifiMac::SetActiveProbing (bool enable)
144 {
145  NS_LOG_FUNCTION (this << enable);
146  if (enable)
147  {
148  Simulator::ScheduleNow (&StaWifiMac::TryToEnsureAssociated, this);
149  }
150  else
151  {
152  m_probeRequestEvent.Cancel ();
153  }
154 }
155 
156 void
157 StaWifiMac::SendProbeRequest (void)
158 {
159  NS_LOG_FUNCTION (this);
160  WifiMacHeader hdr;
161  hdr.SetProbeReq ();
162  hdr.SetAddr1 (Mac48Address::GetBroadcast ());
163  hdr.SetAddr2 (GetAddress ());
164  hdr.SetAddr3 (Mac48Address::GetBroadcast ());
165  hdr.SetDsNotFrom ();
166  hdr.SetDsNotTo ();
167  Ptr<Packet> packet = Create<Packet> ();
168  MgtProbeRequestHeader probe;
169  probe.SetSsid (GetSsid ());
170  probe.SetSupportedRates (GetSupportedRates ());
171  packet->AddHeader (probe);
172 
173  // The standard is not clear on the correct queue for management
174  // frames if we are a QoS AP. The approach taken here is to always
175  // use the DCF for these regardless of whether we have a QoS
176  // association or not.
177  m_dca->Queue (packet, hdr);
178 
179  m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
180  &StaWifiMac::ProbeRequestTimeout, this);
181 }
182 
183 void
184 StaWifiMac::SendAssociationRequest (void)
185 {
186  NS_LOG_FUNCTION (this << GetBssid ());
187  WifiMacHeader hdr;
188  hdr.SetAssocReq ();
189  hdr.SetAddr1 (GetBssid ());
190  hdr.SetAddr2 (GetAddress ());
191  hdr.SetAddr3 (GetBssid ());
192  hdr.SetDsNotFrom ();
193  hdr.SetDsNotTo ();
194  Ptr<Packet> packet = Create<Packet> ();
195  MgtAssocRequestHeader assoc;
196  assoc.SetSsid (GetSsid ());
197  assoc.SetSupportedRates (GetSupportedRates ());
198  packet->AddHeader (assoc);
199 
200  // The standard is not clear on the correct queue for management
201  // frames if we are a QoS AP. The approach taken here is to always
202  // use the DCF for these regardless of whether we have a QoS
203  // association or not.
204  m_dca->Queue (packet, hdr);
205 
206  m_assocRequestEvent = Simulator::Schedule (m_assocRequestTimeout,
207  &StaWifiMac::AssocRequestTimeout, this);
208 }
209 
210 void
211 StaWifiMac::TryToEnsureAssociated (void)
212 {
213  NS_LOG_FUNCTION (this);
214  switch (m_state)
215  {
216  case ASSOCIATED:
217  return;
218  break;
219  case WAIT_PROBE_RESP:
220  /* we have sent a probe request earlier so we
221  do not need to re-send a probe request immediately.
222  We just need to wait until probe-request-timeout
223  or until we get a probe response
224  */
225  break;
226  case BEACON_MISSED:
227  /* we were associated but we missed a bunch of beacons
228  * so we should assume we are not associated anymore.
229  * We try to initiate a probe request now.
230  */
231  m_linkDown ();
232  SetState (WAIT_PROBE_RESP);
233  SendProbeRequest ();
234  break;
235  case WAIT_ASSOC_RESP:
236  /* we have sent an assoc request so we do not need to
237  re-send an assoc request right now. We just need to
238  wait until either assoc-request-timeout or until
239  we get an assoc response.
240  */
241  break;
242  case REFUSED:
243  /* we have sent an assoc request and received a negative
244  assoc resp. We wait until someone restarts an
245  association with a given ssid.
246  */
247  break;
248  }
249 }
250 
251 void
252 StaWifiMac::AssocRequestTimeout (void)
253 {
254  NS_LOG_FUNCTION (this);
255  SetState (WAIT_ASSOC_RESP);
256  SendAssociationRequest ();
257 }
258 
259 void
260 StaWifiMac::ProbeRequestTimeout (void)
261 {
262  NS_LOG_FUNCTION (this);
263  SetState (WAIT_PROBE_RESP);
264  SendProbeRequest ();
265 }
266 
267 void
268 StaWifiMac::MissedBeacons (void)
269 {
270  NS_LOG_FUNCTION (this);
271  if (m_beaconWatchdogEnd > Simulator::Now ())
272  {
273  m_beaconWatchdog = Simulator::Schedule (m_beaconWatchdogEnd - Simulator::Now (),
274  &StaWifiMac::MissedBeacons, this);
275  return;
276  }
277  NS_LOG_DEBUG ("beacon missed");
278  SetState (BEACON_MISSED);
279  TryToEnsureAssociated ();
280 }
281 
282 void
283 StaWifiMac::RestartBeaconWatchdog (Time delay)
284 {
285  NS_LOG_FUNCTION (this << delay);
286  m_beaconWatchdogEnd = std::max (Simulator::Now () + delay, m_beaconWatchdogEnd);
287  if (Simulator::GetDelayLeft (m_beaconWatchdog) < delay
288  && m_beaconWatchdog.IsExpired ())
289  {
290  NS_LOG_DEBUG ("really restart watchdog.");
291  m_beaconWatchdog = Simulator::Schedule (delay, &StaWifiMac::MissedBeacons, this);
292  }
293 }
294 
295 bool
296 StaWifiMac::IsAssociated (void) const
297 {
298  return m_state == ASSOCIATED;
299 }
300 
301 bool
302 StaWifiMac::IsWaitAssocResp (void) const
303 {
304  return m_state == WAIT_ASSOC_RESP;
305 }
306 
307 void
309 {
310  NS_LOG_FUNCTION (this << packet << to);
311  if (!IsAssociated ())
312  {
313  NotifyTxDrop (packet);
314  TryToEnsureAssociated ();
315  return;
316  }
317  WifiMacHeader hdr;
318 
319  // If we are not a QoS AP then we definitely want to use AC_BE to
320  // transmit the packet. A TID of zero will map to AC_BE (through \c
321  // QosUtilsMapTidToAc()), so we use that as our default here.
322  uint8_t tid = 0;
323 
324  // For now, an AP that supports QoS does not support non-QoS
325  // associations, and vice versa. In future the AP model should
326  // support simultaneously associated QoS and non-QoS STAs, at which
327  // point there will need to be per-association QoS state maintained
328  // by the association state machine, and consulted here.
329  if (m_qosSupported)
330  {
331  hdr.SetType (WIFI_MAC_QOSDATA);
332  hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
333  hdr.SetQosNoEosp ();
334  hdr.SetQosNoAmsdu ();
335  // Transmission of multiple frames in the same TXOP is not
336  // supported for now
337  hdr.SetQosTxopLimit (0);
338 
339  // Fill in the QoS control field in the MAC header
340  tid = QosUtilsGetTidForPacket (packet);
341  // Any value greater than 7 is invalid and likely indicates that
342  // the packet had no QoS tag, so we revert to zero, which'll
343  // mean that AC_BE is used.
344  if (tid >= 7)
345  {
346  tid = 0;
347  }
348  hdr.SetQosTid (tid);
349  }
350  else
351  {
352  hdr.SetTypeData ();
353  }
354 
355  hdr.SetAddr1 (GetBssid ());
356  hdr.SetAddr2 (m_low->GetAddress ());
357  hdr.SetAddr3 (to);
358  hdr.SetDsNotFrom ();
359  hdr.SetDsTo ();
360 
361  if (m_qosSupported)
362  {
363  // Sanity check that the TID is valid
364  NS_ASSERT (tid < 8);
365  m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
366  }
367  else
368  {
369  m_dca->Queue (packet, hdr);
370  }
371 }
372 
373 void
375 {
376  NS_LOG_FUNCTION (this << packet << hdr);
377  NS_ASSERT (!hdr->IsCtl ());
378  if (hdr->GetAddr3 () == GetAddress ())
379  {
380  NS_LOG_LOGIC ("packet sent by us.");
381  return;
382  }
383  else if (hdr->GetAddr1 () != GetAddress ()
384  && !hdr->GetAddr1 ().IsGroup ())
385  {
386  NS_LOG_LOGIC ("packet is not for us");
387  NotifyRxDrop (packet);
388  return;
389  }
390  else if (hdr->IsData ())
391  {
392  if (!IsAssociated ())
393  {
394  NS_LOG_LOGIC ("Received data frame while not associated: ignore");
395  NotifyRxDrop (packet);
396  return;
397  }
398  if (!(hdr->IsFromDs () && !hdr->IsToDs ()))
399  {
400  NS_LOG_LOGIC ("Received data frame not from the DS: ignore");
401  NotifyRxDrop (packet);
402  return;
403  }
404  if (hdr->GetAddr2 () != GetBssid ())
405  {
406  NS_LOG_LOGIC ("Received data frame not from the BSS we are associated with: ignore");
407  NotifyRxDrop (packet);
408  return;
409  }
410 
411  if (hdr->IsQosData ())
412  {
413  if (hdr->IsQosAmsdu ())
414  {
415  NS_ASSERT (hdr->GetAddr3 () == GetBssid ());
416  DeaggregateAmsduAndForward (packet, hdr);
417  packet = 0;
418  }
419  else
420  {
421  ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
422  }
423  }
424  else
425  {
426  ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
427  }
428  return;
429  }
430  else if (hdr->IsProbeReq ()
431  || hdr->IsAssocReq ())
432  {
433  // This is a frame aimed at an AP, so we can safely ignore it.
434  NotifyRxDrop (packet);
435  return;
436  }
437  else if (hdr->IsBeacon ())
438  {
439  MgtBeaconHeader beacon;
440  packet->RemoveHeader (beacon);
441  bool goodBeacon = false;
442  if (GetSsid ().IsBroadcast ()
443  || beacon.GetSsid ().IsEqual (GetSsid ()))
444  {
445  goodBeacon = true;
446  }
447  if ((IsWaitAssocResp () || IsAssociated ()) && hdr->GetAddr3 () != GetBssid ())
448  {
449  goodBeacon = false;
450  }
451  if (goodBeacon)
452  {
453  Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
454  RestartBeaconWatchdog (delay);
455  SetBssid (hdr->GetAddr3 ());
456  }
457  if (goodBeacon && m_state == BEACON_MISSED)
458  {
459  SetState (WAIT_ASSOC_RESP);
460  SendAssociationRequest ();
461  }
462  return;
463  }
464  else if (hdr->IsProbeResp ())
465  {
466  if (m_state == WAIT_PROBE_RESP)
467  {
468  MgtProbeResponseHeader probeResp;
469  packet->RemoveHeader (probeResp);
470  if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
471  {
472  //not a probe resp for our ssid.
473  return;
474  }
475  SetBssid (hdr->GetAddr3 ());
476  Time delay = MicroSeconds (probeResp.GetBeaconIntervalUs () * m_maxMissedBeacons);
477  RestartBeaconWatchdog (delay);
478  if (m_probeRequestEvent.IsRunning ())
479  {
480  m_probeRequestEvent.Cancel ();
481  }
482  SetState (WAIT_ASSOC_RESP);
483  SendAssociationRequest ();
484  }
485  return;
486  }
487  else if (hdr->IsAssocResp ())
488  {
489  if (m_state == WAIT_ASSOC_RESP)
490  {
491  MgtAssocResponseHeader assocResp;
492  packet->RemoveHeader (assocResp);
493  if (m_assocRequestEvent.IsRunning ())
494  {
495  m_assocRequestEvent.Cancel ();
496  }
497  if (assocResp.GetStatusCode ().IsSuccess ())
498  {
499  SetState (ASSOCIATED);
500  NS_LOG_DEBUG ("assoc completed");
501  SupportedRates rates = assocResp.GetSupportedRates ();
502  for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
503  {
504  WifiMode mode = m_phy->GetMode (i);
505  if (rates.IsSupportedRate (mode.GetDataRate ()))
506  {
507  m_stationManager->AddSupportedMode (hdr->GetAddr2 (), mode);
508  if (rates.IsBasicRate (mode.GetDataRate ()))
509  {
510  m_stationManager->AddBasicMode (mode);
511  }
512  }
513  }
514  if (!m_linkUp.IsNull ())
515  {
516  m_linkUp ();
517  }
518  }
519  else
520  {
521  NS_LOG_DEBUG ("assoc refused");
522  SetState (REFUSED);
523  }
524  }
525  return;
526  }
527 
528  // Invoke the receive handler of our parent class to deal with any
529  // other frames. Specifically, this will handle Block Ack-related
530  // Management Action frames.
531  RegularWifiMac::Receive (packet, hdr);
532 }
533 
535 StaWifiMac::GetSupportedRates (void) const
536 {
537  SupportedRates rates;
538  for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
539  {
540  WifiMode mode = m_phy->GetMode (i);
541  rates.AddSupportedRate (mode.GetDataRate ());
542  }
543  return rates;
544 }
545 
546 void
547 StaWifiMac::SetState (MacState value)
548 {
549  if (value == ASSOCIATED
550  && m_state != ASSOCIATED)
551  {
552  m_assocLogger (GetBssid ());
553  }
554  else if (value != ASSOCIATED
555  && m_state == ASSOCIATED)
556  {
557  m_deAssocLogger (GetBssid ());
558  }
559  m_state = value;
560 }
561 
562 } // namespace ns3
static Time GetDelayLeft(const EventId &id)
Definition: simulator.cc:188
uint32_t RemoveHeader(Header &header)
Definition: packet.cc:285
keep track of time unit.
Definition: nstime.h:149
virtual void Receive(Ptr< Packet > packet, const WifiMacHeader *hdr)
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
virtual uint32_t GetNModes(void) const =0
void SetProbeRequestTimeout(Time timeout)
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:255
bool IsRunning(void) const
Definition: event-id.cc:59
virtual void DeaggregateAmsduAndForward(Ptr< Packet > aggregatedPacket, const WifiMacHeader *hdr)
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Definition: simulator.h:820
virtual Ssid GetSsid(void) const
The Supported Rates Information ElementThis class knows how to serialise and deserialise the Supporte...
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:88
void SetAssocRequestTimeout(Time timeout)
virtual void Receive(Ptr< Packet > packet, const WifiMacHeader *hdr)
uint8_t QosUtilsGetTidForPacket(Ptr< const Packet > packet)
Definition: qos-utils.cc:60
virtual void SetBssid(Mac48Address bssid)
Ptr< DcaTxop > m_dca
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:237
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Definition: qos-utils.cc:27
static Mac48Address GetBroadcast(void)
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
void StartActiveAssociation(void)
void SetMaxMissedBeacons(uint32_t missed)
bool IsGroup(void) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
an EUI-48 address
Definition: mac48-address.h:41
virtual WifiMode GetMode(uint32_t mode) const =0
static EventId ScheduleNow(MEM mem_ptr, OBJ obj)
Definition: simulator.h:981
static Time Now(void)
Definition: simulator.cc:179
virtual Mac48Address GetBssid(void) const
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
#define NS_LOG_DEBUG(msg)
Definition: log.h:255
virtual Mac48Address GetAddress(void) const
virtual void Enqueue(Ptr< const Packet > packet, Mac48Address to)
void Cancel(void)
Definition: event-id.cc:47
bool IsExpired(void) const
Definition: event-id.cc:53
uint64_t GetDataRate(void) const
Definition: wifi-mode.cc:57
Time MicroSeconds(uint64_t us)
create ns3::Time instances in units of microseconds.
Definition: nstime.h:615