void
StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
NS_LOG_FUNCTION (this << packet << hdr);
NS_ASSERT (!hdr->IsCtl ());
if (hdr->GetAddr3 () == GetAddress ())
{
NS_LOG_LOGIC ("packet sent by us.");
return;
}
else if (hdr->GetAddr1 () != GetAddress ()
&& !hdr->GetAddr1 ().IsGroup ())
{
NS_LOG_LOGIC ("packet is not for us");
NotifyRxDrop (packet);
return;
}
else if (hdr->IsData ())
{
if (!IsAssociated ())
{
NS_LOG_LOGIC ("Received data frame while not associated: ignore");
NotifyRxDrop (packet);
return;
}
if (!(hdr->IsFromDs () && !hdr->IsToDs ()))
{
NS_LOG_LOGIC ("Received data frame not from the DS: ignore");
NotifyRxDrop (packet);
return;
}
if (hdr->GetAddr2 () != GetBssid ())
{
NS_LOG_LOGIC ("Received data frame not from the BSS we are associated with: ignore");
NotifyRxDrop (packet);
return;
}
if (hdr->IsQosData ())
{
if (hdr->IsQosAmsdu ())
{
NS_ASSERT (hdr->GetAddr3 () == GetBssid ());
DeaggregateAmsduAndForward (packet, hdr);
packet = 0;
}
else
{
ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
}
}
else
{
ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
}
return;
}
else if (hdr->IsProbeReq ()
|| hdr->IsAssocReq ())
{
//This is a frame aimed at an AP, so we can safely ignore it.
NotifyRxDrop (packet);
return;
}
else if (hdr->IsBeacon ())
{
MgtBeaconHeader beacon;
packet->RemoveHeader (beacon);
CapabilityInformation capabilities = beacon.GetCapabilities ();
bool goodBeacon = false;
if (GetSsid ().IsBroadcast ()
|| beacon.GetSsid ().IsEqual (GetSsid ()))
{
NS_LOG_LOGIC ("Beacon is for our SSID");
goodBeacon = true;
}
SupportedRates rates = beacon.GetSupportedRates ();
bool bssMembershipSelectorMatch = false;
for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
{
uint32_t selector = m_phy->GetBssMembershipSelector (i);
if (rates.IsBssMembershipSelectorRate (selector))
{
NS_LOG_LOGIC ("Beacon is matched to our BSS membership selector");
bssMembershipSelectorMatch = true;
}
}
if (m_phy->GetNBssMembershipSelectors () > 0 && bssMembershipSelectorMatch == false)
{
NS_LOG_LOGIC ("No match for BSS membership selector");
goodBeacon = false;
}
if ((IsWaitAssocResp () || IsAssociated ()) && hdr->GetAddr3 () != GetBssid ())
{
NS_LOG_LOGIC ("Beacon is not for us");
goodBeacon = false;
}
if (goodBeacon)
{
Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
RestartBeaconWatchdog (delay);
SetBssid (hdr->GetAddr3 ());
bool isShortPreambleEnabled = capabilities.IsShortPreamble ();
if (m_erpSupported)
{
ErpInformation erpInformation = beacon.GetErpInformation ();
isShortPreambleEnabled &= !erpInformation.GetBarkerPreambleMode ();
if (erpInformation.GetUseProtection() == true)
{
m_stationManager->SetUseNonErpProtection (true);
}
else
{
m_stationManager->SetUseNonErpProtection (false);
}
if (capabilities.IsShortSlotTime () == true)
{
//enable short slot time
SetSlot (MicroSeconds (9));
}
else
{
//disable short slot time
SetSlot (MicroSeconds (20));
}
}
// if (m_qosSupported)
// {
// EdcaParameterSet edcaParameters = beacon.GetEdcaParameterSet ();
// //The value of the TXOP Limit field is specified as an unsigned integer, with the least significant octet transmitted first, in units of 32 μs.
// SetEdcaParameters (AC_BE, edcaParameters.GetBeCWmin(), edcaParameters.GetBeCWmax(), edcaParameters.GetBeAifsn(), 32 * MicroSeconds (edcaParameters.GetBeTXOPLimit()));
// SetEdcaParameters (AC_BK, edcaParameters.GetBkCWmin(), edcaParameters.GetBkCWmax(), edcaParameters.GetBkAifsn(), 32 * MicroSeconds (edcaParameters.GetBkTXOPLimit()));
// SetEdcaParameters (AC_VI, edcaParameters.GetViCWmin(), edcaParameters.GetViCWmax(), edcaParameters.GetViAifsn(), 32 * MicroSeconds (edcaParameters.GetViTXOPLimit()));
// SetEdcaParameters (AC_VO, edcaParameters.GetVoCWmin(), edcaParameters.GetVoCWmax(), edcaParameters.GetVoAifsn(), 32 * MicroSeconds (edcaParameters.GetVoTXOPLimit()));
// }
m_stationManager->SetShortPreambleEnabled (isShortPreambleEnabled);
m_stationManager->SetShortSlotTimeEnabled (capabilities.IsShortSlotTime ());
}
if (goodBeacon && m_state == BEACON_MISSED)
{
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest ();
}
return;
}
else if (hdr->IsProbeResp ())
{
if (m_state == WAIT_PROBE_RESP)
{
MgtProbeResponseHeader probeResp;
packet->RemoveHeader (probeResp);
CapabilityInformation capabilities = probeResp.GetCapabilities ();
if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
{
//not a probe resp for our ssid.
return;
}
SupportedRates rates = probeResp.GetSupportedRates ();
for (uint32_t i = 0; i < m_phy->GetNBssMembershipSelectors (); i++)
{
uint32_t selector = m_phy->GetBssMembershipSelector (i);
if (!rates.IsSupportedRate (selector))
{
return;
}
}
for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
{
WifiMode mode = m_phy->GetMode (i);
uint8_t nss = 1; // Assume 1 spatial stream
if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, nss)))
{
m_stationManager->AddSupportedMode (hdr->GetAddr2 (), mode);
if (rates.IsBasicRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, nss)))
{
m_stationManager->AddBasicMode (mode);
}
}
}
bool isShortPreambleEnabled = capabilities.IsShortPreamble ();
if (m_erpSupported)
{
bool isErpAllowed = false;
for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
{
WifiMode mode = m_phy->GetMode (i);
if (mode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM && rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
{
isErpAllowed = true;
break;
}
}
if (!isErpAllowed)
{
//disable short slot time and set cwMin to 31
SetSlot (MicroSeconds (20));
//ConfigureContentionWindow (31, 1023);
}
else
{
ErpInformation erpInformation = probeResp.GetErpInformation ();
isShortPreambleEnabled &= !erpInformation.GetBarkerPreambleMode ();
if (m_stationManager->GetShortSlotTimeEnabled ())
{
//enable short slot time
SetSlot (MicroSeconds (9));
}
else
{
//disable short slot time
SetSlot (MicroSeconds (20));
}
//ConfigureContentionWindow (15, 1023);
}
}
m_stationManager->SetShortPreambleEnabled (isShortPreambleEnabled);
m_stationManager->SetShortSlotTimeEnabled (capabilities.IsShortSlotTime ());
SetBssid (hdr->GetAddr3 ());
Time delay = MicroSeconds (probeResp.GetBeaconIntervalUs () * m_maxMissedBeacons);
RestartBeaconWatchdog (delay);
if (m_probeRequestEvent.IsRunning ())
{
m_probeRequestEvent.Cancel ();
}
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest ();
}
return;
}
else if (hdr->IsAssocResp ())
{
if (m_state == WAIT_ASSOC_RESP)
{
MgtAssocResponseHeader assocResp;
packet->RemoveHeader (assocResp);
if (m_assocRequestEvent.IsRunning ())
{
m_assocRequestEvent.Cancel ();
}
if (assocResp.GetStatusCode ().IsSuccess ())
{
SetState (ASSOCIATED);
NS_LOG_DEBUG ("assoc completed");
CapabilityInformation capabilities = assocResp.GetCapabilities ();
SupportedRates rates = assocResp.GetSupportedRates ();
bool isShortPreambleEnabled = capabilities.IsShortPreamble ();
if (m_erpSupported)
{
bool isErpAllowed = false;
for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
{
WifiMode mode = m_phy->GetMode (i);
if (mode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM && rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth (), false, 1)))
{
isErpAllowed = true;
break;
}
}
if (!isErpAllowed)
{
//disable short slot time and set cwMin to 31
SetSlot (MicroSeconds (20));
//ConfigureContentionWindow (31, 1023);
}
else
{
ErpInformation erpInformation = assocResp.GetErpInformation ();
isShortPreambleEnabled &= !erpInformation.GetBarkerPreambleMode ();
if (m_stationManager->GetShortSlotTimeEnabled ())
{
//enable short slot time
SetSlot (MicroSeconds (9));
}
else
{
//disable short slot time
SetSlot (MicroSeconds (20));
}
//ConfigureContentionWindow (15, 1023);
}
}