wifi: Non-AP MLDs include TID-to-Link Mapping element(s) in AssocReq frames

This commit is contained in:
Stefano Avallone
2023-05-17 15:54:01 +02:00
parent b7f8abc3d0
commit a36de7eafe
6 changed files with 157 additions and 1 deletions

View File

@@ -467,6 +467,76 @@ StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
return multiLinkElement;
}
std::vector<TidToLinkMapping>
StaWifiMac::GetTidToLinkMappingElements(uint8_t apNegSupport)
{
NS_LOG_FUNCTION(this << apNegSupport);
auto ehtConfig = GetEhtConfiguration();
NS_ASSERT(ehtConfig);
EnumValue negSupport;
ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
NS_ABORT_MSG_IF(negSupport.Get() == 0,
"Cannot request TID-to-Link Mapping if negotiation is not supported");
// store the mappings, so that we can enforce them when the AP MLD accepts them
m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
bool mappingValidForNegType1 = TidToLinkMappingValidForNegType1(m_dlTidLinkMappingInAssocReq,
m_ulTidLinkMappingInAssocReq);
NS_ABORT_MSG_IF(
negSupport.Get() == 1 && !mappingValidForNegType1,
"Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
if (apNegSupport == 1 && !mappingValidForNegType1)
{
// If the TID-to-link Mapping Negotiation Support subfield value received from a peer
// MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
// peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
// the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
// this requirement.
NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
m_dlTidLinkMappingInAssocReq.clear();
m_ulTidLinkMappingInAssocReq.clear();
}
std::vector<TidToLinkMapping> ret(1);
ret.back().m_control.direction = WifiDirection::DOWNLINK;
// lambda to fill the last TID-to-Link Mapping IE in the vector to return
auto fillIe = [&ret](const auto& mapping) {
ret.back().m_control.defaultMapping = mapping.empty();
for (const auto& [tid, linkSet] : mapping)
{
// At any point in time, a TID shall always be mapped to at least one setup link both
// in DL and UL, which means that a TID-to-link mapping change is only valid and
// successful if it will not result in having any TID for which the link set for DL
// or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
ret.back().SetLinkMappingOfTid(tid, linkSet);
}
};
fillIe(m_dlTidLinkMappingInAssocReq);
if (m_ulTidLinkMappingInAssocReq == m_dlTidLinkMappingInAssocReq)
{
ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
return ret;
}
ret.emplace_back();
ret.back().m_control.direction = WifiDirection::UPLINK;
fillIe(m_ulTidLinkMappingInAssocReq);
return ret;
}
void
StaWifiMac::SendAssociationRequest(bool isReassoc)
{
@@ -500,7 +570,9 @@ StaWifiMac::SendAssociationRequest(bool isReassoc)
auto frame = GetAssociationRequest(isReassoc, linkId);
// include a Multi-Link Element if this device has multiple links (independently
// of how many links will be setup) and the AP is a multi-link device
// of how many links will be setup) and the AP is a multi-link device;
// if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
// include the TID-to-link Mapping element(s)
if (GetNLinks() > 1 &&
GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
{
@@ -508,6 +580,17 @@ StaWifiMac::SendAssociationRequest(bool isReassoc)
frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
};
std::visit(addMle, frame);
uint8_t negSupport;
if (const auto& mldCapabilities =
GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
mldCapabilities && (negSupport = mldCapabilities->get().tidToLinkMappingSupport) > 0)
{
auto addTlm = [&](auto&& frame) {
frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
};
std::visit(addTlm, frame);
}
}
if (!isReassoc)

View File

@@ -504,6 +504,13 @@ class StaWifiMac : public WifiMac
* \return the Multi-Link Element
*/
MultiLinkElement GetMultiLinkElement(bool isReassoc, uint8_t linkId) const;
/**
* \param apNegSupport the negotiation type supported by the AP MLD
* \return the TID-to-Link Mapping element(s) to include in Association Request frame.
*/
std::vector<TidToLinkMapping> GetTidToLinkMappingElements(uint8_t apNegSupport);
/**
* Set the current MAC state.
*
@@ -590,6 +597,11 @@ class StaWifiMac : public WifiMac
///< of the first Probe Response on each channel
Time m_pmModeSwitchTimeout; ///< PM mode switch timeout
/// store the DL TID-to-Link Mapping included in the Association Request frame
WifiTidLinkMapping m_dlTidLinkMappingInAssocReq;
/// store the UL TID-to-Link Mapping included in the Association Request frame
WifiTidLinkMapping m_ulTidLinkMappingInAssocReq;
TracedCallback<Mac48Address> m_assocLogger; ///< association logger
TracedCallback<uint8_t, Mac48Address> m_setupCompleted; ///< link setup completed logger
TracedCallback<Mac48Address> m_deAssocLogger; ///< disassociation logger

View File

@@ -1642,6 +1642,17 @@ WifiRemoteStationManager::GetStationEmlCapabilities(const Mac48Address& from)
return std::nullopt;
}
std::optional<std::reference_wrapper<CommonInfoBasicMle::MldCapabilities>>
WifiRemoteStationManager::GetStationMldCapabilities(const Mac48Address& from)
{
if (auto state = LookupState(from);
state->m_mleCommonInfo && state->m_mleCommonInfo->m_mldCapabilities)
{
return state->m_mleCommonInfo->m_mldCapabilities.value();
}
return std::nullopt;
}
bool
WifiRemoteStationManager::GetLdpcSupported(Mac48Address address) const
{

View File

@@ -310,6 +310,12 @@ class WifiRemoteStationManager : public Object
*/
std::optional<std::reference_wrapper<CommonInfoBasicMle::EmlCapabilities>>
GetStationEmlCapabilities(const Mac48Address& from);
/**
* \param from the (MLD or link) address of the remote non-AP MLD
* \return the MLD Capabilities advertised by the remote non-AP MLD
*/
std::optional<std::reference_wrapper<CommonInfoBasicMle::MldCapabilities>>
GetStationMldCapabilities(const Mac48Address& from);
/**
* Return whether the device has HT capability support enabled.
*

View File

@@ -144,4 +144,37 @@ GetSize(Ptr<const Packet> packet, const WifiMacHeader* hdr, bool isAmpdu)
return size;
}
bool
TidToLinkMappingValidForNegType1(const WifiTidLinkMapping& dlLinkMapping,
const WifiTidLinkMapping& ulLinkMapping)
{
if (dlLinkMapping.empty() && ulLinkMapping.empty())
{
// default mapping is valid
return true;
}
if (dlLinkMapping.size() != 8 || ulLinkMapping.size() != 8)
{
// not all TIDs have been mapped
return false;
}
const auto& linkSet = dlLinkMapping.cbegin()->second;
for (const auto& linkMapping : {std::cref(dlLinkMapping), std::cref(ulLinkMapping)})
{
for (const auto& [tid, links] : linkMapping.get())
{
if (links != linkSet)
{
// distinct link sets
return false;
}
}
}
return true;
}
} // namespace ns3

View File

@@ -170,6 +170,17 @@ void AddWifiMacTrailer(Ptr<Packet> packet);
*/
uint32_t GetSize(Ptr<const Packet> packet, const WifiMacHeader* hdr, bool isAmpdu);
/**
* Check if the given TID-to-Link Mappings are valid for a negotiation type of 1. Specifically,
* it is checked whether all TIDs are mapped to the same set of links.
*
* \param dlLinkMapping the given TID-to-Link Mapping for Downlink
* \param ulLinkMapping the given TID-to-Link Mapping for Uplink
* \return whether the given TID-to-Link Mappings are valid for a negotiation type of 1
*/
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping& dlLinkMapping,
const WifiTidLinkMapping& ulLinkMapping);
/// Size of the space of sequence numbers
static constexpr uint16_t SEQNO_SPACE_SIZE = 4096;