wifi: Non-AP MLDs include TID-to-Link Mapping element(s) in AssocReq frames
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user