wifi: (fixes #2831) trigger reassociation if PHY capabilities changed

This commit is contained in:
Sébastien Deronne
2018-02-23 23:11:17 +01:00
parent e136b8eb0a
commit 3acf9f511a
13 changed files with 883 additions and 73 deletions

View File

@@ -51,6 +51,7 @@ Bugs fixed
- Bug 2824 - ICMP opcode fr fragment timeout drop is wrong
- Bug 2828 - OLSR simple P2P example produces wrong results
- Bug 2827 - wifi: Active scanning not working with 802.11n/ac/ax
- Bug 2831 - wifi: runtime channel width switch has no effect
- Bug 2836 - wifi: Missing VHT information in radiotap header when A-MPDU is used
- Bug 2838 - wifi: ht-wifi-network crashes with RTS/CTS enabled and frequency set to 2.4GHz
- Bug 2843 - spectrum, wifi: Incorrect channel width and center frequency provided for non-HT PPDUs when building SpectralDensity

View File

@@ -719,11 +719,11 @@ ApWifiMac::SendProbeResp (Mac48Address to)
}
void
ApWifiMac::SendAssocResp (Mac48Address to, bool success)
ApWifiMac::SendAssocResp (Mac48Address to, bool success, bool isReassoc)
{
NS_LOG_FUNCTION (this << to << success);
NS_LOG_FUNCTION (this << to << success << isReassoc);
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_MGT_ASSOCIATION_RESPONSE);
hdr.SetType (isReassoc ? WIFI_MAC_MGT_REASSOCIATION_RESPONSE : WIFI_MAC_MGT_ASSOCIATION_RESPONSE);
hdr.SetAddr1 (to);
hdr.SetAddr2 (GetAddress ());
hdr.SetAddr3 (GetAddress ());
@@ -736,8 +736,25 @@ ApWifiMac::SendAssocResp (Mac48Address to, bool success)
if (success)
{
code.SetSuccess ();
uint16_t aid = GetNextAssociationId ();
m_staList.insert (std::make_pair (aid, to));
uint16_t aid;
bool found = false;
if (isReassoc)
{
for (std::map<uint16_t, Mac48Address>::const_iterator i = m_staList.begin (); i != m_staList.end (); ++i)
{
if (i->second == to)
{
aid = i->first;
found = true;
break;
}
}
}
if (!found)
{
aid = GetNextAssociationId ();
m_staList.insert (std::make_pair (aid, to));
}
assoc.SetAssociationId (aid);
}
else
@@ -857,8 +874,7 @@ ApWifiMac::TxOk (const WifiMacHeader &hdr)
{
NS_LOG_FUNCTION (this);
RegularWifiMac::TxOk (hdr);
if (hdr.IsAssocResp ()
if ((hdr.IsAssocResp () || hdr.IsReassocResp ())
&& m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
{
NS_LOG_DEBUG ("associated with sta=" << hdr.GetAddr1 ());
@@ -872,10 +888,10 @@ ApWifiMac::TxFailed (const WifiMacHeader &hdr)
NS_LOG_FUNCTION (this);
RegularWifiMac::TxFailed (hdr);
if (hdr.IsAssocResp ()
if ((hdr.IsAssocResp () || hdr.IsReassocResp ())
&& m_stationManager->IsWaitAssocTxOk (hdr.GetAddr1 ()))
{
NS_LOG_DEBUG ("assoc failed with sta=" << hdr.GetAddr1 ());
NS_LOG_DEBUG ("association failed with sta=" << hdr.GetAddr1 ());
m_stationManager->RecordGotAssocTxFailed (hdr.GetAddr1 ());
}
}
@@ -884,9 +900,7 @@ 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 ();
@@ -961,6 +975,7 @@ ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
if (hdr->IsProbeReq ())
{
NS_ASSERT (hdr->GetAddr1 ().IsBroadcast ());
NS_LOG_DEBUG ("Probe request received from " << from << ": send probe response");
SendProbeResp (from);
return;
}
@@ -968,6 +983,7 @@ ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
if (hdr->IsAssocReq ())
{
NS_LOG_DEBUG ("Association request received from " << from);
//first, verify that the the station's supported
//rate set is compatible with our Basic Rate set
MgtAssocRequestHeader assocReq;
@@ -1074,14 +1090,12 @@ ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
}
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);
NS_LOG_DEBUG ("One of the Basic Rate set mode is not supported by the station: send association response with an error status");
SendAssocResp (hdr->GetAddr2 (), false, false);
}
else
{
//station supports all rates in Basic Rate Set.
NS_LOG_DEBUG ("The Basic Rate set modes are supported by the station");
//record all its supported modes in its associated WifiRemoteStation
for (uint8_t j = 0; j < m_phy->GetNModes (); j++)
{
@@ -1136,18 +1150,202 @@ ApWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
if (!isHtStation)
{
m_nonHtStations.push_back (hdr->GetAddr2 ());
m_nonHtStations.unique ();
}
if (!isErpStation && isDsssStation)
{
m_nonErpStations.push_back (hdr->GetAddr2 ());
m_nonErpStations.unique ();
}
// send assoc response with success status.
SendAssocResp (hdr->GetAddr2 (), true);
NS_LOG_DEBUG ("Send association response with success status");
SendAssocResp (hdr->GetAddr2 (), true, false);
}
return;
}
else if (hdr->IsReassocReq ())
{
NS_LOG_DEBUG ("Reassociation request received from " << from);
//first, verify that the the station's supported
//rate set is compatible with our Basic Rate set
MgtReassocRequestHeader reassocReq;
packet->RemoveHeader (reassocReq);
CapabilityInformation capabilities = reassocReq.GetCapabilities ();
m_stationManager->AddSupportedPlcpPreamble (from, capabilities.IsShortPreamble ());
SupportedRates rates = reassocReq.GetSupportedRates ();
bool problem = false;
bool isHtStation = false;
bool isOfdmStation = false;
bool isErpStation = false;
bool isDsssStation = false;
for (uint8_t i = 0; i < m_stationManager->GetNBasicModes (); i++)
{
WifiMode mode = m_stationManager->GetBasicMode (i);
if (!rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth ())))
{
if ((mode.GetModulationClass () == WIFI_MOD_CLASS_DSSS) || (mode.GetModulationClass () == WIFI_MOD_CLASS_HR_DSSS))
{
isDsssStation = false;
}
else if (mode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM)
{
isErpStation = false;
}
else if (mode.GetModulationClass () == WIFI_MOD_CLASS_OFDM)
{
isOfdmStation = false;
}
if (isDsssStation == false && isErpStation == false && isOfdmStation == false)
{
problem = true;
break;
}
}
else
{
if ((mode.GetModulationClass () == WIFI_MOD_CLASS_DSSS) || (mode.GetModulationClass () == WIFI_MOD_CLASS_HR_DSSS))
{
isDsssStation = true;
}
else if (mode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM)
{
isErpStation = true;
}
else if (mode.GetModulationClass () == WIFI_MOD_CLASS_OFDM)
{
isOfdmStation = true;
}
}
}
m_stationManager->AddSupportedErpSlotTime (from, capabilities.IsShortSlotTime () && isErpStation);
if (m_htSupported)
{
//check whether the HT STA supports all MCSs in Basic MCS Set
HtCapabilities htcapabilities = reassocReq.GetHtCapabilities ();
if (htcapabilities.IsSupportedMcs (0))
{
isHtStation = true;
for (uint8_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 whether the VHT STA supports all MCSs in Basic MCS Set
VhtCapabilities vhtcapabilities = reassocReq.GetVhtCapabilities ();
if (vhtcapabilities.GetVhtCapabilitiesInfo () != 0)
{
for (uint8_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
{
WifiMode mcs = m_stationManager->GetBasicMcs (i);
if (!vhtcapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
{
problem = true;
break;
}
}
}
}
if (m_heSupported)
{
//check whether the HE STA supports all MCSs in Basic MCS Set
HeCapabilities hecapabilities = reassocReq.GetHeCapabilities ();
if (hecapabilities.GetSupportedMcsAndNss () != 0)
{
for (uint8_t i = 0; i < m_stationManager->GetNBasicMcs (); i++)
{
WifiMode mcs = m_stationManager->GetBasicMcs (i);
if (!hecapabilities.IsSupportedTxMcs (mcs.GetMcsValue ()))
{
problem = true;
break;
}
}
}
}
if (problem)
{
NS_LOG_DEBUG ("One of the Basic Rate set mode is not supported by the station: send reassociation response with an error status");
SendAssocResp (hdr->GetAddr2 (), false, true);
}
else
{
NS_LOG_DEBUG ("The Basic Rate set modes are supported by the station");
//update all its supported modes in its associated WifiRemoteStation
for (uint8_t j = 0; j < m_phy->GetNModes (); j++)
{
WifiMode mode = m_phy->GetMode (j);
if (rates.IsSupportedRate (mode.GetDataRate (m_phy->GetChannelWidth ())))
{
m_stationManager->AddSupportedMode (from, mode);
}
}
if (m_htSupported)
{
HtCapabilities htCapabilities = reassocReq.GetHtCapabilities ();
if (htCapabilities.IsSupportedMcs (0))
{
m_stationManager->AddStationHtCapabilities (from, htCapabilities);
}
}
if (m_vhtSupported)
{
VhtCapabilities vhtCapabilities = reassocReq.GetVhtCapabilities ();
//we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used to check whether it supports VHT
if (vhtCapabilities.GetRxHighestSupportedLgiDataRate () > 0)
{
m_stationManager->AddStationVhtCapabilities (from, vhtCapabilities);
for (uint8_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
}
}
}
}
if (m_heSupported)
{
HeCapabilities heCapabilities = reassocReq.GetHeCapabilities ();
//todo: once we support non constant rate managers, we should add checks here whether HE is supported by the peer
m_stationManager->AddStationHeCapabilities (from, heCapabilities);
for (uint8_t i = 0; i < m_phy->GetNMcs (); i++)
{
WifiMode mcs = m_phy->GetMcs (i);
if (mcs.GetModulationClass () == WIFI_MOD_CLASS_HE && heCapabilities.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);
if (!isHtStation)
{
m_nonHtStations.push_back (hdr->GetAddr2 ());
m_nonHtStations.unique ();
}
if (!isErpStation && isDsssStation)
{
m_nonErpStations.push_back (hdr->GetAddr2 ());
m_nonErpStations.unique ();
}
NS_LOG_DEBUG ("Send reassociation response with success status");
SendAssocResp (hdr->GetAddr2 (), true, true);
}
return;
}
else if (hdr->IsDisassociation ())
{
NS_LOG_DEBUG ("Disassociation received from " << from);
m_stationManager->RecordDisassociated (from);
for (std::map<uint16_t, Mac48Address>::const_iterator j = m_staList.begin (); j != m_staList.end (); j++)
{

View File

@@ -199,13 +199,15 @@ private:
*/
void SendProbeResp (Mac48Address to);
/**
* Forward an association response packet to the DCF. The standard is not clear on the correct
* queue for management frames if QoS is supported. We always use the DCF.
* Forward an association or a reassociation response packet to the DCF.
* The standard is not clear on the correct queue for management frames if QoS is supported.
* We always use the DCF.
*
* \param to the address of the STA we are sending an association response to
* \param success indicates whether the association was successful or not
* \param isReassoc indicates whether it is a reassociation response
*/
void SendAssocResp (Mac48Address to, bool success);
void SendAssocResp (Mac48Address to, bool success, bool isReassoc);
/**
* Forward a beacon packet to the beacon special DCF.
*/
@@ -300,7 +302,7 @@ private:
EventId m_beaconEvent; //!< Event to generate one beacon
Ptr<UniformRandomVariable> m_beaconJitter; //!< UniformRandomVariable used to randomize the time of the first beacon
bool m_enableBeaconJitter; //!< Flag whether the first beacon should be generated at random time
std::map<uint16_t, Mac48Address> m_staList;//!< Map of all stations currently associated to the AP with their association ID
std::map<uint16_t, Mac48Address> m_staList; //!< Map of all stations currently associated to the AP with their association ID
std::list<Mac48Address> m_nonErpStations; //!< List of all non-ERP stations currently associated to the AP
std::list<Mac48Address> m_nonHtStations; //!< List of all non-HT stations currently associated to the AP
bool m_enableNonErpProtection; //!< Flag whether protection mechanism is used or not when non-ERP STAs are present within the BSS

View File

@@ -686,7 +686,203 @@ MgtAssocRequestHeader::Deserialize (Buffer::Iterator start)
/***********************************************************
* Assoc Response
* Ressoc Request
***********************************************************/
NS_OBJECT_ENSURE_REGISTERED (MgtReassocRequestHeader);
MgtReassocRequestHeader::MgtReassocRequestHeader ()
: m_currentApAddr (Mac48Address ())
{
}
MgtReassocRequestHeader::~MgtReassocRequestHeader ()
{
}
void
MgtReassocRequestHeader::SetSsid (Ssid ssid)
{
m_ssid = ssid;
}
void
MgtReassocRequestHeader::SetSupportedRates (SupportedRates rates)
{
m_rates = rates;
}
void
MgtReassocRequestHeader::SetListenInterval (uint16_t interval)
{
m_listenInterval = interval;
}
void
MgtReassocRequestHeader::SetCapabilities (CapabilityInformation capabilities)
{
m_capability = capabilities;
}
CapabilityInformation
MgtReassocRequestHeader::GetCapabilities (void) const
{
return m_capability;
}
void
MgtReassocRequestHeader::SetExtendedCapabilities (ExtendedCapabilities extendedcapabilities)
{
m_extendedCapability = extendedcapabilities;
}
ExtendedCapabilities
MgtReassocRequestHeader::GetExtendedCapabilities (void) const
{
return m_extendedCapability;
}
void
MgtReassocRequestHeader::SetHtCapabilities (HtCapabilities htcapabilities)
{
m_htCapability = htcapabilities;
}
HtCapabilities
MgtReassocRequestHeader::GetHtCapabilities (void) const
{
return m_htCapability;
}
void
MgtReassocRequestHeader::SetVhtCapabilities (VhtCapabilities vhtcapabilities)
{
m_vhtCapability = vhtcapabilities;
}
VhtCapabilities
MgtReassocRequestHeader::GetVhtCapabilities (void) const
{
return m_vhtCapability;
}
void
MgtReassocRequestHeader::SetHeCapabilities (HeCapabilities hecapabilities)
{
m_heCapability = hecapabilities;
}
HeCapabilities
MgtReassocRequestHeader::GetHeCapabilities (void) const
{
return m_heCapability;
}
Ssid
MgtReassocRequestHeader::GetSsid (void) const
{
return m_ssid;
}
SupportedRates
MgtReassocRequestHeader::GetSupportedRates (void) const
{
return m_rates;
}
uint16_t
MgtReassocRequestHeader::GetListenInterval (void) const
{
return m_listenInterval;
}
void
MgtReassocRequestHeader::SetCurrentApAddress (Mac48Address currentApAddr)
{
m_currentApAddr = currentApAddr;
}
TypeId
MgtReassocRequestHeader::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::MgtReassocRequestHeader")
.SetParent<Header> ()
.SetGroupName ("Wifi")
.AddConstructor<MgtReassocRequestHeader> ()
;
return tid;
}
TypeId
MgtReassocRequestHeader::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
uint32_t
MgtReassocRequestHeader::GetSerializedSize (void) const
{
uint32_t size = 0;
size += m_capability.GetSerializedSize ();
size += 2; //listen interval
size += 6; //current AP address
size += m_ssid.GetSerializedSize ();
size += m_rates.GetSerializedSize ();
size += m_rates.extended.GetSerializedSize ();
size += m_extendedCapability.GetSerializedSize ();
size += m_htCapability.GetSerializedSize ();
size += m_vhtCapability.GetSerializedSize ();
size += m_heCapability.GetSerializedSize ();
return size;
}
void
MgtReassocRequestHeader::Print (std::ostream &os) const
{
os << "current AP address=" << m_currentApAddr << ", "
<< "ssid=" << m_ssid << ", "
<< "rates=" << m_rates << ", "
<< "HT Capabilities=" << m_htCapability << " , "
<< "VHT Capabilities=" << m_vhtCapability << " , "
<< "HE Capabilities=" << m_heCapability;
}
void
MgtReassocRequestHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
i = m_capability.Serialize (i);
i.WriteHtolsbU16 (m_listenInterval);
WriteTo (i, m_currentApAddr);
i = m_ssid.Serialize (i);
i = m_rates.Serialize (i);
i = m_rates.extended.Serialize (i);
i = m_extendedCapability.Serialize (i);
i = m_htCapability.Serialize (i);
i = m_vhtCapability.Serialize (i);
i = m_heCapability.Serialize (i);
}
uint32_t
MgtReassocRequestHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
i = m_capability.Deserialize (i);
m_listenInterval = i.ReadLsbtohU16 ();
ReadFrom (i, m_currentApAddr);
i = m_ssid.Deserialize (i);
i = m_rates.Deserialize (i);
i = m_rates.extended.DeserializeIfPresent (i);
i = m_extendedCapability.DeserializeIfPresent (i);
i = m_htCapability.DeserializeIfPresent (i);
i = m_vhtCapability.DeserializeIfPresent (i);
i = m_heCapability.DeserializeIfPresent (i);
return i.GetDistanceFrom (start);
}
/***********************************************************
* Assoc/Reassoc Response
***********************************************************/
NS_OBJECT_ENSURE_REGISTERED (MgtAssocResponseHeader);

View File

@@ -37,6 +37,7 @@
#include "edca-parameter-set.h"
#include "he-capabilities.h"
#include "he-operation.h"
#include "ns3/address-utils.h"
namespace ns3 {
@@ -173,7 +174,145 @@ private:
/**
* \ingroup wifi
* Implement the header for management frames of type association response.
* Implement the header for management frames of type reassociation request.
*/
class MgtReassocRequestHeader : public Header
{
public:
MgtReassocRequestHeader ();
~MgtReassocRequestHeader ();
/**
* Set the Service Set Identifier (SSID).
*
* \param ssid SSID
*/
void SetSsid (Ssid ssid);
/**
* Set the supported rates.
*
* \param rates the supported rates
*/
void SetSupportedRates (SupportedRates rates);
/**
* Set the listen interval.
*
* \param interval the listen interval
*/
void SetListenInterval (uint16_t interval);
/**
* Set the Capability information.
*
* \param capabilities Capability information
*/
void SetCapabilities (CapabilityInformation capabilities);
/**
* Set the Extended Capabilities.
*
* \param extendedcapabilities the Extended Capabilities
*/
void SetExtendedCapabilities (ExtendedCapabilities extendedcapabilities);
/**
* Set the HT capabilities.
*
* \param htcapabilities HT capabilities
*/
void SetHtCapabilities (HtCapabilities htcapabilities);
/**
* Set the VHT capabilities.
*
* \param vhtcapabilities VHT capabilities
*/
void SetVhtCapabilities (VhtCapabilities vhtcapabilities);
/**
* Set the HE capabilities.
*
* \param hecapabilities HE capabilities
*/
void SetHeCapabilities (HeCapabilities hecapabilities);
/**
* Return the Capability information.
*
* \return Capability information
*/
CapabilityInformation GetCapabilities (void) const;
/**
* Return the extended capabilities.
*
* \return the extended capabilities
*/
ExtendedCapabilities GetExtendedCapabilities (void) const;
/**
* Return the HT capabilities.
*
* \return HT capabilities
*/
HtCapabilities GetHtCapabilities (void) const;
/**
* Return the VHT capabilities.
*
* \return VHT capabilities
*/
VhtCapabilities GetVhtCapabilities (void) const;
/**
* Return the HE capabilities.
*
* \return HE capabilities
*/
HeCapabilities GetHeCapabilities (void) const;
/**
* Return the Service Set Identifier (SSID).
*
* \return SSID
*/
Ssid GetSsid (void) const;
/**
* Return the supported rates.
*
* \return the supported rates
*/
SupportedRates GetSupportedRates (void) const;
/**
* Return the listen interval.
*
* \return the listen interval
*/
uint16_t GetListenInterval (void) const;
/**
* Set the address of the current access point.
*
* \param currentApAddr address of the current access point
*/
void SetCurrentApAddress (Mac48Address currentApAddr);
/**
* Register this type.
* \return The TypeId.
*/
static TypeId GetTypeId (void);
TypeId GetInstanceTypeId (void) const;
void Print (std::ostream &os) const;
uint32_t GetSerializedSize (void) const;
void Serialize (Buffer::Iterator start) const;
uint32_t Deserialize (Buffer::Iterator start);
private:
Mac48Address m_currentApAddr; //!< Address of the current access point
Ssid m_ssid; //!< Service Set ID (SSID)
SupportedRates m_rates; //!< List of supported rates
CapabilityInformation m_capability; //!< Capability information
ExtendedCapabilities m_extendedCapability; //!< Extended capabilities
HtCapabilities m_htCapability; //!< HT capabilities
VhtCapabilities m_vhtCapability; //!< VHT capabilities
HeCapabilities m_heCapability; //!< HE capabilities
uint16_t m_listenInterval; //!< listen interval
};
/**
* \ingroup wifi
* Implement the header for management frames of type association and reassociation response.
*/
class MgtAssocResponseHeader : public Header
{

View File

@@ -1006,7 +1006,7 @@ RegularWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
void
RegularWifiMac::DeaggregateAmsduAndForward (Ptr<Packet> aggregatedPacket, const WifiMacHeader *hdr)
{
NS_LOG_FUNCTION(this << aggregatedPacket << hdr);
NS_LOG_FUNCTION (this << aggregatedPacket << hdr);
MsduAggregator::DeaggregatedMsdus packets = MsduAggregator::Deaggregate (aggregatedPacket);
for (MsduAggregator::DeaggregatedMsdusCI i = packets.begin ();
i != packets.end (); ++i)

View File

@@ -216,7 +216,7 @@ public:
/**
* \param phy the physical layer attached to this MAC.
*/
void SetWifiPhy (const Ptr<WifiPhy> phy);
virtual void SetWifiPhy (const Ptr<WifiPhy> phy);
/**
* \return the physical layer attached to this MAC.
*/

View File

@@ -58,7 +58,7 @@ StaWifiMac::GetTypeId (void)
TimeValue (Seconds (0.05)),
MakeTimeAccessor (&StaWifiMac::m_probeRequestTimeout),
MakeTimeChecker ())
.AddAttribute ("AssocRequestTimeout", "The interval between two consecutive assoc request attempts.",
.AddAttribute ("AssocRequestTimeout", "The interval between two consecutive association request attempts.",
TimeValue (Seconds (0.5)),
MakeTimeAccessor (&StaWifiMac::m_assocRequestTimeout),
MakeTimeChecker ())
@@ -120,11 +120,20 @@ StaWifiMac::SetActiveProbing (bool enable)
m_activeProbing = enable;
}
bool StaWifiMac::GetActiveProbing (void) const
bool
StaWifiMac::GetActiveProbing (void) const
{
return m_activeProbing;
}
void
StaWifiMac::SetWifiPhy (const Ptr<WifiPhy> phy)
{
NS_LOG_FUNCTION (this << phy);
RegularWifiMac::SetWifiPhy (phy);
m_phy->SetCapabilitiesChangedCallback (MakeCallback (&StaWifiMac::PhyCapabilitiesChanged, this));
}
void
StaWifiMac::SendProbeRequest (void)
{
@@ -171,11 +180,11 @@ StaWifiMac::SendProbeRequest (void)
}
void
StaWifiMac::SendAssociationRequest (void)
StaWifiMac::SendAssociationRequest (bool isReassoc)
{
NS_LOG_FUNCTION (this << GetBssid ());
NS_LOG_FUNCTION (this << GetBssid () << isReassoc);
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_MGT_ASSOCIATION_REQUEST);
hdr.SetType (isReassoc ? WIFI_MAC_MGT_REASSOCIATION_REQUEST : WIFI_MAC_MGT_ASSOCIATION_REQUEST);
hdr.SetAddr1 (GetBssid ());
hdr.SetAddr2 (GetAddress ());
hdr.SetAddr3 (GetBssid ());
@@ -183,24 +192,49 @@ StaWifiMac::SendAssociationRequest (void)
hdr.SetDsNotTo ();
hdr.SetNoOrder ();
Ptr<Packet> packet = Create<Packet> ();
MgtAssocRequestHeader assoc;
assoc.SetSsid (GetSsid ());
assoc.SetSupportedRates (GetSupportedRates ());
assoc.SetCapabilities (GetCapabilities ());
if (m_htSupported || m_vhtSupported || m_heSupported)
if (!isReassoc)
{
assoc.SetExtendedCapabilities (GetExtendedCapabilities ());
assoc.SetHtCapabilities (GetHtCapabilities ());
MgtAssocRequestHeader assoc;
assoc.SetSsid (GetSsid ());
assoc.SetSupportedRates (GetSupportedRates ());
assoc.SetCapabilities (GetCapabilities ());
if (m_htSupported || m_vhtSupported || m_heSupported)
{
assoc.SetExtendedCapabilities (GetExtendedCapabilities ());
assoc.SetHtCapabilities (GetHtCapabilities ());
}
if (m_vhtSupported || m_heSupported)
{
assoc.SetVhtCapabilities (GetVhtCapabilities ());
}
if (m_heSupported)
{
assoc.SetHeCapabilities (GetHeCapabilities ());
}
packet->AddHeader (assoc);
}
if (m_vhtSupported || m_heSupported)
else
{
assoc.SetVhtCapabilities (GetVhtCapabilities ());
MgtReassocRequestHeader reassoc;
reassoc.SetCurrentApAddress (GetBssid ());
reassoc.SetSsid (GetSsid ());
reassoc.SetSupportedRates (GetSupportedRates ());
reassoc.SetCapabilities (GetCapabilities ());
if (m_htSupported || m_vhtSupported || m_heSupported)
{
reassoc.SetExtendedCapabilities (GetExtendedCapabilities ());
reassoc.SetHtCapabilities (GetHtCapabilities ());
}
if (m_vhtSupported || m_heSupported)
{
reassoc.SetVhtCapabilities (GetVhtCapabilities ());
}
if (m_heSupported)
{
reassoc.SetHeCapabilities (GetHeCapabilities ());
}
packet->AddHeader (reassoc);
}
if (m_heSupported)
{
assoc.SetHeCapabilities (GetHeCapabilities ());
}
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
@@ -245,15 +279,15 @@ StaWifiMac::TryToEnsureAssociated (void)
}
break;
case WAIT_ASSOC_RESP:
/* we have sent an assoc request so we do not need to
re-send an assoc request right now. We just need to
/* we have sent an association request so we do not need to
re-send an association request right now. We just need to
wait until either assoc-request-timeout or until
we get an assoc response.
we get an association response.
*/
break;
case REFUSED:
/* we have sent an assoc request and received a negative
assoc resp. We wait until someone restarts an
/* we have sent an association request and received a negative
association response. We wait until someone restarts an
association with a given ssid.
*/
break;
@@ -265,7 +299,7 @@ StaWifiMac::AssocRequestTimeout (void)
{
NS_LOG_FUNCTION (this);
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest ();
SendAssociationRequest (false);
}
void
@@ -447,7 +481,8 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
return;
}
else if (hdr->IsProbeReq ()
|| hdr->IsAssocReq ())
|| hdr->IsAssocReq ()
|| hdr->IsReassocReq ())
{
//This is a frame aimed at an AP, so we can safely ignore it.
NotifyRxDrop (packet);
@@ -455,6 +490,7 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
}
else if (hdr->IsBeacon ())
{
NS_LOG_DEBUG ("Beacon received");
MgtBeaconHeader beacon;
packet->RemoveHeader (beacon);
CapabilityInformation capabilities = beacon.GetCapabilities ();
@@ -608,7 +644,8 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
if (goodBeacon && m_state == BEACON_MISSED)
{
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest ();
NS_LOG_DEBUG ("Good beacon received: send association request");
SendAssociationRequest (false);
}
return;
}
@@ -616,12 +653,13 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
if (m_state == WAIT_PROBE_RESP)
{
NS_LOG_DEBUG ("Probe response received");
MgtProbeResponseHeader probeResp;
packet->RemoveHeader (probeResp);
CapabilityInformation capabilities = probeResp.GetCapabilities ();
if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
{
//not a probe resp for our ssid.
NS_LOG_DEBUG ("Probe response is not for our SSID");
return;
}
SupportedRates rates = probeResp.GetSupportedRates ();
@@ -630,6 +668,7 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
uint8_t selector = m_phy->GetBssMembershipSelector (i);
if (!rates.IsBssMembershipSelectorRate (selector))
{
NS_LOG_DEBUG ("Supported rates do not fit with the BSS membership selector");
return;
}
}
@@ -692,11 +731,11 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
m_probeRequestEvent.Cancel ();
}
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest ();
SendAssociationRequest (false);
}
return;
}
else if (hdr->IsAssocResp ())
else if (hdr->IsAssocResp () || hdr->IsReassocResp ())
{
if (m_state == WAIT_ASSOC_RESP)
{
@@ -709,7 +748,14 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
if (assocResp.GetStatusCode ().IsSuccess ())
{
SetState (ASSOCIATED);
NS_LOG_DEBUG ("assoc completed");
if (hdr->IsReassocResp ())
{
NS_LOG_DEBUG ("reassociation done");
}
else
{
NS_LOG_DEBUG ("association completed");
}
CapabilityInformation capabilities = assocResp.GetCapabilities ();
SupportedRates rates = assocResp.GetSupportedRates ();
bool isShortPreambleEnabled = capabilities.IsShortPreamble ();
@@ -869,7 +915,7 @@ StaWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
}
else
{
NS_LOG_DEBUG ("assoc refused");
NS_LOG_DEBUG ("association refused");
SetState (REFUSED);
}
}
@@ -938,4 +984,16 @@ StaWifiMac::SetEdcaParameters (AcIndex ac, uint32_t cwMin, uint32_t cwMax, uint8
edca->SetTxopLimit (txopLimit);
}
void
StaWifiMac::PhyCapabilitiesChanged (void)
{
NS_LOG_FUNCTION (this);
if (IsAssociated ())
{
NS_LOG_DEBUG ("PHY capabilities changed: send reassociation request");
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest (true);
}
}
} //namespace ns3

View File

@@ -58,6 +58,11 @@ public:
*/
void Enqueue (Ptr<const Packet> packet, Mac48Address to);
/**
* \param phy the physical layer attached to this MAC.
*/
void SetWifiPhy (const Ptr<WifiPhy> phy);
private:
/**
@@ -93,10 +98,14 @@ private:
*/
void SendProbeRequest (void);
/**
* Forward an association request packet to the DCF. The standard is not clear on the correct
* queue for management frames if QoS is supported. We always use the DCF.
* Forward an association or reassociation request packet to the DCF.
* The standard is not clear on the correct queue for management frames if QoS is supported.
* We always use the DCF.
*
* \param isReassoc flag whether it is a reassociation request
*
*/
void SendAssociationRequest (void);
void SendAssociationRequest (bool isReassoc);
/**
* Try to ensure that we are associated with an AP by taking an appropriate action
* depending on the current association status.
@@ -164,6 +173,11 @@ private:
*/
CapabilityInformation GetCapabilities (void) const;
/**
* Indicate that PHY capabilities have changed.
*/
void PhyCapabilitiesChanged (void);
MacState m_state; ///< MAC state
Time m_probeRequestTimeout; ///< probe request timeout
Time m_assocRequestTimeout; ///< assoc request timeout

View File

@@ -98,6 +98,7 @@ WifiNetDevice::DoDispose (void)
void
WifiNetDevice::DoInitialize (void)
{
NS_LOG_FUNCTION_NOARGS ();
m_phy->Initialize ();
m_mac->Initialize ();
m_stationManager->Initialize ();
@@ -140,7 +141,7 @@ WifiNetDevice::NotifyNewAggregate (void)
// register the select queue callback
m_queueInterface->SetSelectQueueCallback (MakeCallback (&WifiNetDevice::SelectQueue, this));
m_queueInterface->SetLateTxQueuesCreation (true);
FlowControlConfig ();
FlowControlConfig ();
}
}
NetDevice::NotifyNewAggregate ();

View File

@@ -434,6 +434,12 @@ WifiPhy::UnregisterListener (WifiPhyListener *listener)
m_state->UnregisterListener (listener);
}
void
WifiPhy::SetCapabilitiesChangedCallback (Callback<void> callback)
{
m_capabilitiesChangedCallback = callback;
}
void
WifiPhy::InitializeFrequencyChannelNumber (void)
{
@@ -537,7 +543,7 @@ WifiPhy::GetTxPowerEnd (void) const
void
WifiPhy::SetNTxPower (uint8_t n)
{
NS_LOG_FUNCTION (this << static_cast<uint16_t>(n));
NS_LOG_FUNCTION (this << static_cast<uint16_t> (n));
m_nTxPower = n;
}
@@ -707,7 +713,7 @@ WifiPhy::GetFrameCaptureModel (void) const
{
return m_frameCaptureModel;
}
void
WifiPhy::SetWifiRadioEnergyModel (const Ptr<WifiRadioEnergyModel> wifiRadioEnergyModel)
{
@@ -1267,9 +1273,15 @@ WifiPhy::GetFrequency (void) const
void
WifiPhy::SetChannelWidth (uint8_t channelwidth)
{
NS_LOG_FUNCTION (this << static_cast<uint16_t> (channelwidth));
NS_ASSERT_MSG (channelwidth == 5 || channelwidth == 10 || channelwidth == 20 || channelwidth == 22 || channelwidth == 40 || channelwidth == 80 || channelwidth == 160, "wrong channel width value");
bool changed = (m_channelWidth == channelwidth);
m_channelWidth = channelwidth;
AddSupportedChannelWidth (channelwidth);
if (changed && !m_capabilitiesChangedCallback.IsNull ())
{
m_capabilitiesChangedCallback ();
}
}
uint8_t
@@ -1296,8 +1308,13 @@ void
WifiPhy::SetMaxSupportedTxSpatialStreams (uint8_t streams)
{
NS_ASSERT (streams <= GetNumberOfAntennas ());
bool changed = (m_txSpatialStreams == streams);
m_txSpatialStreams = streams;
ConfigureHtDeviceMcsSet ();
if (changed && !m_capabilitiesChangedCallback.IsNull ())
{
m_capabilitiesChangedCallback ();
}
}
uint8_t
@@ -1310,7 +1327,12 @@ void
WifiPhy::SetMaxSupportedRxSpatialStreams (uint8_t streams)
{
NS_ASSERT (streams <= GetNumberOfAntennas ());
bool changed = (m_rxSpatialStreams == streams);
m_rxSpatialStreams = streams;
if (changed && !m_capabilitiesChangedCallback.IsNull ())
{
m_capabilitiesChangedCallback ();
}
}
uint8_t
@@ -2398,10 +2420,10 @@ WifiPhy::StartReceivePreambleAndHeader (Ptr<Packet> packet, double rxPowerW, Tim
if (tag.GetFrameComplete () == 0)
{
NS_LOG_DEBUG ("drop packet because of incomplete frame");
NotifyRxDrop (packet);
m_plcpSuccess = false;
return;
NS_LOG_DEBUG ("drop packet because of incomplete frame");
NotifyRxDrop (packet);
m_plcpSuccess = false;
return;
}
WifiTxVector txVector = tag.GetWifiTxVector ();

View File

@@ -53,7 +53,7 @@ class FrameCaptureModel;
* WifiRadioEnergyModel class
*/
class WifiRadioEnergyModel;
/**
* This enumeration defines the type of an MPDU.
*/
@@ -257,6 +257,11 @@ public:
*/
void UnregisterListener (WifiPhyListener *listener);
/**
* \param callback the callback to invoke when PHY capabilities have changed.
*/
void SetCapabilitiesChangedCallback (Callback<void> callback);
/**
* Starting receiving the plcp of a packet (i.e. the first bit of the preamble has arrived).
*
@@ -353,7 +358,7 @@ public:
/**
* \return true if the current state of the PHY layer is WifiPhy::OFF, false otherwise.
*/
bool IsStateOff (void) const ;
bool IsStateOff (void) const;
/**
* \return the amount of time since the current state has started.
@@ -1798,7 +1803,7 @@ private:
* \return the FrequencyWidthPair found
*/
FrequencyWidthPair GetFrequencyWidthForChannelNumberStandard (uint8_t channelNumber, WifiPhyStandard standard) const;
/**
* Due to newly arrived signal, the current reception cannot be continued and has to be aborted
*
@@ -1809,7 +1814,7 @@ private:
* Eventually switch to CCA busy
*/
void MaybeCcaBusyDuration (void);
/**
* Starting receiving the packet after having detected the medium is idle or after a reception switch.
*
@@ -1987,6 +1992,8 @@ private:
Ptr<InterferenceHelper::Event> m_currentEvent; //!< Hold the current event
Ptr<FrameCaptureModel> m_frameCaptureModel; //!< Frame capture model
Ptr<WifiRadioEnergyModel> m_wifiRadioEnergyModel; //!< Wifi radio energy model
Callback<void> m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed
};
/**

View File

@@ -1283,7 +1283,7 @@ Bug2483TestCase::DoRun (void)
spectrumChannel->AddPropagationLossModel (lossModel);
Ptr<ConstantSpeedPropagationDelayModel> delayModel
= CreateObject<ConstantSpeedPropagationDelayModel> ();
= CreateObject<ConstantSpeedPropagationDelayModel> ();
spectrumChannel->SetPropagationDelayModel (delayModel);
spectrumPhy.SetChannel (spectrumChannel);
@@ -1343,6 +1343,177 @@ Bug2483TestCase::DoRun (void)
NS_TEST_ASSERT_MSG_EQ (std::get<3> (m_distinctTuples[1]), WifiModulationClass::WIFI_MOD_CLASS_VHT, "Second tuple should be VHT_OFDM");
}
//-----------------------------------------------------------------------------
/**
* Make sure that the channel width and the channel number can be changed at runtime.
*
* The scenario considers an access point and a station using a 20 MHz channel width.
* After 1s, we change the channel width and the channel number to use a 40 MHz channel.
* The tests checks the operational channel width sent in Beacon frames
* and verify that a reassociation procedure is executed.
*
* See \bugid{2831}
*/
class Bug2831TestCase : public TestCase
{
public:
Bug2831TestCase ();
virtual ~Bug2831TestCase ();
virtual void DoRun (void);
private:
/**
* Function called to change the supported channel width at runtime
*/
void ChangeSupportedChannelWidth (void);
/**
* Callback triggered when a packet is received by the PHYs
* \param context the context
* \param p the received packet
*/
void RxCallback (std::string context, Ptr<const Packet> p);
Ptr<YansWifiPhy> m_apPhy; ///< AP PHY
Ptr<YansWifiPhy> m_staPhy; ///< STA PHY
uint8_t m_reassocReqCount; ///< count number of reassociation requests
uint8_t m_reassocRespCount; ///< count number of reassociation responses
uint8_t m_countOperationalChannelWidth20; ///< count number of beacon frames announcing a 20 MHz operating channel width
uint8_t m_countOperationalChannelWidth40; ///< count number of beacon frames announcing a 40 MHz operating channel width
};
Bug2831TestCase::Bug2831TestCase ()
: TestCase ("Test case for Bug 2831"),
m_reassocReqCount (0),
m_reassocRespCount (0),
m_countOperationalChannelWidth20 (0),
m_countOperationalChannelWidth40 (0)
{
}
Bug2831TestCase::~Bug2831TestCase ()
{
}
void
Bug2831TestCase::ChangeSupportedChannelWidth ()
{
m_apPhy->SetChannelNumber (38);
m_apPhy->SetChannelWidth (40);
m_staPhy->SetChannelNumber (38);
m_staPhy->SetChannelWidth (40);
}
void
Bug2831TestCase::RxCallback (std::string context, Ptr<const Packet> p)
{
Ptr<Packet> packet = p->Copy ();
WifiMacHeader hdr;
packet->RemoveHeader (hdr);
if (hdr.IsReassocReq ())
{
m_reassocReqCount++;
}
else if (hdr.IsReassocResp ())
{
m_reassocRespCount++;
}
else if (hdr.IsBeacon ())
{
MgtBeaconHeader beacon;
packet->RemoveHeader (beacon);
HtOperation htOperation = beacon.GetHtOperation ();
if (htOperation.GetStaChannelWidth () > 0)
{
m_countOperationalChannelWidth40++;
}
else
{
m_countOperationalChannelWidth20++;
}
}
}
void
Bug2831TestCase::DoRun (void)
{
Ptr<YansWifiChannel> channel = CreateObject<YansWifiChannel> ();
ObjectFactory propDelay;
propDelay.SetTypeId ("ns3::ConstantSpeedPropagationDelayModel");
Ptr<PropagationDelayModel> propagationDelay = propDelay.Create<PropagationDelayModel> ();
Ptr<PropagationLossModel> propagationLoss = CreateObject<RandomPropagationLossModel> ();
channel->SetPropagationDelayModel (propagationDelay);
channel->SetPropagationLossModel (propagationLoss);
Ptr<Node> apNode = CreateObject<Node> ();
Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice> ();
ObjectFactory mac;
mac.SetTypeId ("ns3::ApWifiMac");
Ptr<WifiMac> apMac = mac.Create<WifiMac> ();
apMac->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ);
Ptr<Node> staNode = CreateObject<Node> ();
Ptr<WifiNetDevice> staDev = CreateObject<WifiNetDevice> ();
mac.SetTypeId ("ns3::StaWifiMac");
Ptr<WifiMac> staMac = mac.Create<WifiMac> ();
staMac->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ);
Ptr<ConstantPositionMobilityModel> apMobility = CreateObject<ConstantPositionMobilityModel> ();
apMobility->SetPosition (Vector (0.0, 0.0, 0.0));
apNode->AggregateObject (apMobility);
Ptr<ErrorRateModel> error = CreateObject<YansErrorRateModel> ();
m_apPhy = CreateObject<YansWifiPhy> ();
m_apPhy->SetErrorRateModel (error);
m_apPhy->SetChannel (channel);
m_apPhy->SetMobility (apMobility);
m_apPhy->SetDevice (apDev);
m_apPhy->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ);
m_apPhy->SetChannelNumber (36);
m_apPhy->SetChannelWidth (20);
Ptr<ConstantPositionMobilityModel> staMobility = CreateObject<ConstantPositionMobilityModel> ();
staMobility->SetPosition (Vector (1.0, 0.0, 0.0));
staNode->AggregateObject (staMobility);
m_staPhy = CreateObject<YansWifiPhy> ();
m_staPhy->SetErrorRateModel (error);
m_staPhy->SetChannel (channel);
m_staPhy->SetMobility (staMobility);
m_staPhy->SetDevice (apDev);
m_staPhy->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ);
m_staPhy->SetChannelNumber (36);
m_staPhy->SetChannelWidth (20);
apMac->SetAddress (Mac48Address::Allocate ());
apDev->SetMac (apMac);
apDev->SetPhy (m_apPhy);
ObjectFactory manager;
manager.SetTypeId ("ns3::ConstantRateWifiManager");
apDev->SetRemoteStationManager (manager.Create<WifiRemoteStationManager> ());
apNode->AddDevice (apDev);
staMac->SetAddress (Mac48Address::Allocate ());
staDev->SetMac (staMac);
staDev->SetPhy (m_staPhy);
staDev->SetRemoteStationManager (manager.Create<WifiRemoteStationManager> ());
staNode->AddDevice (staDev);
Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/PhyRxBegin", MakeCallback (&Bug2831TestCase::RxCallback, this));
Simulator::Schedule (Seconds (1.0), &Bug2831TestCase::ChangeSupportedChannelWidth, this);
Simulator::Stop (Seconds (3.0));
Simulator::Run ();
Simulator::Destroy ();
NS_TEST_ASSERT_MSG_EQ (m_reassocReqCount, 1, "Reassociation request not received");
NS_TEST_ASSERT_MSG_EQ (m_reassocRespCount, 1, "Reassociation response not received");
NS_TEST_ASSERT_MSG_EQ (m_countOperationalChannelWidth20, 10, "Incorrect operational channel width before channel change");
NS_TEST_ASSERT_MSG_EQ (m_countOperationalChannelWidth40, 20, "Incorrect operational channel width after channel change");
}
/**
* \ingroup wifi-test
* \ingroup tests
@@ -1366,6 +1537,7 @@ WifiTestSuite::WifiTestSuite ()
AddTestCase (new SetChannelFrequencyTest, TestCase::QUICK);
AddTestCase (new Bug2222TestCase, TestCase::QUICK); //Bug 2222
AddTestCase (new Bug2483TestCase, TestCase::QUICK); //Bug 2483
AddTestCase (new Bug2831TestCase, TestCase::QUICK); //Bug 2831
}
static WifiTestSuite g_wifiTestSuite; ///< the test suite