diff -r 23aa339aecd6 src/wifi/model/ap-wifi-mac.cc --- a/src/wifi/model/ap-wifi-mac.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/ap-wifi-mac.cc Tue Feb 20 21:39:57 2018 +0100 @@ -719,11 +719,11 @@ } 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ } 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 @@ 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 -r 23aa339aecd6 src/wifi/model/ap-wifi-mac.h --- a/src/wifi/model/ap-wifi-mac.h Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/ap-wifi-mac.h Tue Feb 20 21:39:57 2018 +0100 @@ -199,13 +199,15 @@ */ 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. */ diff -r 23aa339aecd6 src/wifi/model/mgt-headers.cc --- a/src/wifi/model/mgt-headers.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/mgt-headers.cc Tue Feb 20 21:39:57 2018 +0100 @@ -686,7 +686,203 @@ /*********************************************************** - * 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 -r 23aa339aecd6 src/wifi/model/mgt-headers.h --- a/src/wifi/model/mgt-headers.h Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/mgt-headers.h Tue Feb 20 21:39:57 2018 +0100 @@ -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 @@ /** * \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 -r 23aa339aecd6 src/wifi/model/regular-wifi-mac.h --- a/src/wifi/model/regular-wifi-mac.h Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/regular-wifi-mac.h Tue Feb 20 21:39:57 2018 +0100 @@ -216,7 +216,7 @@ /** * \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 -r 23aa339aecd6 src/wifi/model/sta-wifi-mac.cc --- a/src/wifi/model/sta-wifi-mac.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/sta-wifi-mac.cc Tue Feb 20 21:39:57 2018 +0100 @@ -58,7 +58,7 @@ 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,12 +120,21 @@ 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) { NS_LOG_FUNCTION (this); @@ -171,11 +180,11 @@ } 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 @@ 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 @@ } 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 @@ { NS_LOG_FUNCTION (this); SetState (WAIT_ASSOC_RESP); - SendAssociationRequest (); + SendAssociationRequest (false); } void @@ -447,7 +481,8 @@ 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 @@ } else if (hdr->IsBeacon ()) { + NS_LOG_DEBUG ("Beacon received"); MgtBeaconHeader beacon; packet->RemoveHeader (beacon); CapabilityInformation capabilities = beacon.GetCapabilities (); @@ -608,7 +644,8 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ } else { - NS_LOG_DEBUG ("assoc refused"); + NS_LOG_DEBUG ("association refused"); SetState (REFUSED); } } @@ -938,4 +984,16 @@ 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 -r 23aa339aecd6 src/wifi/model/sta-wifi-mac.h --- a/src/wifi/model/sta-wifi-mac.h Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/sta-wifi-mac.h Tue Feb 20 21:39:57 2018 +0100 @@ -58,6 +58,11 @@ */ 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 @@ */ 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 @@ */ 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 -r 23aa339aecd6 src/wifi/model/wifi-net-device.cc --- a/src/wifi/model/wifi-net-device.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/wifi-net-device.cc Tue Feb 20 21:39:57 2018 +0100 @@ -98,6 +98,7 @@ void WifiNetDevice::DoInitialize (void) { + NS_LOG_FUNCTION_NOARGS (); m_phy->Initialize (); m_mac->Initialize (); m_stationManager->Initialize (); diff -r 23aa339aecd6 src/wifi/model/wifi-phy.cc --- a/src/wifi/model/wifi-phy.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/wifi-phy.cc Tue Feb 20 21:39:57 2018 +0100 @@ -435,6 +435,12 @@ } void +WifiPhy::SetCapabilitiesChangedCallback (Callback callback) +{ + m_capabilitiesChangedCallback = callback; +} + +void WifiPhy::InitializeFrequencyChannelNumber (void) { NS_LOG_FUNCTION (this); @@ -1267,9 +1273,15 @@ 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 @@ 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 @@ 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 diff -r 23aa339aecd6 src/wifi/model/wifi-phy.h --- a/src/wifi/model/wifi-phy.h Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/model/wifi-phy.h Tue Feb 20 21:39:57 2018 +0100 @@ -258,6 +258,11 @@ 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). * * \param packet the arriving packet @@ -1987,6 +1992,8 @@ 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 -r 23aa339aecd6 src/wifi/test/wifi-test.cc --- a/src/wifi/test/wifi-test.cc Tue Feb 20 12:52:37 2018 +0100 +++ b/src/wifi/test/wifi-test.cc Tue Feb 20 21:39:57 2018 +0100 @@ -1343,6 +1343,169 @@ 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: + void ChangeSupportedChannelWidth (void); + void RxCallback (std::string context, Ptr p); + + Ptr m_apPhy; + Ptr m_staPhy; + + uint8_t m_reassocReqCount; + uint8_t m_reassocRespCount; + uint8_t m_countOperationalChannelWidth20; + uint8_t m_countOperationalChannelWidth40; +}; + +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 +1529,7 @@ 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