From 35d49214028523bd5dae222226a166e66ec5ce95 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Fri, 3 May 2024 17:25:07 +0200 Subject: [PATCH] wifi: Add new WifiMac::Enqueue methods to avoid code duplication At this stage, these methods are not yet used. --- src/mesh/model/mesh-wifi-interface-mac.cc | 45 +++++++++++++ src/mesh/model/mesh-wifi-interface-mac.h | 1 + src/wifi/model/adhoc-wifi-mac.cc | 56 ++++++++++++++++ src/wifi/model/adhoc-wifi-mac.h | 1 + src/wifi/model/ap-wifi-mac.cc | 49 ++++++++++++++ src/wifi/model/ap-wifi-mac.h | 1 + src/wifi/model/sta-wifi-mac.cc | 32 ++++++++++ src/wifi/model/sta-wifi-mac.h | 2 + src/wifi/model/wifi-mac.cc | 78 +++++++++++++++++++++-- src/wifi/model/wifi-mac.h | 44 +++++++++++-- src/wifi/test/wifi-mlo-test.cc | 4 ++ 11 files changed, 302 insertions(+), 11 deletions(-) diff --git a/src/mesh/model/mesh-wifi-interface-mac.cc b/src/mesh/model/mesh-wifi-interface-mac.cc index 1ff9e94e3..b65e4e063 100644 --- a/src/mesh/model/mesh-wifi-interface-mac.cc +++ b/src/mesh/model/mesh-wifi-interface-mac.cc @@ -222,6 +222,51 @@ MeshWifiInterfaceMac::SwitchFrequencyChannel(uint16_t new_id) //----------------------------------------------------------------------------- // Forward frame down //----------------------------------------------------------------------------- +void +MeshWifiInterfaceMac::Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION(this << *mpdu << to << from); + + auto& hdr = mpdu->GetHeader(); + auto packet = mpdu->GetPacket()->Copy(); + + hdr.SetAddr2(GetAddress()); + hdr.SetAddr3(to); + hdr.SetAddr4(from); + hdr.SetDsFrom(); + hdr.SetDsTo(); + // Address 1 is unknown here. Routing plugin is responsible to correctly set it. + hdr.SetAddr1(Mac48Address()); + // Filter packet through all installed plugins + for (auto i = m_plugins.end() - 1; i != m_plugins.begin() - 1; i--) + { + bool drop = !((*i)->UpdateOutcomingFrame(packet, hdr, from, to)); + if (drop) + { + return; // plugin drops frame + } + } + // Assert that address1 is set. Assert will fail e.g. if there is no installed routing plugin. + NS_ASSERT(hdr.GetAddr1() != Mac48Address()); + // Queue frame + if (GetWifiRemoteStationManager()->IsBrandNew(hdr.GetAddr1())) + { + // in adhoc mode, we assume that every destination + // supports all the rates we support. + for (const auto& mode : GetWifiPhy()->GetModeList()) + { + GetWifiRemoteStationManager()->AddSupportedMode(hdr.GetAddr1(), mode); + } + GetWifiRemoteStationManager()->RecordDisassociated(hdr.GetAddr1()); + } + + m_stats.sentFrames++; + m_stats.sentBytes += packet->GetSize(); + auto tid = hdr.GetQosTid(); + NS_ASSERT(GetQosTxop(tid) != nullptr); + GetQosTxop(tid)->Queue(Create(packet, hdr)); +} + void MeshWifiInterfaceMac::ForwardDown(Ptr packet, Mac48Address from, Mac48Address to) { diff --git a/src/mesh/model/mesh-wifi-interface-mac.h b/src/mesh/model/mesh-wifi-interface-mac.h index a4570b10f..db78ef6cb 100644 --- a/src/mesh/model/mesh-wifi-interface-mac.h +++ b/src/mesh/model/mesh-wifi-interface-mac.h @@ -264,6 +264,7 @@ class MeshWifiInterfaceMac : public WifiMac typedef std::vector> PluginList; ///< PluginList typedef void DoInitialize() override; + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override; /// \name Mesh timing intervals ///@{ diff --git a/src/wifi/model/adhoc-wifi-mac.cc b/src/wifi/model/adhoc-wifi-mac.cc index 3c5341675..704915d6a 100644 --- a/src/wifi/model/adhoc-wifi-mac.cc +++ b/src/wifi/model/adhoc-wifi-mac.cc @@ -71,6 +71,62 @@ AdhocWifiMac::CanForwardPacketsTo(Mac48Address to) const return true; } +void +AdhocWifiMac::Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION(this << *mpdu << to << from); + + if (GetWifiRemoteStationManager()->IsBrandNew(to)) + { + // In ad hoc mode, we assume that every destination supports all the rates we support. + if (GetHtSupported(SINGLE_LINK_OP_ID)) + { + GetWifiRemoteStationManager()->AddAllSupportedMcs(to); + GetWifiRemoteStationManager()->AddStationHtCapabilities( + to, + GetHtCapabilities(SINGLE_LINK_OP_ID)); + } + if (GetVhtSupported(SINGLE_LINK_OP_ID)) + { + GetWifiRemoteStationManager()->AddStationVhtCapabilities( + to, + GetVhtCapabilities(SINGLE_LINK_OP_ID)); + } + if (GetHeSupported()) + { + GetWifiRemoteStationManager()->AddStationHeCapabilities( + to, + GetHeCapabilities(SINGLE_LINK_OP_ID)); + if (Is6GhzBand(SINGLE_LINK_OP_ID)) + { + GetWifiRemoteStationManager()->AddStationHe6GhzCapabilities( + to, + GetHe6GhzBandCapabilities(SINGLE_LINK_OP_ID)); + } + } + if (GetEhtSupported()) + { + GetWifiRemoteStationManager()->AddStationEhtCapabilities( + to, + GetEhtCapabilities(SINGLE_LINK_OP_ID)); + } + GetWifiRemoteStationManager()->AddAllSupportedModes(to); + GetWifiRemoteStationManager()->RecordDisassociated(to); + } + + auto& hdr = mpdu->GetHeader(); + + hdr.SetAddr1(to); + hdr.SetAddr2(GetAddress()); + hdr.SetAddr3(GetBssid(SINGLE_LINK_OP_ID)); + hdr.SetDsNotFrom(); + hdr.SetDsNotTo(); + + auto txop = hdr.IsQosData() ? StaticCast(GetQosTxop(hdr.GetQosTid())) : GetTxop(); + NS_ASSERT(txop); + txop->Queue(mpdu); +} + void AdhocWifiMac::Enqueue(Ptr packet, Mac48Address to) { diff --git a/src/wifi/model/adhoc-wifi-mac.h b/src/wifi/model/adhoc-wifi-mac.h index 43b894935..ed82e3804 100644 --- a/src/wifi/model/adhoc-wifi-mac.h +++ b/src/wifi/model/adhoc-wifi-mac.h @@ -51,6 +51,7 @@ class AdhocWifiMac : public WifiMac private: void Receive(Ptr mpdu, uint8_t linkId) override; void DoCompleteConfig() override; + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override; }; } // namespace ns3 diff --git a/src/wifi/model/ap-wifi-mac.cc b/src/wifi/model/ap-wifi-mac.cc index 0ec1c2786..39a1678e5 100644 --- a/src/wifi/model/ap-wifi-mac.cc +++ b/src/wifi/model/ap-wifi-mac.cc @@ -525,6 +525,55 @@ ApWifiMac::Enqueue(Ptr packet, Mac48Address to) Enqueue(packet, to, GetAddress()); } +void +ApWifiMac::Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION(this << *mpdu << to << from); + + std::list addr2Set; + if (to.IsGroup()) + { + // broadcast frames are transmitted on all the links + for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++) + { + addr2Set.push_back(GetFrameExchangeManager(linkId)->GetAddress()); + } + } + else + { + // the Transmitter Address (TA) is the MLD address only for non-broadcast data frames + // exchanged between two MLDs + addr2Set = {GetAddress()}; + auto linkId = IsAssociated(to); + NS_ASSERT_MSG(linkId, "Station " << to << "is not associated, cannot send it a frame"); + if (GetNLinks() == 1 || !GetWifiRemoteStationManager(*linkId)->GetMldAddress(to)) + { + addr2Set = {GetFrameExchangeManager(*linkId)->GetAddress()}; + } + } + + for (auto addr2 = addr2Set.cbegin(); addr2 != addr2Set.cend(); ++addr2) + { + auto& hdr = mpdu->GetHeader(); + + hdr.SetAddr1(to); + hdr.SetAddr2(*addr2); + hdr.SetAddr3(from); + hdr.SetDsFrom(); + hdr.SetDsNotTo(); + + auto txop = hdr.IsQosData() ? StaticCast(GetQosTxop(hdr.GetQosTid())) : GetTxop(); + NS_ASSERT(txop); + txop->Queue(mpdu); + + // create another MPDU if needed + if (std::next(addr2) != addr2Set.cend()) + { + mpdu = Create(mpdu->GetPacket()->Copy(), hdr); + } + } +} + bool ApWifiMac::SupportsSendFrom() const { diff --git a/src/wifi/model/ap-wifi-mac.h b/src/wifi/model/ap-wifi-mac.h index da2aae896..c4c62877f 100644 --- a/src/wifi/model/ap-wifi-mac.h +++ b/src/wifi/model/ap-wifi-mac.h @@ -266,6 +266,7 @@ class ApWifiMac : public WifiMac Mac48Address DoGetLocalAddress(const Mac48Address& remoteAddr) const override; void Receive(Ptr mpdu, uint8_t linkId) override; void DoCompleteConfig() override; + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override; /** * Check whether the supported rate set included in the received (Re)Association diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index aa8b20efb..a655cc60f 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -972,6 +972,38 @@ StaWifiMac::CanForwardPacketsTo(Mac48Address to) const return IsAssociated(); } +void +StaWifiMac::NotifyDropPacketToEnqueue(Ptr packet, Mac48Address to) +{ + NS_LOG_FUNCTION(this << packet << to); + TryToEnsureAssociated(); +} + +void +StaWifiMac::Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION(this << *mpdu << to << from); + + auto& hdr = mpdu->GetHeader(); + + // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for + // non-broadcast data frames exchanged between two MLDs + auto linkIds = GetSetupLinkIds(); + NS_ASSERT(!linkIds.empty()); + uint8_t linkId = *linkIds.begin(); + const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId)); + + hdr.SetAddr1(apMldAddr.value_or(GetBssid(linkId))); + hdr.SetAddr2(apMldAddr ? GetAddress() : GetFrameExchangeManager(linkId)->GetAddress()); + hdr.SetAddr3(to); + hdr.SetDsNotFrom(); + hdr.SetDsTo(); + + auto txop = hdr.IsQosData() ? StaticCast(GetQosTxop(hdr.GetQosTid())) : GetTxop(); + NS_ASSERT(txop); + txop->Queue(mpdu); +} + void StaWifiMac::Enqueue(Ptr packet, Mac48Address to) { diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index 92a97a3d4..5f0cd61b7 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -410,6 +410,8 @@ class StaWifiMac : public WifiMac void Receive(Ptr mpdu, uint8_t linkId) override; std::unique_ptr CreateLinkEntity() const override; Mac48Address DoGetLocalAddress(const Mac48Address& remoteAddr) const override; + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override; + void NotifyDropPacketToEnqueue(Ptr packet, Mac48Address to) override; /** * Process the Beacon frame received on the given link. diff --git a/src/wifi/model/wifi-mac.cc b/src/wifi/model/wifi-mac.cc index 5dbc6081a..8580becad 100644 --- a/src/wifi/model/wifi-mac.cc +++ b/src/wifi/model/wifi-mac.cc @@ -37,6 +37,7 @@ #include "ns3/packet.h" #include "ns3/pointer.h" #include "ns3/shuffle.h" +#include "ns3/socket.h" #include "ns3/string.h" #include "ns3/vht-configuration.h" @@ -1617,15 +1618,80 @@ WifiMac::UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, } } +void +WifiMac::Enqueue(Ptr packet, Mac48Address to) +{ + NS_LOG_FUNCTION(this << packet << to); + // We're sending this packet with a from address that is our own. We + // get that address from the lower MAC and make use of the + // from-spoofing Enqueue() method to avoid duplicated code. + Enqueue(packet, to, GetAddress()); +} + void WifiMac::Enqueue(Ptr packet, Mac48Address to, Mac48Address from) { - // We expect WifiMac subclasses which do support forwarding (e.g., - // AP) to override this method. Therefore, we throw a fatal error if - // someone tries to invoke this method on a class which has not done - // this. - NS_FATAL_ERROR("This MAC entity (" << this << ", " << GetAddress() - << ") does not support Enqueue() with from address"); + NS_LOG_FUNCTION(this << packet << to << from); + + // If we are not a QoS AP then we definitely want to use AC_BE to + // transmit the packet. A TID of zero will map to AC_BE (through \c + // QosUtilsMapTidToAc()), so we use that as our default here. + uint8_t tid = 0; + + SocketPriorityTag qos; + if (packet->RemovePacketTag(qos) && qos.GetPriority() < 8) + { + tid = qos.GetPriority(); + } + + Enqueue(packet, to, from, tid); +} + +void +WifiMac::Enqueue(Ptr packet, Mac48Address to, Mac48Address from, uint8_t tid) +{ + NS_LOG_FUNCTION(this << packet << to << from << tid); + + NS_ABORT_MSG_IF(!SupportsSendFrom() && from != GetAddress(), + "This Mac does not support forwarding frames"); + + if (!CanForwardPacketsTo(to)) + { + NotifyTxDrop(packet); + NotifyDropPacketToEnqueue(packet, to); + return; + } + + WifiMacHeader hdr; + + // For now, an AP that supports QoS does not support non-QoS + // associations, and vice versa. In future the AP model should + // support simultaneously associated QoS and non-QoS STAs, at which + // point there will need to be per-association QoS state maintained + // by the association state machine, and consulted here. + if (GetQosSupported()) + { + hdr.SetType(WIFI_MAC_QOSDATA); + hdr.SetQosAckPolicy(WifiMacHeader::NORMAL_ACK); + hdr.SetQosNoEosp(); + hdr.SetQosNoAmsdu(); + hdr.SetQosTid(tid); + hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not + // yet implemented (set it to 1 when implemented) + } + else + { + hdr.SetType(WIFI_MAC_DATA); + } + + // create an MPDU and pass it to subclasses to finalize MAC header + Enqueue(Create(packet, hdr), to, from); +} + +void +WifiMac::NotifyDropPacketToEnqueue(Ptr packet, Mac48Address to) +{ + NS_LOG_FUNCTION(this << packet << to); } void diff --git a/src/wifi/model/wifi-mac.h b/src/wifi/model/wifi-mac.h index 20605a948..9a6763f78 100644 --- a/src/wifi/model/wifi-mac.h +++ b/src/wifi/model/wifi-mac.h @@ -370,27 +370,43 @@ class WifiMac : public Object * \return whether packets can be forwarded to the given destination */ virtual bool CanForwardPacketsTo(Mac48Address to) const = 0; + + /** + * \param packet the packet to send. + * \param to the address to which the packet should be sent. + * + * The packet should be enqueued in a TX queue, and should be + * dequeued as soon as the DCF/EDCA function determines that + * access is granted to this MAC. + */ + virtual void Enqueue(Ptr packet, Mac48Address to); + /** * \param packet the packet to send. * \param to the address to which the packet should be sent. * \param from the address from which the packet should be sent. * * The packet should be enqueued in a TX queue, and should be - * dequeued as soon as the DCF function determines that - * access it granted to this MAC. The extra parameter "from" allows + * dequeued as soon as the DCF/EDCA function determines that + * access is granted to this MAC. The extra parameter "from" allows * this device to operate in a bridged mode, forwarding received * frames without altering the source address. */ virtual void Enqueue(Ptr packet, Mac48Address to, Mac48Address from); + /** * \param packet the packet to send. * \param to the address to which the packet should be sent. + * \param from the address from which the packet should be sent. + * \param tid the TID to use to send this packet * * The packet should be enqueued in a TX queue, and should be - * dequeued as soon as the DCF function determines that - * access it granted to this MAC. + * dequeued as soon as the DCF/EDCA function determines that + * access is granted to this MAC. The extra parameter "tid" allows + * to specify the TID to use in case QoS is supported. */ - virtual void Enqueue(Ptr packet, Mac48Address to) = 0; + void Enqueue(Ptr packet, Mac48Address to, Mac48Address from, uint8_t tid); + /** * \return if this MAC supports sending from arbitrary address. * @@ -1114,6 +1130,24 @@ class WifiMac : public Object */ void SetBkBlockAckInactivityTimeout(uint16_t timeout); + /** + * \param mpdu the MPDU to send. + * \param to the address to which the packet should be sent. + * \param from the address from which the packet should be sent. + * + * Subclasses need to implement this method to finalize the MAC header of the MPDU + * (MAC addresses and ToDS/FromDS flags) and enqueue the MPDU in a TX queue. + */ + virtual void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) = 0; + + /** + * Allow subclasses to take actions when a packet to enqueue has been dropped. + * + * \param packet the dropped packet + * \param to the address to which the packet should have been sent + */ + virtual void NotifyDropPacketToEnqueue(Ptr packet, Mac48Address to); + /** * This Boolean is set \c true iff this WifiMac is to model * 802.11e/WMM style Quality of Service. It is exposed through the diff --git a/src/wifi/test/wifi-mlo-test.cc b/src/wifi/test/wifi-mlo-test.cc index 8c267cbe5..92831c8fe 100644 --- a/src/wifi/test/wifi-mlo-test.cc +++ b/src/wifi/test/wifi-mlo-test.cc @@ -221,6 +221,10 @@ class MldSwapLinksTest : public TestCase void DoCompleteConfig() override { } + + void Enqueue(Ptr mpdu, Mac48Address to, Mac48Address from) override + { + } }; public: