A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ap-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 "ap-wifi-mac.h"
23 
24 #include "ns3/assert.h"
25 #include "ns3/log.h"
26 #include "ns3/simulator.h"
27 #include "ns3/string.h"
28 #include "ns3/pointer.h"
29 #include "ns3/boolean.h"
30 
31 #include "qos-tag.h"
32 #include "wifi-phy.h"
33 #include "dcf-manager.h"
34 #include "mac-rx-middle.h"
35 #include "mac-tx-middle.h"
36 #include "mgt-headers.h"
37 #include "mac-low.h"
38 #include "amsdu-subframe-header.h"
39 #include "msdu-aggregator.h"
40 
41 NS_LOG_COMPONENT_DEFINE ("ApWifiMac");
42 
43 namespace ns3 {
44 
45 NS_OBJECT_ENSURE_REGISTERED (ApWifiMac);
46 
47 TypeId
49 {
50  static TypeId tid = TypeId ("ns3::ApWifiMac")
52  .AddConstructor<ApWifiMac> ()
53  .AddAttribute ("BeaconInterval", "Delay between two beacons",
54  TimeValue (MicroSeconds (102400)),
55  MakeTimeAccessor (&ApWifiMac::GetBeaconInterval,
57  MakeTimeChecker ())
58  .AddAttribute ("BeaconGeneration", "Whether or not beacons are generated.",
59  BooleanValue (true),
60  MakeBooleanAccessor (&ApWifiMac::SetBeaconGeneration,
62  MakeBooleanChecker ())
63  ;
64  return tid;
65 }
66 
68 {
69  NS_LOG_FUNCTION (this);
70  m_beaconDca = CreateObject<DcaTxop> ();
71  m_beaconDca->SetAifsn (1);
72  m_beaconDca->SetMinCw (0);
73  m_beaconDca->SetMaxCw (0);
76 
77  // Let the lower layers know that we are acting as an AP.
79 
81 }
82 
84 {
85  NS_LOG_FUNCTION (this);
86 }
87 
88 void
90 {
91  NS_LOG_FUNCTION (this);
92  m_beaconDca = 0;
96 }
97 
98 void
100 {
101  // As an AP, our MAC address is also the BSSID. Hence we are
102  // overriding this function and setting both in our parent class.
103  RegularWifiMac::SetAddress (address);
104  RegularWifiMac::SetBssid (address);
105 }
106 
107 void
109 {
110  NS_LOG_FUNCTION (this << enable);
111  if (!enable)
112  {
114  }
115  else if (enable && !m_enableBeaconGeneration)
116  {
118  }
119  m_enableBeaconGeneration = enable;
120 }
121 
122 bool
124 {
126 }
127 
128 Time
130 {
131  return m_beaconInterval;
132 }
133 
134 void
136 {
137  NS_LOG_FUNCTION (this << stationManager);
138  m_beaconDca->SetWifiRemoteStationManager (stationManager);
140 }
141 
142 void
144 {
145  NS_LOG_FUNCTION (this);
147 
148  // The approach taken here is that, from the point of view of an AP,
149  // the link is always up, so we immediately invoke the callback if
150  // one is set
151  linkUp ();
152 }
153 
154 void
156 {
157  NS_LOG_FUNCTION (this << interval);
158  if ((interval.GetMicroSeconds () % 1024) != 0)
159  {
160  NS_LOG_WARN ("beacon interval should be multiple of 1024us, see IEEE Std. 802.11-2007, section 11.1.1.1");
161  }
162  m_beaconInterval = interval;
163 }
164 
165 void
167 {
168  NS_LOG_FUNCTION (this);
169  SendOneBeacon ();
170 }
171 
172 void
174  Mac48Address to)
175 {
176  // If we are not a QoS AP then we definitely want to use AC_BE to
177  // transmit the packet. A TID of zero will map to AC_BE (through \c
178  // QosUtilsMapTidToAc()), so we use that as our default here.
179  uint8_t tid = 0;
180 
181  // If we are a QoS AP then we attempt to get a TID for this packet
182  if (m_qosSupported)
183  {
184  tid = QosUtilsGetTidForPacket (packet);
185  // Any value greater than 7 is invalid and likely indicates that
186  // the packet had no QoS tag, so we revert to zero, which'll
187  // mean that AC_BE is used.
188  if (tid >= 7)
189  {
190  tid = 0;
191  }
192  }
193 
194  ForwardDown (packet, from, to, tid);
195 }
196 
197 void
199  Mac48Address to, uint8_t tid)
200 {
201  NS_LOG_FUNCTION (this << packet << from << to);
202  WifiMacHeader hdr;
203 
204  // For now, an AP that supports QoS does not support non-QoS
205  // associations, and vice versa. In future the AP model should
206  // support simultaneously associated QoS and non-QoS STAs, at which
207  // point there will need to be per-association QoS state maintained
208  // by the association state machine, and consulted here.
209  if (m_qosSupported)
210  {
213  hdr.SetQosNoEosp ();
214  hdr.SetQosNoAmsdu ();
215  // Transmission of multiple frames in the same TXOP is not
216  // supported for now
217  hdr.SetQosTxopLimit (0);
218  // Fill in the QoS control field in the MAC header
219  hdr.SetQosTid (tid);
220  }
221  else
222  {
223  hdr.SetTypeData ();
224  }
225 
226  hdr.SetAddr1 (to);
227  hdr.SetAddr2 (GetAddress ());
228  hdr.SetAddr3 (from);
229  hdr.SetDsFrom ();
230  hdr.SetDsNotTo ();
231 
232  if (m_qosSupported)
233  {
234  // Sanity check that the TID is valid
235  NS_ASSERT (tid < 8);
236  m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
237  }
238  else
239  {
240  m_dca->Queue (packet, hdr);
241  }
242 }
243 
244 void
246 {
247  NS_LOG_FUNCTION (this << packet << to << from);
248  if (to.IsBroadcast () || m_stationManager->IsAssociated (to))
249  {
250  ForwardDown (packet, from, to);
251  }
252 }
253 
254 void
256 {
257  // We're sending this packet with a from address that is our own. We
258  // get that address from the lower MAC and make use of the
259  // from-spoofing Enqueue() method to avoid duplicated code.
260  Enqueue (packet, to, m_low->GetAddress ());
261 }
262 
263 bool
265 {
266  return true;
267 }
268 
271 {
272  // send the set of supported rates and make sure that we indicate
273  // the Basic Rate set in this set of supported rates.
274  SupportedRates rates;
275  for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
276  {
277  WifiMode mode = m_phy->GetMode (i);
278  rates.AddSupportedRate (mode.GetDataRate ());
279  }
280  // set the basic rates
281  for (uint32_t j = 0; j < m_stationManager->GetNBasicModes (); j++)
282  {
284  rates.SetBasicRate (mode.GetDataRate ());
285  }
286  return rates;
287 }
288 
289 void
291 {
292  NS_LOG_FUNCTION (this << to);
293  WifiMacHeader hdr;
294  hdr.SetProbeResp ();
295  hdr.SetAddr1 (to);
296  hdr.SetAddr2 (GetAddress ());
297  hdr.SetAddr3 (GetAddress ());
298  hdr.SetDsNotFrom ();
299  hdr.SetDsNotTo ();
300  Ptr<Packet> packet = Create<Packet> ();
302  probe.SetSsid (GetSsid ());
303  probe.SetSupportedRates (GetSupportedRates ());
304  probe.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
305  packet->AddHeader (probe);
306 
307  // The standard is not clear on the correct queue for management
308  // frames if we are a QoS AP. The approach taken here is to always
309  // use the DCF for these regardless of whether we have a QoS
310  // association or not.
311  m_dca->Queue (packet, hdr);
312 }
313 
314 void
316 {
317  NS_LOG_FUNCTION (this << to << success);
318  WifiMacHeader hdr;
319  hdr.SetAssocResp ();
320  hdr.SetAddr1 (to);
321  hdr.SetAddr2 (GetAddress ());
322  hdr.SetAddr3 (GetAddress ());
323  hdr.SetDsNotFrom ();
324  hdr.SetDsNotTo ();
325  Ptr<Packet> packet = Create<Packet> ();
327  StatusCode code;
328  if (success)
329  {
330  code.SetSuccess ();
331  }
332  else
333  {
334  code.SetFailure ();
335  }
336  assoc.SetSupportedRates (GetSupportedRates ());
337  assoc.SetStatusCode (code);
338  packet->AddHeader (assoc);
339 
340  // The standard is not clear on the correct queue for management
341  // frames if we are a QoS AP. The approach taken here is to always
342  // use the DCF for these regardless of whether we have a QoS
343  // association or not.
344  m_dca->Queue (packet, hdr);
345 }
346 
347 void
349 {
350  NS_LOG_FUNCTION (this);
351  WifiMacHeader hdr;
352  hdr.SetBeacon ();
354  hdr.SetAddr2 (GetAddress ());
355  hdr.SetAddr3 (GetAddress ());
356  hdr.SetDsNotFrom ();
357  hdr.SetDsNotTo ();
358  Ptr<Packet> packet = Create<Packet> ();
359  MgtBeaconHeader beacon;
360  beacon.SetSsid (GetSsid ());
361  beacon.SetSupportedRates (GetSupportedRates ());
362  beacon.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
363 
364  packet->AddHeader (beacon);
365 
366  // The beacon has it's own special queue, so we load it in there
367  m_beaconDca->Queue (packet, hdr);
369 }
370 
371 void
373 {
374  NS_LOG_FUNCTION (this);
375  RegularWifiMac::TxOk (hdr);
376 
377  if (hdr.IsAssocResp ()
379  {
380  NS_LOG_DEBUG ("associated with sta=" << hdr.GetAddr1 ());
382  }
383 }
384 
385 void
387 {
388  NS_LOG_FUNCTION (this);
390 
391  if (hdr.IsAssocResp ()
393  {
394  NS_LOG_DEBUG ("assoc failed with sta=" << hdr.GetAddr1 ());
396  }
397 }
398 
399 void
401 {
402  NS_LOG_FUNCTION (this << packet << hdr);
403 
404  Mac48Address from = hdr->GetAddr2 ();
405 
406  if (hdr->IsData ())
407  {
408  Mac48Address bssid = hdr->GetAddr1 ();
409  if (!hdr->IsFromDs ()
410  && hdr->IsToDs ()
411  && bssid == GetAddress ()
412  && m_stationManager->IsAssociated (from))
413  {
414  Mac48Address to = hdr->GetAddr3 ();
415  if (to == GetAddress ())
416  {
417  NS_LOG_DEBUG ("frame for me from=" << from);
418  if (hdr->IsQosData ())
419  {
420  if (hdr->IsQosAmsdu ())
421  {
422  NS_LOG_DEBUG ("Received A-MSDU from=" << from << ", size=" << packet->GetSize ());
423  DeaggregateAmsduAndForward (packet, hdr);
424  packet = 0;
425  }
426  else
427  {
428  ForwardUp (packet, from, bssid);
429  }
430  }
431  else
432  {
433  ForwardUp (packet, from, bssid);
434  }
435  }
436  else if (to.IsGroup ()
438  {
439  NS_LOG_DEBUG ("forwarding frame from=" << from << ", to=" << to);
440  Ptr<Packet> copy = packet->Copy ();
441 
442  // If the frame we are forwarding is of type QoS Data,
443  // then we need to preserve the UP in the QoS control
444  // header...
445  if (hdr->IsQosData ())
446  {
447  ForwardDown (packet, from, to, hdr->GetQosTid ());
448  }
449  else
450  {
451  ForwardDown (packet, from, to);
452  }
453  ForwardUp (copy, from, to);
454  }
455  else
456  {
457  ForwardUp (packet, from, to);
458  }
459  }
460  else if (hdr->IsFromDs ()
461  && hdr->IsToDs ())
462  {
463  // this is an AP-to-AP frame
464  // we ignore for now.
465  NotifyRxDrop (packet);
466  }
467  else
468  {
469  // we can ignore these frames since
470  // they are not targeted at the AP
471  NotifyRxDrop (packet);
472  }
473  return;
474  }
475  else if (hdr->IsMgt ())
476  {
477  if (hdr->IsProbeReq ())
478  {
479  NS_ASSERT (hdr->GetAddr1 ().IsBroadcast ());
480  SendProbeResp (from);
481  return;
482  }
483  else if (hdr->GetAddr1 () == GetAddress ())
484  {
485  if (hdr->IsAssocReq ())
486  {
487  // first, verify that the the station's supported
488  // rate set is compatible with our Basic Rate set
489  MgtAssocRequestHeader assocReq;
490  packet->RemoveHeader (assocReq);
491  SupportedRates rates = assocReq.GetSupportedRates ();
492  bool problem = false;
493  for (uint32_t i = 0; i < m_stationManager->GetNBasicModes (); i++)
494  {
496  if (!rates.IsSupportedRate (mode.GetDataRate ()))
497  {
498  problem = true;
499  break;
500  }
501  }
502  if (problem)
503  {
504  // one of the Basic Rate set mode is not
505  // supported by the station. So, we return an assoc
506  // response with an error status.
507  SendAssocResp (hdr->GetAddr2 (), false);
508  }
509  else
510  {
511  // station supports all rates in Basic Rate Set.
512  // record all its supported modes in its associated WifiRemoteStation
513  for (uint32_t j = 0; j < m_phy->GetNModes (); j++)
514  {
515  WifiMode mode = m_phy->GetMode (j);
516  if (rates.IsSupportedRate (mode.GetDataRate ()))
517  {
518  m_stationManager->AddSupportedMode (from, mode);
519  }
520  }
522  // send assoc response with success status.
523  SendAssocResp (hdr->GetAddr2 (), true);
524  }
525  return;
526  }
527  else if (hdr->IsDisassociation ())
528  {
530  return;
531  }
532  }
533  }
534 
535  // Invoke the receive handler of our parent class to deal with any
536  // other frames. Specifically, this will handle Block Ack-related
537  // Management Action frames.
538  RegularWifiMac::Receive (packet, hdr);
539 }
540 
541 void
543  const WifiMacHeader *hdr)
544 {
546  MsduAggregator::Deaggregate (aggregatedPacket);
547 
548  for (MsduAggregator::DeaggregatedMsdusCI i = packets.begin ();
549  i != packets.end (); ++i)
550  {
551  if ((*i).second.GetDestinationAddr () == GetAddress ())
552  {
553  ForwardUp ((*i).first, (*i).second.GetSourceAddr (),
554  (*i).second.GetDestinationAddr ());
555  }
556  else
557  {
558  Mac48Address from = (*i).second.GetSourceAddr ();
559  Mac48Address to = (*i).second.GetDestinationAddr ();
560  NS_LOG_DEBUG ("forwarding QoS frame from=" << from << ", to=" << to);
561  ForwardDown ((*i).first, from, to, hdr->GetQosTid ());
562  }
563  }
564 }
565 
566 void
568 {
569  m_beaconDca->Start ();
572  {
574  }
576 }
577 
578 } // namespace ns3