diff --git a/RELEASE_NOTES b/RELEASE_NOTES index a8bf6e9ca..8977ea3db 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -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 diff --git a/src/wifi/model/ap-wifi-mac.cc b/src/wifi/model/ap-wifi-mac.cc index d7586509f..f846b8649 100644 --- a/src/wifi/model/ap-wifi-mac.cc +++ b/src/wifi/model/ap-wifi-mac.cc @@ -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::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, 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, 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, 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, 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, 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::const_iterator j = m_staList.begin (); j != m_staList.end (); j++) { diff --git a/src/wifi/model/ap-wifi-mac.h b/src/wifi/model/ap-wifi-mac.h index e3f7a3b43..123613a6b 100644 --- a/src/wifi/model/ap-wifi-mac.h +++ b/src/wifi/model/ap-wifi-mac.h @@ -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 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 m_staList;//!< Map of all stations currently associated to the AP with their association ID + std::map m_staList; //!< Map of all stations currently associated to the AP with their association ID std::list m_nonErpStations; //!< List of all non-ERP stations currently associated to the AP std::list 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 diff --git a/src/wifi/model/mgt-headers.cc b/src/wifi/model/mgt-headers.cc index 1c1993e69..296aa8de1 100644 --- a/src/wifi/model/mgt-headers.cc +++ b/src/wifi/model/mgt-headers.cc @@ -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
() + .SetGroupName ("Wifi") + .AddConstructor () + ; + 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); diff --git a/src/wifi/model/mgt-headers.h b/src/wifi/model/mgt-headers.h index 033fee0d4..3d48d9794 100644 --- a/src/wifi/model/mgt-headers.h +++ b/src/wifi/model/mgt-headers.h @@ -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 { diff --git a/src/wifi/model/regular-wifi-mac.cc b/src/wifi/model/regular-wifi-mac.cc index a75dc98be..0b3f6fe2e 100644 --- a/src/wifi/model/regular-wifi-mac.cc +++ b/src/wifi/model/regular-wifi-mac.cc @@ -1006,7 +1006,7 @@ RegularWifiMac::Receive (Ptr packet, const WifiMacHeader *hdr) void RegularWifiMac::DeaggregateAmsduAndForward (Ptr 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) diff --git a/src/wifi/model/regular-wifi-mac.h b/src/wifi/model/regular-wifi-mac.h index cfcc8a143..434138267 100644 --- a/src/wifi/model/regular-wifi-mac.h +++ b/src/wifi/model/regular-wifi-mac.h @@ -216,7 +216,7 @@ public: /** * \param phy the physical layer attached to this MAC. */ - void SetWifiPhy (const Ptr phy); + virtual void SetWifiPhy (const Ptr phy); /** * \return the physical layer attached to this MAC. */ diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index ca88d80e5..beb54e7d9 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -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 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 = Create (); - 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, 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, 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, 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, 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, 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, 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, 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, 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 diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index 7d37bbfb6..81d184c66 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -58,6 +58,11 @@ public: */ void Enqueue (Ptr packet, Mac48Address to); + /** + * \param phy the physical layer attached to this MAC. + */ + void SetWifiPhy (const Ptr 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 diff --git a/src/wifi/model/wifi-net-device.cc b/src/wifi/model/wifi-net-device.cc index ea6456374..d1f5fb0dd 100644 --- a/src/wifi/model/wifi-net-device.cc +++ b/src/wifi/model/wifi-net-device.cc @@ -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 (); diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index bf00253d4..6cdfd6fc6 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -434,6 +434,12 @@ WifiPhy::UnregisterListener (WifiPhyListener *listener) m_state->UnregisterListener (listener); } +void +WifiPhy::SetCapabilitiesChangedCallback (Callback 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(n)); + NS_LOG_FUNCTION (this << static_cast (n)); m_nTxPower = n; } @@ -707,7 +713,7 @@ WifiPhy::GetFrameCaptureModel (void) const { return m_frameCaptureModel; } - + void WifiPhy::SetWifiRadioEnergyModel (const Ptr wifiRadioEnergyModel) { @@ -1267,9 +1273,15 @@ WifiPhy::GetFrequency (void) const void WifiPhy::SetChannelWidth (uint8_t channelwidth) { + NS_LOG_FUNCTION (this << static_cast (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, 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 (); diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 9c7c2d040..eead34efb 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -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 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 m_currentEvent; //!< Hold the current event Ptr m_frameCaptureModel; //!< Frame capture model Ptr m_wifiRadioEnergyModel; //!< Wifi radio energy model + + Callback m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed }; /** diff --git a/src/wifi/test/wifi-test.cc b/src/wifi/test/wifi-test.cc index 624979063..0ada2e82c 100644 --- a/src/wifi/test/wifi-test.cc +++ b/src/wifi/test/wifi-test.cc @@ -1283,7 +1283,7 @@ Bug2483TestCase::DoRun (void) spectrumChannel->AddPropagationLossModel (lossModel); Ptr delayModel - = CreateObject (); + = CreateObject (); 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 p); + + Ptr m_apPhy; ///< AP PHY + Ptr 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 p) +{ + Ptr 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 channel = CreateObject (); + ObjectFactory propDelay; + propDelay.SetTypeId ("ns3::ConstantSpeedPropagationDelayModel"); + Ptr propagationDelay = propDelay.Create (); + Ptr propagationLoss = CreateObject (); + channel->SetPropagationDelayModel (propagationDelay); + channel->SetPropagationLossModel (propagationLoss); + + Ptr apNode = CreateObject (); + Ptr apDev = CreateObject (); + ObjectFactory mac; + mac.SetTypeId ("ns3::ApWifiMac"); + Ptr apMac = mac.Create (); + apMac->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ); + + Ptr staNode = CreateObject (); + Ptr staDev = CreateObject (); + mac.SetTypeId ("ns3::StaWifiMac"); + Ptr staMac = mac.Create (); + staMac->ConfigureStandard (WIFI_PHY_STANDARD_80211n_5GHZ); + + Ptr apMobility = CreateObject (); + apMobility->SetPosition (Vector (0.0, 0.0, 0.0)); + apNode->AggregateObject (apMobility); + + Ptr error = CreateObject (); + m_apPhy = CreateObject (); + 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 staMobility = CreateObject (); + staMobility->SetPosition (Vector (1.0, 0.0, 0.0)); + staNode->AggregateObject (staMobility); + + m_staPhy = CreateObject (); + 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 ()); + apNode->AddDevice (apDev); + + staMac->SetAddress (Mac48Address::Allocate ()); + staDev->SetMac (staMac); + staDev->SetPhy (m_staPhy); + staDev->SetRemoteStationManager (manager.Create ()); + 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