A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
sta-wifi-mac.cc
Go to the documentation of this file.
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
66 {
67  static TypeId tid = TypeId ("ns3::StaWifiMac")
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.",
90  .AddTraceSource ("DeAssoc", "Association with an access point lost.",
92  ;
93  return tid;
94 }
95 
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.
107 }
108 
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);
126 }
127 
128 void
130 {
131  NS_LOG_FUNCTION (this << timeout);
133 }
134 
135 void
137 {
138  NS_LOG_FUNCTION (this);
140 }
141 
142 void
144 {
145  NS_LOG_FUNCTION (this << enable);
146  if (enable)
147  {
149  }
150  else
151  {
153  }
154 }
155 
156 void
158 {
159  NS_LOG_FUNCTION (this);
160  WifiMacHeader hdr;
161  hdr.SetProbeReq ();
163  hdr.SetAddr2 (GetAddress ());
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 
181 }
182 
183 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 
208 }
209 
210 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 ();
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
253 {
254  NS_LOG_FUNCTION (this);
257 }
258 
259 void
261 {
262  NS_LOG_FUNCTION (this);
264  SendProbeRequest ();
265 }
266 
267 void
269 {
270  NS_LOG_FUNCTION (this);
272  {
275  return;
276  }
277  NS_LOG_DEBUG ("beacon missed");
280 }
281 
282 void
284 {
285  NS_LOG_FUNCTION (this << delay);
286  m_beaconWatchdogEnd = std::max (Simulator::Now () + delay, m_beaconWatchdogEnd);
289  {
290  NS_LOG_DEBUG ("really restart watchdog.");
292  }
293 }
294 
295 bool
297 {
298  return m_state == ASSOCIATED;
299 }
300 
301 bool
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);
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  {
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  {
454  RestartBeaconWatchdog (delay);
455  SetBssid (hdr->GetAddr3 ());
456  }
457  if (goodBeacon && m_state == BEACON_MISSED)
458  {
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);
479  {
481  }
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);
494  {
496  }
497  if (assocResp.GetStatusCode ().IsSuccess ())
498  {
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  {
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 
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
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  {
558  }
559  m_state = value;
560 }
561 
562 } // namespace ns3