diff --git a/src/wifi/CMakeLists.txt b/src/wifi/CMakeLists.txt index 27072150b..1e26bf5c4 100644 --- a/src/wifi/CMakeLists.txt +++ b/src/wifi/CMakeLists.txt @@ -337,6 +337,7 @@ set(header_files model/yans-wifi-channel.h model/yans-wifi-phy.h model/wifi-spectrum-value-helper.h + test/wifi-mlo-test.h ) build_lib( diff --git a/src/wifi/test/wifi-mlo-test.cc b/src/wifi/test/wifi-mlo-test.cc index 8ac30e66a..a7e92c059 100644 --- a/src/wifi/test/wifi-mlo-test.cc +++ b/src/wifi/test/wifi-mlo-test.cc @@ -6,7 +6,8 @@ * Author: Stefano Avallone */ -#include "ns3/ap-wifi-mac.h" +#include "wifi-mlo-test.h" + #include "ns3/config.h" #include "ns3/eht-configuration.h" #include "ns3/ht-frame-exchange-manager.h" @@ -15,21 +16,14 @@ #include "ns3/mgt-headers.h" #include "ns3/mobility-helper.h" #include "ns3/multi-link-element.h" -#include "ns3/multi-model-spectrum-channel.h" #include "ns3/node-list.h" -#include "ns3/packet-socket-client.h" #include "ns3/packet-socket-helper.h" -#include "ns3/packet-socket-server.h" #include "ns3/packet.h" #include "ns3/pointer.h" -#include "ns3/qos-utils.h" #include "ns3/rng-seed-manager.h" #include "ns3/rr-multi-user-scheduler.h" -#include "ns3/spectrum-wifi-helper.h" #include "ns3/spectrum-wifi-phy.h" -#include "ns3/sta-wifi-mac.h" #include "ns3/string.h" -#include "ns3/test.h" #include "ns3/vht-configuration.h" #include "ns3/wifi-acknowledgment.h" #include "ns3/wifi-assoc-manager.h" @@ -37,41 +31,17 @@ #include "ns3/wifi-mac-queue.h" #include "ns3/wifi-net-device.h" #include "ns3/wifi-protection.h" -#include "ns3/wifi-psdu.h" #include #include #include -#include #include #include -#include using namespace ns3; NS_LOG_COMPONENT_DEFINE("WifiMloTest"); -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Test the implementation of WifiAssocManager::GetNextAffiliatedAp(), which - * searches a given RNR element for APs affiliated to the same AP MLD as the - * reporting AP that sent the frame containing the element. - */ -class GetRnrLinkInfoTest : public TestCase -{ - public: - /** - * Constructor - */ - GetRnrLinkInfoTest(); - ~GetRnrLinkInfoTest() override = default; - - private: - void DoRun() override; -}; - GetRnrLinkInfoTest::GetRnrLinkInfoTest() : TestCase("Check the implementation of WifiAssocManager::GetNextAffiliatedAp()") { @@ -180,64 +150,6 @@ GetRnrLinkInfoTest::DoRun() "Unexpected tbtt ID of the second reported AP"); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * Test the WifiMac::SwapLinks() method. - */ -class MldSwapLinksTest : public TestCase -{ - /** - * Test WifiMac subclass used to access the SwapLinks method. - */ - class TestWifiMac : public WifiMac - { - public: - ~TestWifiMac() override = default; - - using WifiMac::GetLinks; - using WifiMac::SwapLinks; - - bool CanForwardPacketsTo(Mac48Address to) const override - { - return true; - } - - private: - void DoCompleteConfig() override - { - } - - void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override - { - } - }; - - public: - MldSwapLinksTest(); - ~MldSwapLinksTest() override = default; - - protected: - void DoRun() override; - - private: - /** - * Run a single test case. - * - * \param text string identifying the test case - * \param nLinks the number of links of the MLD - * \param links a set of pairs (from, to) each mapping a current link ID to the - * link ID it has to become (i.e., link 'from' becomes link 'to') - * \param expected maps each link ID to the id of the PHY that is expected - * to operate on that link after the swap - */ - void RunOne(std::string text, - std::size_t nLinks, - const std::map& links, - const std::map& expected); -}; - MldSwapLinksTest::MldSwapLinksTest() : TestCase("Test the WifiMac::SwapLinks() method") { @@ -300,40 +212,6 @@ MldSwapLinksTest::DoRun() RunOne("Move all links to a new set of IDs", 2, {{0, 2}, {1, 3}}, {{2, 0}, {3, 1}}); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * Test that the AIDs that an AP MLD assigns to SLDs and MLDs are all unique. - */ -class AidAssignmentTest : public TestCase -{ - public: - /** - * Constructor. - * - * \param linkIds A vector specifying the set of link IDs each STA will setup - */ - AidAssignmentTest(const std::vector>& linkIds); - - private: - void DoSetup() override; - void DoRun() override; - - /** - * Set the SSID on the next station that needs to start the association procedure. - * This method is triggered every time a STA completes its association. - * - * \param staMac the MAC of the STA that completed association - */ - void SetSsid(Ptr staMac, Mac48Address /* apAddr */); - - const std::vector m_linkChannels; //!< channels for all AP links - const std::vector> m_linkIds; //!< link IDs for all non-AP STAs/MLDs - NetDeviceContainer m_staDevices; //!< non-AP STAs/MLDs devices - uint16_t m_expectedAid; //!< expected AID for current non-AP STA/MLD -}; - AidAssignmentTest::AidAssignmentTest(const std::vector>& linkIds) : TestCase("Test the assignment of AIDs"), m_linkChannels({"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}"}), @@ -484,170 +362,6 @@ AidAssignmentTest::DoRun() Simulator::Destroy(); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Base class for Multi-Link Operations tests - * - * Three spectrum channels are created, one for each band (2.4 GHz, 5 GHz and 6 GHz). - * Each PHY object is attached to the spectrum channel corresponding to the PHY band - * in which it is operating. - */ -class MultiLinkOperationsTestBase : public TestCase -{ - public: - /** - * Configuration parameters common to all subclasses - */ - struct BaseParams - { - std::vector - staChannels; //!< the strings specifying the operating channels for the non-AP MLD - std::vector - apChannels; //!< the strings specifying the operating channels for the AP MLD - std::vector - fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band - }; - - /** - * Constructor - * - * \param name The name of the new TestCase created - * \param nStations the number of stations to create - * \param baseParams common configuration parameters - */ - MultiLinkOperationsTestBase(const std::string& name, - uint8_t nStations, - const BaseParams& baseParams); - ~MultiLinkOperationsTestBase() override = default; - - protected: - /** - * Callback invoked when a FEM passes PSDUs to the PHY. - * - * \param mac the MAC transmitting the PSDUs - * \param phyId the ID of the PHY transmitting the PSDUs - * \param psduMap the PSDU map - * \param txVector the TX vector - * \param txPowerW the tx power in Watts - */ - virtual void Transmit(Ptr mac, - uint8_t phyId, - WifiConstPsduMap psduMap, - WifiTxVector txVector, - double txPowerW); - - /** - * Check that the expected Capabilities information elements are present in the given - * management frame based on the band in which the given link is operating. - * - * \param mpdu the given management frame - * \param mac the MAC transmitting the management frame - * \param phyId the ID of the PHY transmitting the management frame - */ - void CheckCapabilities(Ptr mpdu, Ptr mac, uint8_t phyId); - - /** - * Function to trace packets received by the server application - * \param nodeId the ID of the node that received the packet - * \param p the packet - * \param addr the address - */ - virtual void L7Receive(uint8_t nodeId, Ptr p, const Address& addr); - - /** - * \param sockAddr the packet socket address identifying local outgoing interface - * and remote address - * \param count the number of packets to generate - * \param pktSize the size of the packets to generate - * \param delay the delay with which traffic generation starts - * \param priority user priority for generated packets - * \return an application generating the given number packets of the given size destined - * to the given packet socket address - */ - Ptr GetApplication(const PacketSocketAddress& sockAddr, - std::size_t count, - std::size_t pktSize, - Time delay = Seconds(0), - uint8_t priority = 0) const; - - void DoSetup() override; - - /// PHY band-indexed map of spectrum channels - using ChannelMap = std::map>; - - /** - * Uplink or Downlink direction - */ - enum Direction - { - DL = 0, - UL - }; - - /** - * Check that the Address 1 and Address 2 fields of the given PSDU contain device MAC addresses. - * - * \param psdu the given PSDU - * \param direction indicates direction for management frames (DL or UL) - */ - void CheckAddresses(Ptr psdu, - std::optional direction = std::nullopt); - - /// Information about transmitted frames - struct FrameInfo - { - Time startTx; ///< TX start time - WifiConstPsduMap psduMap; ///< transmitted PSDU map - WifiTxVector txVector; ///< TXVECTOR - uint8_t linkId; ///< link ID - uint8_t phyId; ///< ID of the transmitting PHY - }; - - std::vector m_txPsdus; ///< transmitted PSDUs - const std::vector m_staChannels; ///< strings specifying channels for STA - const std::vector m_apChannels; ///< strings specifying channels for AP - const std::vector m_fixedPhyBands; ///< links on non-AP MLD with fixed PHY band - Ptr m_apMac; ///< AP wifi MAC - std::vector> m_staMacs; ///< STA wifi MACs - uint8_t m_nStations; ///< number of stations to create - uint16_t m_lastAid; ///< AID of last associated station - Time m_duration{Seconds(1)}; ///< simulation duration - std::vector m_rxPkts; ///< number of packets received at application layer - ///< by each node (index is node ID) - - private: - /** - * Reset the given PHY helper, use the given strings to set the ChannelSettings - * attribute of the PHY objects to create, and attach them to the given spectrum - * channels appropriately. - * - * \param helper the given PHY helper - * \param channels the strings specifying the operating channels to configure - * \param channelMap the created spectrum channels - */ - void SetChannels(SpectrumWifiPhyHelper& helper, - const std::vector& channels, - const ChannelMap& channelMap); - - /** - * Set the SSID on the next station that needs to start the association procedure. - * This method is connected to the ApWifiMac's AssociatedSta trace source. - * Start generating traffic (if needed) when all stations are associated. - * - * \param aid the AID assigned to the previous associated STA - */ - void SetSsid(uint16_t aid, Mac48Address /* addr */); - - /** - * Start the generation of traffic (needs to be overridden) - */ - virtual void StartTraffic() - { - } -}; - MultiLinkOperationsTestBase::MultiLinkOperationsTestBase(const std::string& name, uint8_t nStations, const BaseParams& baseParams) @@ -1041,147 +755,6 @@ MultiLinkOperationsTestBase::SetSsid(uint16_t aid, Mac48Address /* addr */) Simulator::Schedule(MilliSeconds(5), &MultiLinkOperationsTestBase::StartTraffic, this); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Multi-Link Discovery & Setup test. - * - * This test sets up an AP MLD and a non-AP MLD having a variable number of links. - * The RF channels to set each link to are provided as input parameters through the test - * case constructor, along with the identifiers (starting at 0) of the links that cannot - * switch PHY band (if any). The links that are expected to be setup are also provided as input - * parameters. This test verifies that the management frames exchanged during ML discovery - * and ML setup contain the expected values and that the two MLDs setup the expected links. - * - * The negotiated TID-to-link mapping is tested by verifying that generated QoS data frames of - * a given TID are transmitted on links which the TID is mapped to. Specifically, the following - * operations are performed separately for each direction (downlink and uplink). A first TID - * is searched such that it is not mapped on all the setup links. If no such TID is found, only - * QoS frames of TID 0 are generated. Otherwise, we also search for a second TID that is mapped - * to a link set that is disjoint with the link set to which the first TID is mapped. If such a - * TID is found, QoS frames of both the first TID and the second TID are generated; otherwise, - * only QoS frames of the first TID are generated. For each TID, a number of QoS frames equal - * to the number of setup links is generated. For each TID, we check that the first N QoS frames, - * where N is the size of the link set to which the TID is mapped, are transmitted concurrently, - * while the following QoS frames are sent after the first QoS frame sent on the same link. We - * also check that all the QoS frames are sent on a link belonging to the link set to which the - * TID is mapped. If QoS frames of two TIDs are generated, we also check that the first N QoS - * frames of a TID, where N is the size of the link set to which that TID is mapped, are sent - * concurrently with the first M QoS frames of the other TID, where M is the size of the link - * set to which the other TID is mapped. - */ -class MultiLinkSetupTest : public MultiLinkOperationsTestBase -{ - public: - /** - * Constructor - * - * \param baseParams common configuration parameters - * \param scanType the scan type (active or passive) - * \param setupLinks a list of links that are expected to be setup. In case one of the two - * devices has a single link, the ID of the link on the MLD is indicated - * \param apNegSupport TID-to-Link Mapping negotiation supported by the AP MLD (0, 1, or 3) - * \param dlTidToLinkMapping DL TID-to-Link Mapping for EHT configuration of non-AP MLD - * \param ulTidToLinkMapping UL TID-to-Link Mapping for EHT configuration of non-AP MLD - * \param support160MHzOp whether non-AP MLDs support 160 MHz operations - */ - MultiLinkSetupTest(const BaseParams& baseParams, - WifiScanType scanType, - const std::vector& setupLinks, - WifiTidToLinkMappingNegSupport apNegSupport, - const std::string& dlTidToLinkMapping, - const std::string& ulTidToLinkMapping, - bool support160MHzOp = true); - ~MultiLinkSetupTest() override = default; - - protected: - void DoSetup() override; - void DoRun() override; - - private: - void StartTraffic() override; - - /** - * Check correctness of Multi-Link Setup procedure. - */ - void CheckMlSetup(); - - /** - * Check that links that are not setup on the non-AP MLD are disabled. Also, on the AP side, - * check that the queue storing QoS data frames destined to the non-AP MLD has a mask for a - * link if and only if the link has been setup by the non-AO MLD. - */ - void CheckDisabledLinks(); - - /** - * Check correctness of the given Beacon frame. - * - * \param mpdu the given Beacon frame - * \param linkId the ID of the link on which the Beacon frame was transmitted - */ - void CheckBeacon(Ptr mpdu, uint8_t linkId); - - /** - * Check correctness of the given Probe Response frame. - * - * \param mpdu the given Probe Response frame - * \param linkId the ID of the link on which the Probe Response frame was transmitted - */ - void CheckProbeResponse(Ptr mpdu, uint8_t linkId); - - /** - * Check correctness of the given Association Request frame. - * - * \param mpdu the given Association Request frame - * \param linkId the ID of the link on which the Association Request frame was transmitted - */ - void CheckAssocRequest(Ptr mpdu, uint8_t linkId); - - /** - * Check correctness of the given Association Response frame. - * - * \param mpdu the given Association Response frame - * \param linkId the ID of the link on which the Association Response frame was transmitted - */ - void CheckAssocResponse(Ptr mpdu, uint8_t linkId); - - /** - * Check that QoS data frames are sent on links their TID is mapped to and with the - * correct TX width. - * - * \param mpdu the given QoS data frame - * \param txvector the TXVECTOR used to send the QoS data frame - * \param linkId the ID of the link on which the QoS data frame was transmitted - * \param index index of the QoS data frame in the vector of transmitted PSDUs - */ - void CheckQosData(Ptr mpdu, - const WifiTxVector& txvector, - uint8_t linkId, - std::size_t index); - - const std::vector m_setupLinks; //!< IDs of the expected links to setup - WifiScanType m_scanType; //!< the scan type (active or passive) - std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD - WifiTidToLinkMappingNegSupport - m_apNegSupport; //!< TID-to-Link Mapping negotiation supported by the AP MLD - std::string m_dlTidLinkMappingStr; //!< DL TID-to-Link Mapping for non-AP MLD EHT configuration - std::string m_ulTidLinkMappingStr; //!< UL TID-to-Link Mapping for non-AP MLD EHT configuration - WifiTidLinkMapping m_dlTidLinkMapping; //!< expected DL TID-to-Link Mapping requested by non-AP - //!< MLD and accepted by AP MLD - WifiTidLinkMapping m_ulTidLinkMapping; //!< expected UL TID-to-Link Mapping requested by non-AP - //!< MLD and accepted by AP MLD - uint8_t m_dlTid1; //!< the TID of the first set of DL QoS data frames - uint8_t m_ulTid1; //!< the TID of the first set of UL QoS data frames - std::optional m_dlTid2; //!< the TID of the optional set of DL QoS data frames - std::optional m_ulTid2; //!< the TID of the optional set of UL QoS data frames - std::vector - m_qosFrames1; //!< indices of QoS frames of the first set in the vector of TX PSDUs - std::vector - m_qosFrames2; //!< indices of QoS frames of the optional set in the vector of TX PSDUs - bool m_support160MHzOp; //!< whether non-AP MLDs support 160 MHz operations -}; - MultiLinkSetupTest::MultiLinkSetupTest(const BaseParams& baseParams, WifiScanType scanType, const std::vector& setupLinks, @@ -2097,124 +1670,6 @@ MultiLinkSetupTest::CheckQosData(Ptr mpdu, } } -/** - * Tested traffic patterns. - */ -enum class WifiTrafficPattern : uint8_t -{ - STA_TO_STA = 0, - STA_TO_AP, - AP_TO_STA, - AP_TO_BCAST, - STA_TO_BCAST -}; - -/** - * Block Ack agreement enabled/disabled - */ -enum class WifiBaEnabled : uint8_t -{ - NO = 0, - YES -}; - -/** - * Whether to send a BlockAckReq after a missed BlockAck - */ -enum class WifiUseBarAfterMissedBa : uint8_t -{ - NO = 0, - YES -}; - -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Test data transmission between two MLDs. - * - * This test sets up an AP MLD and two non-AP MLDs having a variable number of links. - * The RF channels to set each link to are provided as input parameters through the test - * case constructor, along with the identifiers (starting at 0) of the links that cannot - * switch PHY band (if any). This test aims at veryfing the successful transmission of both - * unicast QoS data frames (from one station to another, from one station to the AP, from - * the AP to the station) and broadcast QoS data frames (from the AP or from one station). - * In the scenarios in which the AP forwards frames (i.e., from one station to another and - * from one station to broadcast) the client application generates only 4 packets, in order - * to limit the probability of collisions. In the other scenarios, 8 packets are generated. - * When BlockAck agreements are enabled, the maximum A-MSDU size is set such that two - * packets can be aggregated in an A-MSDU. The MPDU with sequence number equal to 1 is - * corrupted (once, by using a post reception error model) to test its successful - * re-transmission, unless the traffic scenario is from the AP to broadcast (broadcast frames - * are not retransmitted) or is a scenario where the AP forwards frame (to limit the - * probability of collisions). - * - * When BlockAck agreements are enabled, we also corrupt a BlockAck frame, so as to simulate - * the case of BlockAck timeout. Both the case where a BlockAckReq is sent and the case where - * data frame are retransmitted are tested. Finally, when BlockAck agreements are enabled, we - * also enable the concurrent transmission of data frames over two links and check that at - * least one MPDU is concurrently transmitted over two links. - */ -class MultiLinkTxTest : public MultiLinkOperationsTestBase -{ - public: - /** - * Constructor - * - * \param baseParams common configuration parameters - * \param trafficPattern the pattern of traffic to generate - * \param baEnabled whether BA agreement is enabled or disabled - * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck - * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight - * (unused if Block Ack agreements are not established) - */ - MultiLinkTxTest(const BaseParams& baseParams, - WifiTrafficPattern trafficPattern, - WifiBaEnabled baEnabled, - WifiUseBarAfterMissedBa useBarAfterMissedBa, - uint8_t nMaxInflight); - ~MultiLinkTxTest() override = default; - - protected: - /** - * Check the content of a received BlockAck frame when the max number of links on which - * an MPDU can be inflight is one. - * - * \param psdu the PSDU containing the BlockAck - * \param txVector the TXVECTOR used to transmit the BlockAck - * \param linkId the ID of the link on which the BlockAck was transmitted - */ - void CheckBlockAck(Ptr psdu, const WifiTxVector& txVector, uint8_t linkId); - - void Transmit(Ptr mac, - uint8_t phyId, - WifiConstPsduMap psduMap, - WifiTxVector txVector, - double txPowerW) override; - void DoSetup() override; - void DoRun() override; - - private: - void StartTraffic() override; - - /// Receiver address-indexed map of list error models - using RxErrorModelMap = std::unordered_map, WifiAddressHash>; - - RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets - std::list m_uidList; ///< list of UIDs of packets to corrupt - bool m_dataCorrupted{false}; ///< whether second data frame has been already corrupted - WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate - bool m_baEnabled; ///< whether BA agreement is enabled or disabled - bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck - std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight - std::size_t m_nPackets; ///< number of application packets to generate - std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter - std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter - std::map m_inflightCount; ///< seqNo-indexed max number of simultaneous - ///< transmissions of a data frame - Ptr m_sourceMac; ///< MAC of the node sending application packets -}; - MultiLinkTxTest::MultiLinkTxTest(const BaseParams& baseParams, WifiTrafficPattern trafficPattern, WifiBaEnabled baEnabled, @@ -2682,105 +2137,6 @@ MultiLinkTxTest::DoRun() Simulator::Destroy(); } -/** - * Tested MU traffic patterns. - */ -enum class WifiMuTrafficPattern : uint8_t -{ - DL_MU_BAR_BA_SEQUENCE = 0, - DL_MU_MU_BAR, - DL_MU_AGGR_MU_BAR, - UL_MU -}; - -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Test data transmission between MLDs using OFDMA MU transmissions - * - * This test sets up an AP MLD and two non-AP MLDs having a variable number of links. - * The RF channels to set each link to are provided as input parameters through the test - * case constructor, along with the identifiers (starting at 0) of the links that cannot - * switch PHY band (if any). This test aims at veryfing the successful transmission of both - * DL MU and UL MU frames. In the DL MU scenarios, the client applications installed on the - * AP generate 8 packets addressed to each of the stations (plus 3 packets to trigger the - * establishment of BlockAck agreements). In the UL MU scenario, client applications - * installed on the stations generate 4 packets each (plus 3 packets to trigger the - * establishment of BlockAck agreements). - * - * The maximum A-MSDU size is set such that two packets can be aggregated in an A-MSDU. - * The MPDU with sequence number equal to 3 is corrupted (by using a post reception error - * model) once and for a single station, to test its successful re-transmission. - * - * Also, we enable the concurrent transmission of data frames over two links and check that at - * least one MPDU is concurrently transmitted over two links. - */ -class MultiLinkMuTxTest : public MultiLinkOperationsTestBase -{ - public: - /** - * Constructor - * - * \param baseParams common configuration parameters - * \param muTrafficPattern the pattern of traffic to generate - * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck - * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight - * (unused if Block Ack agreements are not established) - */ - MultiLinkMuTxTest(const BaseParams& baseParams, - WifiMuTrafficPattern muTrafficPattern, - WifiUseBarAfterMissedBa useBarAfterMissedBa, - uint8_t nMaxInflight); - ~MultiLinkMuTxTest() override = default; - - protected: - /** - * Check the content of a received BlockAck frame when the max number of links on which - * an MPDU can be inflight is one. - * - * \param psdu the PSDU containing the BlockAck - * \param txVector the TXVECTOR used to transmit the BlockAck - * \param linkId the ID of the link on which the BlockAck was transmitted - */ - void CheckBlockAck(Ptr psdu, const WifiTxVector& txVector, uint8_t linkId); - - void Transmit(Ptr mac, - uint8_t phyId, - WifiConstPsduMap psduMap, - WifiTxVector txVector, - double txPowerW) override; - void DoSetup() override; - void DoRun() override; - - private: - void StartTraffic() override; - - /// Receiver address-indexed map of list error models - using RxErrorModelMap = std::unordered_map, WifiAddressHash>; - - /// A pair of a MAC address (the address of the receiver for DL frames and the address of - /// the sender for UL frames) and a sequence number identifying a transmitted QoS data frame - using AddrSeqNoPair = std::pair; - - RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets - std::list m_uidList; ///< list of UIDs of packets to corrupt - std::optional m_dataCorruptedSta; ///< MAC address of the station that received - ///< MPDU with SeqNo=2 corrupted - bool m_waitFirstTf{true}; ///< whether we are waiting for the first Basic Trigger Frame - WifiMuTrafficPattern m_muTrafficPattern; ///< the pattern of traffic to generate - bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck - std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight - std::vector m_sockets; ///< packet socket addresses for STAs - std::size_t m_nPackets; ///< number of application packets to generate - std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter - std::size_t m_tfCount{0}; ///< transmitted Trigger Frame counter - // std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter - std::map m_inflightCount; ///< max number of simultaneous - ///< transmissions of each data frame - Ptr m_sourceMac; ///< MAC of the node sending application packets -}; - MultiLinkMuTxTest::MultiLinkMuTxTest(const BaseParams& baseParams, WifiMuTrafficPattern muTrafficPattern, WifiUseBarAfterMissedBa useBarAfterMissedBa, @@ -3292,48 +2648,6 @@ MultiLinkMuTxTest::DoRun() Simulator::Destroy(); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Test release of sequence numbers upon CTS timeout in multi-link operations - * - * In this test, an AP MLD and a non-AP MLD setup 3 links. Usage of RTS/CTS protection is - * enabled for frames whose length is at least 1000 bytes. The AP MLD receives a first set - * of 4 packets from the upper layer and sends an RTS frame, which is corrupted at the - * receiver, on a first link. When the RTS frame is transmitted, the AP MLD receives another - * set of 4 packets, which are transmitted after a successful RTS/CTS exchange on a second - * link. In the meantime, a new RTS/CTS exchange is successfully carried out (on the first - * link or on the third link) to transmit the first set of 4 packets. When the transmission - * of the first set of 4 packets starts, the AP MLD receives the third set of 4 packets from - * the upper layer, which are transmitted after a successful RTS/CTS exchange. - * - * This test checks that sequence numbers are correctly assigned to all the MPDUs carrying data. - */ -class ReleaseSeqNoAfterCtsTimeoutTest : public MultiLinkOperationsTestBase -{ - public: - ReleaseSeqNoAfterCtsTimeoutTest(); - ~ReleaseSeqNoAfterCtsTimeoutTest() override = default; - - protected: - void DoSetup() override; - void DoRun() override; - void Transmit(Ptr mac, - uint8_t phyId, - WifiConstPsduMap psduMap, - WifiTxVector txVector, - double txPowerW) override; - - private: - void StartTraffic() override; - - PacketSocketAddress m_sockAddr; //!< packet socket address - std::size_t m_nQosDataFrames; //!< counter for transmitted QoS data frames - Ptr m_errorModel; //!< error rate model to corrupt first RTS frame - bool m_rtsCorrupted; //!< whether the first RTS frame has been corrupted -}; - ReleaseSeqNoAfterCtsTimeoutTest::ReleaseSeqNoAfterCtsTimeoutTest() : MultiLinkOperationsTestBase( "Check sequence numbers after CTS timeout", @@ -3451,47 +2765,6 @@ ReleaseSeqNoAfterCtsTimeoutTest::DoRun() Simulator::Destroy(); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief Test update of BA starting sequence number after ADDBA Response timeout in - * multi-link operations - * - * In this test, an AP MLD and a non-AP MLD setup 2 links. The AP MLD has a QoS data frame to - * transmit to the non-AP MLD, which triggers the establishment of a BA agreement. When the ADDBA - * Request frame is received by the non-AP MLD, transmissions of the non-AP MLD are blocked to put - * the transmission of the ADDBA Response on hold. The goal is to mimic a delay in getting channel - * access due to, e.g., other devices grabbing the medium. When the ADDBA Response timer at the AP - * MLD expires, transmissions of the non-AP MLD are unblocked, so that the AP MLD sends the QoS data - * frame (protected by RTS, but the test works without RTS as well, and using Normal acknowledgment) - * on one link and the non-AP MLD sends the ADDBA Response on the other link. The transmission of - * the QoS data frame is then corrupted. We verify that: - * - * - when the AP MLD receives the ADDBA Response, the BA starting sequence number is set to the - * sequence number of the QoS data frame which is inflight - * - the QoS data frame is retransmitted and received by the non-AP MLD - */ -class StartSeqNoUpdateAfterAddBaTimeoutTest : public MultiLinkOperationsTestBase -{ - public: - StartSeqNoUpdateAfterAddBaTimeoutTest(); - - private: - void DoSetup() override; - void DoRun() override; - void Transmit(Ptr mac, - uint8_t phyId, - WifiConstPsduMap psduMap, - WifiTxVector txVector, - double txPowerW) override; - void StartTraffic() override; - - PacketSocketAddress m_sockAddr; //!< packet socket address - std::size_t m_nQosDataCount; //!< counter for transmitted QoS data frames - Ptr m_staErrorModel; //!< error rate model to corrupt frames at the non-AP MLD -}; - StartSeqNoUpdateAfterAddBaTimeoutTest::StartSeqNoUpdateAfterAddBaTimeoutTest() : MultiLinkOperationsTestBase( "Check starting sequence number update after ADDBA Response timeout", @@ -3647,18 +2920,6 @@ StartSeqNoUpdateAfterAddBaTimeoutTest::DoRun() Simulator::Destroy(); } -/** - * \ingroup wifi-test - * \ingroup tests - * - * \brief wifi 11be MLD Test Suite - */ -class WifiMultiLinkOperationsTestSuite : public TestSuite -{ - public: - WifiMultiLinkOperationsTestSuite(); -}; - WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite() : TestSuite("wifi-mlo", Type::UNIT) { diff --git a/src/wifi/test/wifi-mlo-test.h b/src/wifi/test/wifi-mlo-test.h new file mode 100644 index 000000000..48f01fe24 --- /dev/null +++ b/src/wifi/test/wifi-mlo-test.h @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#ifndef WIFI_MLO_TEST_H +#define WIFI_MLO_TEST_H + +#include "ns3/ap-wifi-mac.h" +#include "ns3/mgt-action-headers.h" +#include "ns3/mgt-headers.h" +#include "ns3/multi-model-spectrum-channel.h" +#include "ns3/packet-socket-client.h" +#include "ns3/packet-socket-server.h" +#include "ns3/qos-utils.h" +#include "ns3/spectrum-wifi-helper.h" +#include "ns3/sta-wifi-mac.h" +#include "ns3/test.h" +#include "ns3/wifi-psdu.h" + +#include +#include + +using namespace ns3; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test the implementation of WifiAssocManager::GetNextAffiliatedAp(), which + * searches a given RNR element for APs affiliated to the same AP MLD as the + * reporting AP that sent the frame containing the element. + */ +class GetRnrLinkInfoTest : public TestCase +{ + public: + /** + * Constructor + */ + GetRnrLinkInfoTest(); + ~GetRnrLinkInfoTest() override = default; + + private: + void DoRun() override; +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * Test the WifiMac::SwapLinks() method. + */ +class MldSwapLinksTest : public TestCase +{ + /** + * Test WifiMac subclass used to access the SwapLinks method. + */ + class TestWifiMac : public WifiMac + { + public: + ~TestWifiMac() override = default; + + using WifiMac::GetLinks; + using WifiMac::SwapLinks; + + bool CanForwardPacketsTo(Mac48Address to) const override + { + return true; + } + + private: + void DoCompleteConfig() override + { + } + + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override + { + } + }; + + public: + MldSwapLinksTest(); + ~MldSwapLinksTest() override = default; + + protected: + void DoRun() override; + + private: + /** + * Run a single test case. + * + * \param text string identifying the test case + * \param nLinks the number of links of the MLD + * \param links a set of pairs (from, to) each mapping a current link ID to the + * link ID it has to become (i.e., link 'from' becomes link 'to') + * \param expected maps each link ID to the id of the PHY that is expected + * to operate on that link after the swap + */ + void RunOne(std::string text, + std::size_t nLinks, + const std::map& links, + const std::map& expected); +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * Test that the AIDs that an AP MLD assigns to SLDs and MLDs are all unique. + */ +class AidAssignmentTest : public TestCase +{ + public: + /** + * Constructor. + * + * \param linkIds A vector specifying the set of link IDs each STA will setup + */ + AidAssignmentTest(const std::vector>& linkIds); + + private: + void DoSetup() override; + void DoRun() override; + + /** + * Set the SSID on the next station that needs to start the association procedure. + * This method is triggered every time a STA completes its association. + * + * \param staMac the MAC of the STA that completed association + */ + void SetSsid(Ptr staMac, Mac48Address /* apAddr */); + + const std::vector m_linkChannels; //!< channels for all AP links + const std::vector> m_linkIds; //!< link IDs for all non-AP STAs/MLDs + NetDeviceContainer m_staDevices; //!< non-AP STAs/MLDs devices + uint16_t m_expectedAid; //!< expected AID for current non-AP STA/MLD +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Base class for Multi-Link Operations tests + * + * Three spectrum channels are created, one for each band (2.4 GHz, 5 GHz and 6 GHz). + * Each PHY object is attached to the spectrum channel corresponding to the PHY band + * in which it is operating. + */ +class MultiLinkOperationsTestBase : public TestCase +{ + public: + /** + * Configuration parameters common to all subclasses + */ + struct BaseParams + { + std::vector + staChannels; //!< the strings specifying the operating channels for the non-AP MLD + std::vector + apChannels; //!< the strings specifying the operating channels for the AP MLD + std::vector + fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band + }; + + /** + * Constructor + * + * \param name The name of the new TestCase created + * \param nStations the number of stations to create + * \param baseParams common configuration parameters + */ + MultiLinkOperationsTestBase(const std::string& name, + uint8_t nStations, + const BaseParams& baseParams); + ~MultiLinkOperationsTestBase() override = default; + + protected: + /** + * Callback invoked when a FEM passes PSDUs to the PHY. + * + * \param mac the MAC transmitting the PSDUs + * \param phyId the ID of the PHY transmitting the PSDUs + * \param psduMap the PSDU map + * \param txVector the TX vector + * \param txPowerW the tx power in Watts + */ + virtual void Transmit(Ptr mac, + uint8_t phyId, + WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW); + + /** + * Check that the expected Capabilities information elements are present in the given + * management frame based on the band in which the given link is operating. + * + * \param mpdu the given management frame + * \param mac the MAC transmitting the management frame + * \param phyId the ID of the PHY transmitting the management frame + */ + void CheckCapabilities(Ptr mpdu, Ptr mac, uint8_t phyId); + + /** + * Function to trace packets received by the server application + * \param nodeId the ID of the node that received the packet + * \param p the packet + * \param addr the address + */ + virtual void L7Receive(uint8_t nodeId, Ptr p, const Address& addr); + + /** + * \param sockAddr the packet socket address identifying local outgoing interface + * and remote address + * \param count the number of packets to generate + * \param pktSize the size of the packets to generate + * \param delay the delay with which traffic generation starts + * \param priority user priority for generated packets + * \return an application generating the given number packets of the given size destined + * to the given packet socket address + */ + Ptr GetApplication(const PacketSocketAddress& sockAddr, + std::size_t count, + std::size_t pktSize, + Time delay = Seconds(0), + uint8_t priority = 0) const; + + void DoSetup() override; + + /// PHY band-indexed map of spectrum channels + using ChannelMap = std::map>; + + /** + * Uplink or Downlink direction + */ + enum Direction + { + DL = 0, + UL + }; + + /** + * Check that the Address 1 and Address 2 fields of the given PSDU contain device MAC addresses. + * + * \param psdu the given PSDU + * \param direction indicates direction for management frames (DL or UL) + */ + void CheckAddresses(Ptr psdu, + std::optional direction = std::nullopt); + + /// Information about transmitted frames + struct FrameInfo + { + Time startTx; ///< TX start time + WifiConstPsduMap psduMap; ///< transmitted PSDU map + WifiTxVector txVector; ///< TXVECTOR + uint8_t linkId; ///< link ID + uint8_t phyId; ///< ID of the transmitting PHY + }; + + std::vector m_txPsdus; ///< transmitted PSDUs + const std::vector m_staChannels; ///< strings specifying channels for STA + const std::vector m_apChannels; ///< strings specifying channels for AP + const std::vector m_fixedPhyBands; ///< links on non-AP MLD with fixed PHY band + Ptr m_apMac; ///< AP wifi MAC + std::vector> m_staMacs; ///< STA wifi MACs + uint8_t m_nStations; ///< number of stations to create + uint16_t m_lastAid; ///< AID of last associated station + Time m_duration{Seconds(1)}; ///< simulation duration + std::vector m_rxPkts; ///< number of packets received at application layer + ///< by each node (index is node ID) + + /** + * Reset the given PHY helper, use the given strings to set the ChannelSettings + * attribute of the PHY objects to create, and attach them to the given spectrum + * channels appropriately. + * + * \param helper the given PHY helper + * \param channels the strings specifying the operating channels to configure + * \param channelMap the created spectrum channels + */ + void SetChannels(SpectrumWifiPhyHelper& helper, + const std::vector& channels, + const ChannelMap& channelMap); + + /** + * Set the SSID on the next station that needs to start the association procedure. + * This method is connected to the ApWifiMac's AssociatedSta trace source. + * Start generating traffic (if needed) when all stations are associated. + * + * \param aid the AID assigned to the previous associated STA + */ + void SetSsid(uint16_t aid, Mac48Address /* addr */); + + private: + /** + * Start the generation of traffic (needs to be overridden) + */ + virtual void StartTraffic() + { + } +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Multi-Link Discovery & Setup test. + * + * This test sets up an AP MLD and a non-AP MLD having a variable number of links. + * The RF channels to set each link to are provided as input parameters through the test + * case constructor, along with the identifiers (starting at 0) of the links that cannot + * switch PHY band (if any). The links that are expected to be setup are also provided as input + * parameters. This test verifies that the management frames exchanged during ML discovery + * and ML setup contain the expected values and that the two MLDs setup the expected links. + * + * The negotiated TID-to-link mapping is tested by verifying that generated QoS data frames of + * a given TID are transmitted on links which the TID is mapped to. Specifically, the following + * operations are performed separately for each direction (downlink and uplink). A first TID + * is searched such that it is not mapped on all the setup links. If no such TID is found, only + * QoS frames of TID 0 are generated. Otherwise, we also search for a second TID that is mapped + * to a link set that is disjoint with the link set to which the first TID is mapped. If such a + * TID is found, QoS frames of both the first TID and the second TID are generated; otherwise, + * only QoS frames of the first TID are generated. For each TID, a number of QoS frames equal + * to the number of setup links is generated. For each TID, we check that the first N QoS frames, + * where N is the size of the link set to which the TID is mapped, are transmitted concurrently, + * while the following QoS frames are sent after the first QoS frame sent on the same link. We + * also check that all the QoS frames are sent on a link belonging to the link set to which the + * TID is mapped. If QoS frames of two TIDs are generated, we also check that the first N QoS + * frames of a TID, where N is the size of the link set to which that TID is mapped, are sent + * concurrently with the first M QoS frames of the other TID, where M is the size of the link + * set to which the other TID is mapped. + */ +class MultiLinkSetupTest : public MultiLinkOperationsTestBase +{ + public: + /** + * Constructor + * + * \param baseParams common configuration parameters + * \param scanType the scan type (active or passive) + * \param setupLinks a list of links that are expected to be setup. In case one of the two + * devices has a single link, the ID of the link on the MLD is indicated + * \param apNegSupport TID-to-Link Mapping negotiation supported by the AP MLD (0, 1, or 3) + * \param dlTidToLinkMapping DL TID-to-Link Mapping for EHT configuration of non-AP MLD + * \param ulTidToLinkMapping UL TID-to-Link Mapping for EHT configuration of non-AP MLD + * \param support160MHzOp whether non-AP MLDs support 160 MHz operations + */ + MultiLinkSetupTest(const BaseParams& baseParams, + WifiScanType scanType, + const std::vector& setupLinks, + WifiTidToLinkMappingNegSupport apNegSupport, + const std::string& dlTidToLinkMapping, + const std::string& ulTidToLinkMapping, + bool support160MHzOp = true); + ~MultiLinkSetupTest() override = default; + + protected: + void DoSetup() override; + void DoRun() override; + + private: + void StartTraffic() override; + + /** + * Check correctness of Multi-Link Setup procedure. + */ + void CheckMlSetup(); + + /** + * Check that links that are not setup on the non-AP MLD are disabled. Also, on the AP side, + * check that the queue storing QoS data frames destined to the non-AP MLD has a mask for a + * link if and only if the link has been setup by the non-AO MLD. + */ + void CheckDisabledLinks(); + + /** + * Check correctness of the given Beacon frame. + * + * \param mpdu the given Beacon frame + * \param linkId the ID of the link on which the Beacon frame was transmitted + */ + void CheckBeacon(Ptr mpdu, uint8_t linkId); + + /** + * Check correctness of the given Probe Response frame. + * + * \param mpdu the given Probe Response frame + * \param linkId the ID of the link on which the Probe Response frame was transmitted + */ + void CheckProbeResponse(Ptr mpdu, uint8_t linkId); + + /** + * Check correctness of the given Association Request frame. + * + * \param mpdu the given Association Request frame + * \param linkId the ID of the link on which the Association Request frame was transmitted + */ + void CheckAssocRequest(Ptr mpdu, uint8_t linkId); + + /** + * Check correctness of the given Association Response frame. + * + * \param mpdu the given Association Response frame + * \param linkId the ID of the link on which the Association Response frame was transmitted + */ + void CheckAssocResponse(Ptr mpdu, uint8_t linkId); + + /** + * Check that QoS data frames are sent on links their TID is mapped to and with the + * correct TX width. + * + * \param mpdu the given QoS data frame + * \param txvector the TXVECTOR used to send the QoS data frame + * \param linkId the ID of the link on which the QoS data frame was transmitted + * \param index index of the QoS data frame in the vector of transmitted PSDUs + */ + void CheckQosData(Ptr mpdu, + const WifiTxVector& txvector, + uint8_t linkId, + std::size_t index); + + const std::vector m_setupLinks; //!< IDs of the expected links to setup + WifiScanType m_scanType; //!< the scan type (active or passive) + std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD + WifiTidToLinkMappingNegSupport + m_apNegSupport; //!< TID-to-Link Mapping negotiation supported by the AP MLD + std::string m_dlTidLinkMappingStr; //!< DL TID-to-Link Mapping for non-AP MLD EHT configuration + std::string m_ulTidLinkMappingStr; //!< UL TID-to-Link Mapping for non-AP MLD EHT configuration + WifiTidLinkMapping m_dlTidLinkMapping; //!< expected DL TID-to-Link Mapping requested by non-AP + //!< MLD and accepted by AP MLD + WifiTidLinkMapping m_ulTidLinkMapping; //!< expected UL TID-to-Link Mapping requested by non-AP + //!< MLD and accepted by AP MLD + uint8_t m_dlTid1; //!< the TID of the first set of DL QoS data frames + uint8_t m_ulTid1; //!< the TID of the first set of UL QoS data frames + std::optional m_dlTid2; //!< the TID of the optional set of DL QoS data frames + std::optional m_ulTid2; //!< the TID of the optional set of UL QoS data frames + std::vector + m_qosFrames1; //!< indices of QoS frames of the first set in the vector of TX PSDUs + std::vector + m_qosFrames2; //!< indices of QoS frames of the optional set in the vector of TX PSDUs + bool m_support160MHzOp; //!< whether non-AP MLDs support 160 MHz operations +}; + +/** + * Tested traffic patterns. + */ +enum class WifiTrafficPattern : uint8_t +{ + STA_TO_STA = 0, + STA_TO_AP, + AP_TO_STA, + AP_TO_BCAST, + STA_TO_BCAST +}; + +/** + * Block Ack agreement enabled/disabled + */ +enum class WifiBaEnabled : uint8_t +{ + NO = 0, + YES +}; + +/** + * Whether to send a BlockAckReq after a missed BlockAck + */ +enum class WifiUseBarAfterMissedBa : uint8_t +{ + NO = 0, + YES +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test data transmission between two MLDs. + * + * This test sets up an AP MLD and two non-AP MLDs having a variable number of links. + * The RF channels to set each link to are provided as input parameters through the test + * case constructor, along with the identifiers (starting at 0) of the links that cannot + * switch PHY band (if any). This test aims at veryfing the successful transmission of both + * unicast QoS data frames (from one station to another, from one station to the AP, from + * the AP to the station) and broadcast QoS data frames (from the AP or from one station). + * In the scenarios in which the AP forwards frames (i.e., from one station to another and + * from one station to broadcast) the client application generates only 4 packets, in order + * to limit the probability of collisions. In the other scenarios, 8 packets are generated. + * When BlockAck agreements are enabled, the maximum A-MSDU size is set such that two + * packets can be aggregated in an A-MSDU. The MPDU with sequence number equal to 1 is + * corrupted (once, by using a post reception error model) to test its successful + * re-transmission, unless the traffic scenario is from the AP to broadcast (broadcast frames + * are not retransmitted) or is a scenario where the AP forwards frame (to limit the + * probability of collisions). + * + * When BlockAck agreements are enabled, we also corrupt a BlockAck frame, so as to simulate + * the case of BlockAck timeout. Both the case where a BlockAckReq is sent and the case where + * data frame are retransmitted are tested. Finally, when BlockAck agreements are enabled, we + * also enable the concurrent transmission of data frames over two links and check that at + * least one MPDU is concurrently transmitted over two links. + */ +class MultiLinkTxTest : public MultiLinkOperationsTestBase +{ + public: + /** + * Constructor + * + * \param baseParams common configuration parameters + * \param trafficPattern the pattern of traffic to generate + * \param baEnabled whether BA agreement is enabled or disabled + * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck + * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight + * (unused if Block Ack agreements are not established) + */ + MultiLinkTxTest(const BaseParams& baseParams, + WifiTrafficPattern trafficPattern, + WifiBaEnabled baEnabled, + WifiUseBarAfterMissedBa useBarAfterMissedBa, + uint8_t nMaxInflight); + ~MultiLinkTxTest() override = default; + + protected: + /** + * Check the content of a received BlockAck frame when the max number of links on which + * an MPDU can be inflight is one. + * + * \param psdu the PSDU containing the BlockAck + * \param txVector the TXVECTOR used to transmit the BlockAck + * \param linkId the ID of the link on which the BlockAck was transmitted + */ + void CheckBlockAck(Ptr psdu, const WifiTxVector& txVector, uint8_t linkId); + + void Transmit(Ptr mac, + uint8_t phyId, + WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW) override; + void DoSetup() override; + void DoRun() override; + + private: + void StartTraffic() override; + + /// Receiver address-indexed map of list error models + using RxErrorModelMap = std::unordered_map, WifiAddressHash>; + + RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets + std::list m_uidList; ///< list of UIDs of packets to corrupt + bool m_dataCorrupted{false}; ///< whether second data frame has been already corrupted + WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate + bool m_baEnabled; ///< whether BA agreement is enabled or disabled + bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck + std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight + std::size_t m_nPackets; ///< number of application packets to generate + std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter + std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter + std::map m_inflightCount; ///< seqNo-indexed max number of simultaneous + ///< transmissions of a data frame + Ptr m_sourceMac; ///< MAC of the node sending application packets +}; + +/** + * Tested MU traffic patterns. + */ +enum class WifiMuTrafficPattern : uint8_t +{ + DL_MU_BAR_BA_SEQUENCE = 0, + DL_MU_MU_BAR, + DL_MU_AGGR_MU_BAR, + UL_MU +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test data transmission between MLDs using OFDMA MU transmissions + * + * This test sets up an AP MLD and two non-AP MLDs having a variable number of links. + * The RF channels to set each link to are provided as input parameters through the test + * case constructor, along with the identifiers (starting at 0) of the links that cannot + * switch PHY band (if any). This test aims at veryfing the successful transmission of both + * DL MU and UL MU frames. In the DL MU scenarios, the client applications installed on the + * AP generate 8 packets addressed to each of the stations (plus 3 packets to trigger the + * establishment of BlockAck agreements). In the UL MU scenario, client applications + * installed on the stations generate 4 packets each (plus 3 packets to trigger the + * establishment of BlockAck agreements). + * + * The maximum A-MSDU size is set such that two packets can be aggregated in an A-MSDU. + * The MPDU with sequence number equal to 3 is corrupted (by using a post reception error + * model) once and for a single station, to test its successful re-transmission. + * + * Also, we enable the concurrent transmission of data frames over two links and check that at + * least one MPDU is concurrently transmitted over two links. + */ +class MultiLinkMuTxTest : public MultiLinkOperationsTestBase +{ + public: + /** + * Constructor + * + * \param baseParams common configuration parameters + * \param muTrafficPattern the pattern of traffic to generate + * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck + * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight + * (unused if Block Ack agreements are not established) + */ + MultiLinkMuTxTest(const BaseParams& baseParams, + WifiMuTrafficPattern muTrafficPattern, + WifiUseBarAfterMissedBa useBarAfterMissedBa, + uint8_t nMaxInflight); + ~MultiLinkMuTxTest() override = default; + + protected: + /** + * Check the content of a received BlockAck frame when the max number of links on which + * an MPDU can be inflight is one. + * + * \param psdu the PSDU containing the BlockAck + * \param txVector the TXVECTOR used to transmit the BlockAck + * \param linkId the ID of the link on which the BlockAck was transmitted + */ + void CheckBlockAck(Ptr psdu, const WifiTxVector& txVector, uint8_t linkId); + + void Transmit(Ptr mac, + uint8_t phyId, + WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW) override; + void DoSetup() override; + void DoRun() override; + + private: + void StartTraffic() override; + + /// Receiver address-indexed map of list error models + using RxErrorModelMap = std::unordered_map, WifiAddressHash>; + + /// A pair of a MAC address (the address of the receiver for DL frames and the address of + /// the sender for UL frames) and a sequence number identifying a transmitted QoS data frame + using AddrSeqNoPair = std::pair; + + RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets + std::list m_uidList; ///< list of UIDs of packets to corrupt + std::optional m_dataCorruptedSta; ///< MAC address of the station that received + ///< MPDU with SeqNo=2 corrupted + bool m_waitFirstTf{true}; ///< whether we are waiting for the first Basic Trigger Frame + WifiMuTrafficPattern m_muTrafficPattern; ///< the pattern of traffic to generate + bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck + std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight + std::vector m_sockets; ///< packet socket addresses for STAs + std::size_t m_nPackets; ///< number of application packets to generate + std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter + std::size_t m_tfCount{0}; ///< transmitted Trigger Frame counter + // std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter + std::map m_inflightCount; ///< max number of simultaneous + ///< transmissions of each data frame + Ptr m_sourceMac; ///< MAC of the node sending application packets +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test release of sequence numbers upon CTS timeout in multi-link operations + * + * In this test, an AP MLD and a non-AP MLD setup 3 links. Usage of RTS/CTS protection is + * enabled for frames whose length is at least 1000 bytes. The AP MLD receives a first set + * of 4 packets from the upper layer and sends an RTS frame, which is corrupted at the + * receiver, on a first link. When the RTS frame is transmitted, the AP MLD receives another + * set of 4 packets, which are transmitted after a successful RTS/CTS exchange on a second + * link. In the meantime, a new RTS/CTS exchange is successfully carried out (on the first + * link or on the third link) to transmit the first set of 4 packets. When the transmission + * of the first set of 4 packets starts, the AP MLD receives the third set of 4 packets from + * the upper layer, which are transmitted after a successful RTS/CTS exchange. + * + * This test checks that sequence numbers are correctly assigned to all the MPDUs carrying data. + */ +class ReleaseSeqNoAfterCtsTimeoutTest : public MultiLinkOperationsTestBase +{ + public: + ReleaseSeqNoAfterCtsTimeoutTest(); + ~ReleaseSeqNoAfterCtsTimeoutTest() override = default; + + protected: + void DoSetup() override; + void DoRun() override; + void Transmit(Ptr mac, + uint8_t phyId, + WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW) override; + + private: + void StartTraffic() override; + + PacketSocketAddress m_sockAddr; //!< packet socket address + std::size_t m_nQosDataFrames; //!< counter for transmitted QoS data frames + Ptr m_errorModel; //!< error rate model to corrupt first RTS frame + bool m_rtsCorrupted; //!< whether the first RTS frame has been corrupted +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test update of BA starting sequence number after ADDBA Response timeout in + * multi-link operations + * + * In this test, an AP MLD and a non-AP MLD setup 2 links. The AP MLD has a QoS data frame to + * transmit to the non-AP MLD, which triggers the establishment of a BA agreement. When the ADDBA + * Request frame is received by the non-AP MLD, transmissions of the non-AP MLD are blocked to put + * the transmission of the ADDBA Response on hold. The goal is to mimic a delay in getting channel + * access due to, e.g., other devices grabbing the medium. When the ADDBA Response timer at the AP + * MLD expires, transmissions of the non-AP MLD are unblocked, so that the AP MLD sends the QoS data + * frame (protected by RTS, but the test works without RTS as well, and using Normal acknowledgment) + * on one link and the non-AP MLD sends the ADDBA Response on the other link. The transmission of + * the QoS data frame is then corrupted. We verify that: + * + * - when the AP MLD receives the ADDBA Response, the BA starting sequence number is set to the + * sequence number of the QoS data frame which is inflight + * - the QoS data frame is retransmitted and received by the non-AP MLD + */ +class StartSeqNoUpdateAfterAddBaTimeoutTest : public MultiLinkOperationsTestBase +{ + public: + StartSeqNoUpdateAfterAddBaTimeoutTest(); + + private: + void DoSetup() override; + void DoRun() override; + void Transmit(Ptr mac, + uint8_t phyId, + WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW) override; + void StartTraffic() override; + + PacketSocketAddress m_sockAddr; //!< packet socket address + std::size_t m_nQosDataCount; //!< counter for transmitted QoS data frames + Ptr m_staErrorModel; //!< error rate model to corrupt frames at the non-AP MLD +}; + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief wifi 11be MLD Test Suite + */ +class WifiMultiLinkOperationsTestSuite : public TestSuite +{ + public: + WifiMultiLinkOperationsTestSuite(); +}; + +#endif /* WIFI_MLO_TEST_H */