aboutsummaryrefslogtreecommitdiffstats
path: root/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc
diff options
context:
space:
mode:
Diffstat (limited to 'emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc')
-rw-r--r--emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc876
1 files changed, 876 insertions, 0 deletions
diff --git a/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc
new file mode 100644
index 00000000..696d972c
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/ap-wifi-mac.cc
@@ -0,0 +1,876 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 2009 INRIA
+ * Copyright (c) 2009 MIRKO BANCHI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "ap-wifi-mac.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/boolean.h"
+#include "qos-tag.h"
+#include "wifi-phy.h"
+#include "dcf-manager.h"
+#include "mac-rx-middle.h"
+#include "mac-tx-middle.h"
+#include "mgt-headers.h"
+#include "mac-low.h"
+#include "amsdu-subframe-header.h"
+#include "msdu-aggregator.h"
+
+//added: for removing packets to old station
+#include "wifi-mac-queue.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("ApWifiMac");
+
+NS_OBJECT_ENSURE_REGISTERED (ApWifiMac);
+
+TypeId
+ApWifiMac::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ApWifiMac")
+ .SetParent<RegularWifiMac> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<ApWifiMac> ()
+ .AddAttribute ("BeaconInterval", "Delay between two beacons",
+ TimeValue (MicroSeconds (102400)),
+ MakeTimeAccessor (&ApWifiMac::GetBeaconInterval,
+ &ApWifiMac::SetBeaconInterval),
+ MakeTimeChecker ())
+ .AddAttribute ("BeaconJitter", "A uniform random variable to cause the initial beacon starting time (after simulation time 0) "
+ "to be distributed between 0 and the BeaconInterval.",
+ StringValue ("ns3::UniformRandomVariable"),
+ MakePointerAccessor (&ApWifiMac::m_beaconJitter),
+ MakePointerChecker<UniformRandomVariable> ())
+ .AddAttribute ("EnableBeaconJitter", "If beacons are enabled, whether to jitter the initial send event.",
+ BooleanValue (false),
+ MakeBooleanAccessor (&ApWifiMac::m_enableBeaconJitter),
+ MakeBooleanChecker ())
+ .AddAttribute ("BeaconGeneration", "Whether or not beacons are generated.",
+ BooleanValue (true),
+ MakeBooleanAccessor (&ApWifiMac::SetBeaconGeneration,
+ &ApWifiMac::GetBeaconGeneration),
+ MakeBooleanChecker ())
+ ;
+ return tid;
+}
+
+ApWifiMac::ApWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca = CreateObject<DcaTxop> ();
+ m_beaconDca->SetAifsn (1);
+ m_beaconDca->SetMinCw (0);
+ m_beaconDca->SetMaxCw (0);
+ m_beaconDca->SetLow (m_low);
+ m_beaconDca->SetManager (m_dcfManager);
+ m_beaconDca->SetTxMiddle (m_txMiddle);
+
+ //Let the lower layers know that we are acting as an AP.
+ SetTypeOfStation (AP);
+
+ m_enableBeaconGeneration = false;
+}
+
+ApWifiMac::~ApWifiMac ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+ApWifiMac::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca = 0;
+ m_enableBeaconGeneration = false;
+ m_beaconEvent.Cancel ();
+ RegularWifiMac::DoDispose ();
+}
+
+void
+ApWifiMac::SetAddress (Mac48Address address)
+{
+ NS_LOG_FUNCTION (this << address);
+ //As an AP, our MAC address is also the BSSID. Hence we are
+ //overriding this function and setting both in our parent class.
+ RegularWifiMac::SetAddress (address);
+ RegularWifiMac::SetBssid (address);
+}
+
+void
+ApWifiMac::SetBeaconGeneration (bool enable)
+{
+ NS_LOG_FUNCTION (this << enable);
+ if (!enable)
+ {
+ m_beaconEvent.Cancel ();
+ }
+ else if (enable && !m_enableBeaconGeneration)
+ {
+ m_beaconEvent = Simulator::ScheduleNow (&ApWifiMac::SendOneBeacon, this);
+ }
+ m_enableBeaconGeneration = enable;
+}
+
+bool
+ApWifiMac::GetBeaconGeneration (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_enableBeaconGeneration;
+}
+
+Time
+ApWifiMac::GetBeaconInterval (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_beaconInterval;
+}
+
+void
+ApWifiMac::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager)
+{
+ NS_LOG_FUNCTION (this << stationManager);
+ m_beaconDca->SetWifiRemoteStationManager (stationManager);
+ RegularWifiMac::SetWifiRemoteStationManager (stationManager);
+}
+
+void
+ApWifiMac::SetLinkUpCallback (Callback<void> linkUp)
+{
+ NS_LOG_FUNCTION (this << &linkUp);
+ RegularWifiMac::SetLinkUpCallback (linkUp);
+
+ //The approach taken here is that, from the point of view of an AP,
+ //the link is always up, so we immediately invoke the callback if
+ //one is set
+ linkUp ();
+}
+
+void
+ApWifiMac::SetBeaconInterval (Time interval)
+{
+ NS_LOG_FUNCTION (this << interval);
+ if ((interval.GetMicroSeconds () % 1024) != 0)
+ {
+ NS_LOG_WARN ("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE Std. 802.11-2012");
+ }
+ m_beaconInterval = interval;
+}
+
+void
+ApWifiMac::StartBeaconing (void)
+{
+ NS_LOG_FUNCTION (this);
+ SendOneBeacon ();
+}
+
+int64_t
+ApWifiMac::AssignStreams (int64_t stream)
+{
+ NS_LOG_FUNCTION (this << stream);
+ m_beaconJitter->SetStream (stream);
+ return 1;
+}
+
+void
+ApWifiMac::ForwardDown (Ptr<const Packet> packet, Mac48Address from,
+ Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << from << to);
+ //If we are not a QoS AP then we definitely want to use AC_BE to
+ //transmit the packet. A TID of zero will map to AC_BE (through \c
+ //QosUtilsMapTidToAc()), so we use that as our default here.
+ uint8_t tid = 0;
+
+ //If we are a QoS AP then we attempt to get a TID for this packet
+ if (m_qosSupported)
+ {
+ tid = QosUtilsGetTidForPacket (packet);
+ //Any value greater than 7 is invalid and likely indicates that
+ //the packet had no QoS tag, so we revert to zero, which'll
+ //mean that AC_BE is used.
+ if (tid > 7)
+ {
+ tid = 0;
+ }
+ }
+
+ ForwardDown (packet, from, to, tid);
+}
+
+void
+ApWifiMac::ForwardDown (Ptr<const Packet> packet, Mac48Address from,
+ Mac48Address to, uint8_t tid)
+{
+ NS_LOG_FUNCTION (this << packet << from << to << static_cast<uint32_t> (tid));
+ WifiMacHeader hdr;
+
+ //For now, an AP that supports QoS does not support non-QoS
+ //associations, and vice versa. In future the AP model should
+ //support simultaneously associated QoS and non-QoS STAs, at which
+ //point there will need to be per-association QoS state maintained
+ //by the association state machine, and consulted here.
+ if (m_qosSupported)
+ {
+ hdr.SetType (WIFI_MAC_QOSDATA);
+ hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+ hdr.SetQosNoEosp ();
+ hdr.SetQosNoAmsdu ();
+ //Transmission of multiple frames in the same TXOP is not
+ //supported for now
+ hdr.SetQosTxopLimit (0);
+ //Fill in the QoS control field in the MAC header
+ hdr.SetQosTid (tid);
+ }
+ else
+ {
+ hdr.SetTypeData ();
+ }
+
+ if (m_htSupported || m_vhtSupported)
+ {
+ hdr.SetNoOrder ();
+ }
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (from);
+ hdr.SetDsFrom ();
+ hdr.SetDsNotTo ();
+
+ if (m_qosSupported)
+ {
+ //Sanity check that the TID is valid
+ NS_ASSERT (tid < 8);
+ m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
+ }
+ else
+ {
+ m_dca->Queue (packet, hdr);
+ }
+}
+
+void
+ApWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from)
+{
+ NS_LOG_FUNCTION (this << packet << to << from);
+ if (to.IsBroadcast () || m_stationManager->IsAssociated (to))
+ {
+ ForwardDown (packet, from, to);
+ }
+}
+
+void
+ApWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << packet << to);
+ //We're sending this packet with a from address that is our own. We
+ //get that address from the lower MAC and make use of the
+ //from-spoofing Enqueue() method to avoid duplicated code.
+ Enqueue (packet, to, m_low->GetAddress ());
+}
+
+bool
+ApWifiMac::SupportsSendFrom (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return true;
+}
+
+SupportedRates
+ApWifiMac::GetSupportedRates (void) const
+{
+ NS_LOG_FUNCTION (this);
+ SupportedRates rates;
+ //If it is an HT-AP then add the BSSMembershipSelectorSet
+ //which only includes 127 for HT now. The standard says that the BSSMembershipSelectorSet
+ //must have its MSB set to 1 (must be treated as a Basic Rate)
+ //Also the standard mentioned that at leat 1 element should be included in the SupportedRates the rest can be in the ExtendedSupportedRates
+ if (m_htSupported || m_vhtSupported)
+ {
+ for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
+ {
+ rates.SetBasicRate (m_phy->GetBssMembershipSelector (i));
+ }
+ }
+ //Send the set of supported rates and make sure that we indicate
+ //the Basic Rate set in this set of supported rates.
+ for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
+ {
+ WifiMode mode = m_phy->GetMode (i);
+ rates.AddSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1));
+ //Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
+ //here we choose to add the mandatory rates to the BSSBasicRateSet,
+ //exept for 802.11b where we assume that only the non HR-DSSS rates are part of the BSSBasicRateSet
+ if (mode.IsMandatory () && (mode.GetModulationClass () != WIFI_MOD_CLASS_HR_DSSS))
+ {
+ m_stationManager->AddBasicMode (mode);
+ }
+ }
+ //set the basic rates
+ for (uint32_t j = 0; j < m_stationManager->GetNBasicModes (); j++)
+ {
+ WifiMode mode = m_stationManager->GetBasicMode (j);
+ rates.SetBasicRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1));
+ }
+
+ return rates;
+}
+
+HtCapabilities
+ApWifiMac::GetHtCapabilities (void) const
+{
+ HtCapabilities capabilities;
+ capabilities.SetHtSupported (1);
+ if (m_htSupported)
+ {
+ capabilities.SetLdpc (m_phy->GetLdpc ());
+ capabilities.SetSupportedChannelWidth (m_phy->GetChannelWidth () == 40);
+ capabilities.SetShortGuardInterval20 (m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardInterval40 (m_phy->GetChannelWidth () == 40 && m_phy->GetGuardInterval ());
+ capabilities.SetGreenfield (m_phy->GetGreenfield ());
+ capabilities.SetMaxAmsduLength (1); //hardcoded for now (TBD)
+ capabilities.SetLSigProtectionSupport (!m_phy->GetGreenfield ());
+ capabilities.SetMaxAmpduLength (3); //hardcoded for now (TBD)
+ uint64_t maxSupportedRate = 0; //in bit/s
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ capabilities.SetRxMcsBitmask (mcs.GetMcsValue ());
+ if (mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1) > maxSupportedRate)
+ {
+ maxSupportedRate = mcs.GetDataRate (m_phy->GetGuardInterval (), m_phy->GetGuardInterval (), 1);
+ }
+ }
+ capabilities.SetRxHighestSupportedDataRate (maxSupportedRate / 1e6); //in Mbit/s
+ capabilities.SetTxMcsSetDefined (m_phy->GetNMcs () > 0);
+ capabilities.SetTxMaxNSpatialStreams (m_phy->GetNumberOfTransmitAntennas ());
+ }
+ return capabilities;
+}
+
+VhtCapabilities
+ApWifiMac::GetVhtCapabilities (void) const
+{
+ VhtCapabilities capabilities;
+ capabilities.SetVhtSupported (1);
+ if (m_vhtSupported)
+ {
+ if (m_phy->GetChannelWidth () == 160)
+ {
+ capabilities.SetSupportedChannelWidthSet (1);
+ }
+ else
+ {
+ capabilities.SetSupportedChannelWidthSet (0);
+ }
+ capabilities.SetMaxMpduLength (2); //hardcoded for now (TBD)
+ capabilities.SetRxLdpc (m_phy->GetLdpc ());
+ capabilities.SetShortGuardIntervalFor80Mhz ((m_phy->GetChannelWidth () == 80) && m_phy->GetGuardInterval ());
+ capabilities.SetShortGuardIntervalFor160Mhz ((m_phy->GetChannelWidth () == 160) && m_phy->GetGuardInterval ());
+ capabilities.SetMaxAmpduLengthExponent (7); //hardcoded for now (TBD)
+ uint8_t maxMcs = 0;
+ for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetMcsValue () > maxMcs)
+ {
+ maxMcs = mcs.GetMcsValue ();
+ }
+ }
+ capabilities.SetRxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ capabilities.SetTxMcsMap (maxMcs, 1); //Only 1 SS is currently supported
+ }
+ return capabilities;
+}
+
+void
+ApWifiMac::SendProbeResp (Mac48Address to)
+{
+ NS_LOG_FUNCTION (this << to);
+ WifiMacHeader hdr;
+ hdr.SetProbeResp ();
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtProbeResponseHeader probe;
+ probe.SetSsid (GetSsid ());
+ probe.SetSupportedRates (GetSupportedRates ());
+ probe.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ probe.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ probe.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (probe);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+}
+
+void
+ApWifiMac::SendAssocResp (Mac48Address to, bool success)
+{
+ NS_LOG_FUNCTION (this << to << success);
+ WifiMacHeader hdr;
+ hdr.SetAssocResp ();
+ hdr.SetAddr1 (to);
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtAssocResponseHeader assoc;
+ StatusCode code;
+ if (success)
+ {
+ code.SetSuccess ();
+ }
+ else
+ {
+ code.SetFailure ();
+ }
+ assoc.SetSupportedRates (GetSupportedRates ());
+ assoc.SetStatusCode (code);
+
+ if (m_htSupported || m_vhtSupported)
+ {
+ assoc.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ assoc.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (assoc);
+
+ //The standard is not clear on the correct queue for management
+ //frames if we are a QoS AP. The approach taken here is to always
+ //use the DCF for these regardless of whether we have a QoS
+ //association or not.
+ m_dca->Queue (packet, hdr);
+}
+
+void
+ApWifiMac::SendOneBeacon (void)
+{
+ NS_LOG_FUNCTION (this);
+ WifiMacHeader hdr;
+ hdr.SetBeacon ();
+ hdr.SetAddr1 (Mac48Address::GetBroadcast ());
+ hdr.SetAddr2 (GetAddress ());
+ hdr.SetAddr3 (GetAddress ());
+ hdr.SetDsNotFrom ();
+ hdr.SetDsNotTo ();
+ Ptr<Packet> packet = Create<Packet> ();
+ MgtBeaconHeader beacon;
+ beacon.SetSsid (GetSsid ());
+ beacon.SetSupportedRates (GetSupportedRates ());
+ beacon.SetBeaconIntervalUs (m_beaconInterval.GetMicroSeconds ());
+ if (m_htSupported || m_vhtSupported)
+ {
+ beacon.SetHtCapabilities (GetHtCapabilities ());
+ hdr.SetNoOrder ();
+ }
+ if (m_vhtSupported)
+ {
+ beacon.SetVhtCapabilities (GetVhtCapabilities ());
+ }
+ packet->AddHeader (beacon);
+
+ //The beacon has it's own special queue, so we load it in there
+ m_beaconDca->Queue (packet, hdr);
+ m_beaconEvent = Simulator::Schedule (m_beaconInterval, &ApWifiMac::SendOneBeacon, this);
+}
+
+void
+ApWifiMac::TxOk (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this);
+ RegularWifiMac::TxOk (hdr);
+
+ if (hdr.IsAssocResp ()
+ && m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
+ {
+ NS_LOG_DEBUG ("associated with sta=" << hdr.GetAddr1 ());
+ m_stationManager->RecordGotAssocTxOk (hdr.GetAddr1 ());
+ }
+}
+
+void
+ApWifiMac::TxFailed (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this);
+ RegularWifiMac::TxFailed (hdr);
+
+ //modified by zeng: to avoid bugs in associaton process, transmit multiple times association response message until it is acked
+ if (hdr.IsAssocResp ()
+ && m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
+ {
+ m_stationManager->ReportGotAssocTxFailed(hdr.GetAddr1 ());
+
+ if(m_stationManager->NeedAssocRespRetransmission(hdr.GetAddr1 ()))
+ {
+ SendAssocResp(hdr.GetAddr1 (),true);//here it is hardcoded to true for the moment
+ }
+ else
+ {
+ NS_LOG_DEBUG ("assoc failed with sta=" << hdr.GetAddr1 ());
+ std::cout<<"assoc failed with sta="<<hdr.GetAddr1 ()<<"\n";
+ m_stationManager->RecordGotAssocTxFailed (hdr.GetAddr1 ());
+ }
+
+ }
+}
+
+void
+ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << packet << hdr);
+
+ Mac48Address from = hdr->GetAddr2 ();
+
+ if (hdr->IsData ())
+ {
+ Mac48Address bssid = hdr->GetAddr1 ();
+ if (!hdr->IsFromDs ()
+ && hdr->IsToDs ()
+ && bssid == GetAddress ()
+ && m_stationManager->IsAssociated (from))
+ {
+ Mac48Address to = hdr->GetAddr3 ();
+ if (to == GetAddress ())
+ {
+ NS_LOG_DEBUG ("frame for me from=" << from);
+ if (hdr->IsQosData ())
+ {
+ if (hdr->IsQosAmsdu ())
+ {
+ NS_LOG_DEBUG ("Received A-MSDU from=" << from << ", size=" << packet->GetSize ());
+ DeaggregateAmsduAndForward (packet, hdr);
+ packet = 0;
+ }
+ else
+ {
+ ForwardUp (packet, from, bssid);
+ }
+ }
+ else
+ {
+ ForwardUp (packet, from, bssid);
+ }
+ }
+ else if (to.IsGroup ()
+ || m_stationManager->IsAssociated (to))
+ {
+ NS_LOG_DEBUG ("forwarding frame from=" << from << ", to=" << to);
+ Ptr<Packet> copy = packet->Copy ();
+
+ //If the frame we are forwarding is of type QoS Data,
+ //then we need to preserve the UP in the QoS control
+ //header...
+ if (hdr->IsQosData ())
+ {
+ ForwardDown (packet, from, to, hdr->GetQosTid ());
+ }
+ else
+ {
+ ForwardDown (packet, from, to);
+ }
+ ForwardUp (copy, from, to);
+ }
+ else
+ {
+ ForwardUp (packet, from, to);
+ }
+ }
+ else if (hdr->IsFromDs ()
+ && hdr->IsToDs ())
+ {
+ //this is an AP-to-AP frame
+ //we ignore for now.
+ NotifyRxDrop (packet);
+ }
+ else
+ {
+ //we can ignore these frames since
+ //they are not targeted at the AP
+ NotifyRxDrop (packet);
+ }
+ return;
+ }
+ else if (hdr->IsMgt ())
+ {
+ if (hdr->IsProbeReq ())
+ {
+ NS_ASSERT (hdr->GetAddr1 ().IsBroadcast ());
+ SendProbeResp (from);
+ return;
+ }
+ else if (hdr->GetAddr1 () == GetAddress ())
+ {
+ if (hdr->IsAssocReq ())
+ {
+ //first, verify that the the station's supported
+ //rate set is compatible with our Basic Rate set
+ MgtAssocRequestHeader assocReq;
+ packet->RemoveHeader (assocReq);
+ SupportedRates rates = assocReq.GetSupportedRates ();
+ bool problem = false;
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicModes (); i++)
+ {
+ WifiMode mode = m_stationManager->GetBasicMode (i);
+ if (!rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ problem = true;
+ break;
+ }
+ }
+ if (m_htSupported)
+ {
+ //check that the STA supports all MCSs in Basic MCS Set
+ HtCapabilities htcapabilities = assocReq.GetHtCapabilities ();
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
+ {
+ WifiMode mcs = m_stationManager->GetBasicMcs (i);
+ if (!htcapabilities.IsSupportedMcs (mcs.GetMcsValue ()))
+ {
+ problem = true;
+ break;
+ }
+ }
+ }
+ if (m_vhtSupported)
+ {
+ //check that the STA supports all MCSs in Basic MCS Set
+ VhtCapabilities vhtcapabilities = assocReq.GetVhtCapabilities ();
+ for (uint32_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
+ {
+ WifiMode mcs = m_stationManager->GetBasicMcs (i);
+ if (!vhtcapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
+ {
+ problem = true;
+ break;
+ }
+ }
+ }
+ if (problem)
+ {
+ //One of the Basic Rate set mode is not
+ //supported by the station. So, we return an assoc
+ //response with an error status.
+ SendAssocResp (hdr->GetAddr2 (), false);
+ }
+ else
+ {
+ //station supports all rates in Basic Rate Set.
+
+ //added+++++++++++++++
+ //before moving on to accept assoication, we need to clean up the old states related to this station
+ //m_stationManager->RemoveStation(from);
+ //++++++++++++++++++++++++
+#ifdef WITH_MORE_FIX_TO_BA_IN_AP
+ //added: since it is a reassociation, destroy all the existing agreements immediately if exists
+ for(uint8_t tid=0; tid<=7;tid++)
+ {
+
+ MgtDelBaHeader delbaHdr;
+
+ delbaHdr.SetTid (tid);
+
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+
+ //destroy aggreement with station in baMananger:
+ m_edca[ac]->GotDelBaFrame(&delbaHdr, hdr->GetAddr2 ());
+
+ //also destroy aggreement with station at mac low immediately:
+ m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), tid);
+ }
+#endif
+
+ //record all its supported modes in its associated WifiRemoteStation
+ for (uint32_t j = 0; j < m_phy->GetNModes (); j++)
+ {
+ WifiMode mode = m_phy->GetMode (j);
+ if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
+ {
+ m_stationManager->AddSupportedMode (from, mode);
+ }
+ }
+ if (m_htSupported)
+ {
+ HtCapabilities htcapabilities = assocReq.GetHtCapabilities ();
+ m_stationManager->AddStationHtCapabilities (from,htcapabilities);
+ for (uint32_t j = 0; j < m_phy->GetNMcs (); j++)
+ {
+ WifiMode mcs = m_phy->GetMcs (j);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_HT && htcapabilities.IsSupportedMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (from, mcs);
+ }
+ }
+ }
+ if (m_vhtSupported)
+ {
+ VhtCapabilities vhtCapabilities = assocReq.GetVhtCapabilities ();
+ m_stationManager->AddStationVhtCapabilities (from, vhtCapabilities);
+ for (uint32_t i = 0; i < m_phy->GetNMcs (); i++)
+ {
+ WifiMode mcs = m_phy->GetMcs (i);
+ if (mcs.GetModulationClass () == WIFI_MOD_CLASS_VHT && vhtCapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
+ {
+ m_stationManager->AddSupportedMcs (hdr->GetAddr2 (), mcs);
+ //here should add a control to add basic MCS when it is implemented
+ }
+ }
+ }
+ m_stationManager->RecordWaitAssocTxOk (from);
+ // send assoc response with success status.
+ SendAssocResp (hdr->GetAddr2 (), true);
+ }
+ return;
+ }
+ else if (hdr->IsDisassociation ())
+ {
+ //deestroy aggreements and clean up packets to the station:
+ //destroy all block ack agreement with old AP (by pretending to receive a delba frame from AP).
+ //clean up packets for the old AP in the meanwhile
+ for(uint8_t tid=0; tid<=7;tid++)
+ {
+ MgtDelBaHeader delbaHdr;
+ delbaHdr.SetTid (tid);
+ AcIndex ac = QosUtilsMapTidToAc (tid);
+ m_edca[ac]->GotDelBaFrame(&delbaHdr, from);
+// //also destroy aggreement at mac low immediately:
+ m_low->DestroyBlockAckAgreement (from, tid);
+
+ WifiMacHeader dequeuedHdr;
+
+ //for edca:
+ Ptr<WifiMacQueue > edcaQueue=m_edca[ac]->GetEdcaQueue ();
+
+ Ptr<const Packet> dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ // int count=0;
+ while (dequeuedPacket != 0)
+ {
+ // count++;
+ dequeuedPacket = edcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ }
+
+ // if(count!=0)
+ // std::cout<<"No. of packets for old AP is "<<count<<"\n";
+
+ // count=0;
+ //for dca
+ Ptr<WifiMacQueue > dcaQueue=m_dca->GetQueue ();
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+
+ while (dequeuedPacket != 0)
+ {
+// count++;
+ dequeuedPacket = dcaQueue->DequeueByTidAndAddress (&dequeuedHdr, tid,
+ WifiMacHeader::ADDR1,
+ from);
+ }
+// if(count!=0)
+// std::cout<<"No. of packets in dca for old AP is "<<count<<"\n";
+
+ }
+ m_stationManager->RecordDisassociated (from);
+ return;
+ }
+ }
+ }
+
+ //Invoke the receive handler of our parent class to deal with any
+ //other frames. Specifically, this will handle Block Ack-related
+ //Management Action frames.
+ RegularWifiMac::Receive (packet, hdr);
+}
+
+void
+ApWifiMac::DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket,
+ const WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << aggregatedPacket << hdr);
+ MsduAggregator::DeaggregatedMsdus packets =
+ MsduAggregator::Deaggregate (aggregatedPacket);
+
+ for (MsduAggregator::DeaggregatedMsdusCI i = packets.begin ();
+ i != packets.end (); ++i)
+ {
+ if ((*i).second.GetDestinationAddr () == GetAddress ())
+ {
+ ForwardUp ((*i).first, (*i).second.GetSourceAddr (),
+ (*i).second.GetDestinationAddr ());
+ }
+ else
+ {
+ Mac48Address from = (*i).second.GetSourceAddr ();
+ Mac48Address to = (*i).second.GetDestinationAddr ();
+ NS_LOG_DEBUG ("forwarding QoS frame from=" << from << ", to=" << to);
+ ForwardDown ((*i).first, from, to, hdr->GetQosTid ());
+ }
+ }
+}
+
+void
+ApWifiMac::DoInitialize (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_beaconDca->Initialize ();
+ m_beaconEvent.Cancel ();
+ if (m_enableBeaconGeneration)
+ {
+ if (m_enableBeaconJitter)
+ {
+ int64_t jitter = m_beaconJitter->GetValue (0, m_beaconInterval.GetMicroSeconds ());
+ NS_LOG_DEBUG ("Scheduling initial beacon for access point " << GetAddress () << " at time " << jitter << " microseconds");
+ m_beaconEvent = Simulator::Schedule (MicroSeconds (jitter), &ApWifiMac::SendOneBeacon, this);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Scheduling initial beacon for access point " << GetAddress () << " at time 0");
+ m_beaconEvent = Simulator::ScheduleNow (&ApWifiMac::SendOneBeacon, this);
+ }
+ }
+ RegularWifiMac::DoInitialize ();
+}
+
+} //namespace ns3