1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 University of Washington
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Authors: Sébastien Deronne <sebastien.deronne@gmail.com>
19  *          Scott Carpenter <scarpenter44@windstream.net>
20  */
21 
22 #include "ns3/log.h"
23 #include "ns3/test.h"
24 #include "ns3/uinteger.h"
25 #include "ns3/double.h"
26 #include "ns3/string.h"
27 #include "ns3/pointer.h"
28 #include "ns3/config.h"
29 #include "ns3/ssid.h"
30 #include "ns3/rng-seed-manager.h"
31 #include "ns3/mobility-helper.h"
32 #include "ns3/wifi-net-device.h"
33 #include "ns3/spectrum-wifi-helper.h"
34 #include "ns3/multi-model-spectrum-channel.h"
35 #include "ns3/constant-obss-pd-algorithm.h"
36 #include "ns3/he-configuration.h"
37 #include "ns3/wifi-utils.h"
38 
39 using namespace ns3;
40 
41 NS_LOG_COMPONENT_DEFINE ("InterBssTestSuite");
42 
43 static uint32_t
ConvertContextToNodeId(std::string context)44 ConvertContextToNodeId (std::string context)
45 {
46   std::string sub = context.substr (10);
47   uint32_t pos = sub.find ("/Device");
48   uint32_t nodeId = atoi (sub.substr (0, pos).c_str ());
49   return nodeId;
50 }
51 
52 /**
53  * \ingroup wifi-test
54  * \ingroup tests
55  *
56  * \brief Wifi Test
57  *
58  * This test case tests the transmission of inter-BSS cases
59  * and verify behavior of 11ax OBSS_PD spatial reuse.
60  *
61  * The topology for this test case is made of three networks, each with one AP and one STA:
62  *
63  *  AP  --d1--  STA1  --d2--  AP2  --d3-- STA2 --d4--  AP3  --d5-- STA3
64  *  TX1         RX1           TX2         RX2          TX3         RX3
65  *
66  * Main parameters:
67  *  OBSS_PD level = -72dbm
68  *  Received Power by TX1 from TX2 = [-62dbm, -82dbm]
69  *  Received SINR by RX1 from TX1 > 3dB (enough to pass MCS0 reception)
70  *  Received SINR by RX2 from TX2 > 3dB (enough to pass MCS0 reception)
71  *  Received SINR by RX3 from TX3 > 3dB (enough to pass MCS0 reception)
72  *  TX1/RX1 BSS Color = 1
73  *  TX2/RX2 transmission PPDU BSS Color = [2 0]
74  *  TX3/RX3 BSS color = 3 (BSS 3 only used to test some corner cases)
75  *  PHY = 11ax, MCS 0, 80MHz
76  */
77 
78 class TestInterBssConstantObssPdAlgo : public TestCase
79 {
80 public:
81   TestInterBssConstantObssPdAlgo ();
82   ~TestInterBssConstantObssPdAlgo ();
83 
84   void DoRun (void) override;
85 
86 private:
87   /**
88    * Send one packet function
89    * \param tx_dev the transmitting device
90    * \param rx_dev the receiving device
91    * \param payloadSize the payload size
92    */
93   void SendOnePacket (Ptr<WifiNetDevice> tx_dev, Ptr<WifiNetDevice> rx_dev, uint32_t payloadSize);
94 
95   /**
96    * Allocate the node positions
97    * \param d1 distance d1 (in meters)
98    * \param d2 distance d2 (in meters)
99    * \param d3 distance d3 (in meters)
100    * \param d4 distance d4 (in meters)
101    * \param d5 distance d5 (in meters)
102    * \return the node positions
103    */
104   Ptr<ListPositionAllocator> AllocatePositions (double d1, double d2, double d3, double d4, double d5);
105 
106   /**
107    * Set the expected transmit power in dBm
108    * \param txPowerDbm the transmit power in dBm
109    */
110   void SetExpectedTxPower (double txPowerDbm);
111 
112   /**
113    * Setup the simulation
114    */
115   void SetupSimulation ();
116 
117   /**
118    * Check the results
119    */
120   void CheckResults ();
121 
122   /**
123    * Reset the results
124    */
125   void ResetResults ();
126 
127   /**
128    * Clear the drop reasons
129    */
130   void ClearDropReasons ();
131 
132   /**
133    * Run one function
134    */
135   void RunOne ();
136 
137   /**
138    * Check if the Phy State for a device is an expected value
139    * \param device the device to check
140    * \param expectedState the expected PHY state
141    */
142   void CheckPhyState (Ptr<WifiNetDevice> device, WifiPhyState expectedState);
143 
144   /**
145    * Check if the Phy drop reasons for a device are as expected
146    * \param device the device to check
147    * \param expectedDropReasons the expected PHY drop reasons
148    */
149   void CheckPhyDropReasons (Ptr<WifiNetDevice> device, std::vector<WifiPhyRxfailureReason> expectedDropReasons);
150 
151   /**
152    * Notify Phy transmit begin
153    * \param context the context
154    * \param p the packet
155    * \param txPowerW the tx power
156    */
157   void NotifyPhyTxBegin (std::string context, Ptr<const Packet> p, double txPowerW);
158 
159   /**
160    * Notify Phy receive ends
161    * \param context the context
162    * \param p the packet
163    */
164   void NotifyPhyRxEnd (std::string context, Ptr<const Packet> p);
165 
166   /**
167    * Notify Phy receive drops
168    * \param context the context
169    * \param p the packet
170    * \param reason the reason why it was dropped
171    */
172   void NotifyPhyRxDrop (std::string context, Ptr<const Packet> p, WifiPhyRxfailureReason reason);
173 
174   unsigned int m_numSta1PacketsSent; ///< number of sent packets from STA1
175   unsigned int m_numSta2PacketsSent; ///< number of sent packets from STA2
176   unsigned int m_numAp1PacketsSent; ///< number of sent packets from AP1
177   unsigned int m_numAp2PacketsSent; ///< number of sent packets from AP2
178 
179   unsigned int m_numSta1PacketsReceived; ///< number of received packets from STA1
180   unsigned int m_numSta2PacketsReceived; ///< number of received packets from STA2
181   unsigned int m_numAp1PacketsReceived; ///< number of received packets from AP1
182   unsigned int m_numAp2PacketsReceived; ///< number of received packets from AP2
183 
184   std::vector<WifiPhyRxfailureReason> m_dropReasonsSta1; ///< drop reasons for STA1
185   std::vector<WifiPhyRxfailureReason> m_dropReasonsSta2; ///< drop reasons for STA2
186   std::vector<WifiPhyRxfailureReason> m_dropReasonsAp1; ///< drop reasons for AP1
187   std::vector<WifiPhyRxfailureReason> m_dropReasonsAp2; ///< drop reasons for AP2
188 
189   unsigned int m_payloadSize1; ///< size in bytes of packet payload in BSS 1
190   unsigned int m_payloadSize2; ///< size in bytes of packet payload in BSS 2
191   unsigned int m_payloadSize3; ///< size in bytes of packet payload in BSS 3
192 
193   NetDeviceContainer m_staDevices; ///< STA devices
194   NetDeviceContainer m_apDevices;  ///< AP devices
195 
196   double m_txPowerDbm;         ///< configured transmit power in dBm
197   double m_obssPdLevelDbm;     ///< OBSS-PD level in dBm
198   double m_obssRxPowerDbm;     ///< forced RX power in dBm for OBSS
199   double m_expectedTxPowerDbm; ///< expected transmit power in dBm
200 
201   uint8_t m_bssColor1; ///< color for BSS 1
202   uint8_t m_bssColor2; ///< color for BSS 2
203   uint8_t m_bssColor3; ///< color for BSS 3
204 };
205 
TestInterBssConstantObssPdAlgo()206 TestInterBssConstantObssPdAlgo::TestInterBssConstantObssPdAlgo ()
207   : TestCase ("InterBssConstantObssPd"),
208     m_numSta1PacketsSent (0),
209     m_numSta2PacketsSent (0),
210     m_numAp1PacketsSent (0),
211     m_numAp2PacketsSent (0),
212     m_numSta1PacketsReceived (0),
213     m_numSta2PacketsReceived (0),
214     m_numAp1PacketsReceived (0),
215     m_numAp2PacketsReceived (0),
216     m_payloadSize1 (1000),
217     m_payloadSize2 (1500),
218     m_payloadSize3 (2000),
219     m_txPowerDbm (15),
220     m_obssPdLevelDbm (-72),
221     m_obssRxPowerDbm (-82),
222     m_expectedTxPowerDbm (15),
223     m_bssColor1 (1),
224     m_bssColor2 (2),
225     m_bssColor3 (3)
226 {
227 }
228 
~TestInterBssConstantObssPdAlgo()229 TestInterBssConstantObssPdAlgo::~TestInterBssConstantObssPdAlgo ()
230 {
231   ClearDropReasons ();
232 }
233 
234 Ptr<ListPositionAllocator>
AllocatePositions(double d1,double d2,double d3,double d4,double d5)235 TestInterBssConstantObssPdAlgo::AllocatePositions (double d1, double d2, double d3, double d4, double d5)
236 {
237   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
238   positionAlloc->Add (Vector (0.0, 0.0, 0.0));  // AP1
239   positionAlloc->Add (Vector (d1 + d2, 0.0, 0.0));  // AP2
240   positionAlloc->Add (Vector (d1 + d2 + d3 + d4, 0.0, 0.0));  // AP3
241   positionAlloc->Add (Vector (d1, 0.0, 0.0));  // STA1
242   positionAlloc->Add (Vector (d1 + d2 + d3, 0.0, 0.0));  // STA2
243   positionAlloc->Add (Vector (d1 + d2 + d3 + d4 + d5, 0.0, 0.0));  // STA3
244   return positionAlloc;
245 }
246 
247 void
SetupSimulation()248 TestInterBssConstantObssPdAlgo::SetupSimulation ()
249 {
250   Ptr<WifiNetDevice> ap_device1 = DynamicCast<WifiNetDevice> (m_apDevices.Get (0));
251   Ptr<WifiNetDevice> ap_device2 = DynamicCast<WifiNetDevice> (m_apDevices.Get (1));
252   Ptr<WifiNetDevice> ap_device3 = DynamicCast<WifiNetDevice> (m_apDevices.Get (2));
253   Ptr<WifiNetDevice> sta_device1 = DynamicCast<WifiNetDevice> (m_staDevices.Get (0));
254   Ptr<WifiNetDevice> sta_device2 = DynamicCast<WifiNetDevice> (m_staDevices.Get (1));
255   Ptr<WifiNetDevice> sta_device3 = DynamicCast<WifiNetDevice> (m_staDevices.Get (2));
256 
257   bool expectFilter = (m_bssColor1 != 0) && (m_bssColor2 != 0);
258   bool expectPhyReset = expectFilter && (m_obssPdLevelDbm >= m_obssRxPowerDbm);
259   std::vector<WifiPhyRxfailureReason> dropReasons;
260   WifiPhyState stateDuringPayloadNeighboringBss = expectFilter ? WifiPhyState::CCA_BUSY : WifiPhyState::RX;
261   if (expectFilter)
262     {
263       dropReasons.push_back (FILTERED);
264     }
265   if (expectPhyReset)
266     {
267       dropReasons.push_back (OBSS_PD_CCA_RESET);
268     }
269 
270   // In order to have all ADDBA handshakes established, each AP and STA sends a packet.
271 
272   Simulator::Schedule (Seconds (0.25), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device1, sta_device1, m_payloadSize1);
273   Simulator::Schedule (Seconds (0.5), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1);
274   Simulator::Schedule (Seconds (0.75), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2);
275   Simulator::Schedule (Seconds (1), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device2, ap_device2, m_payloadSize2);
276   Simulator::Schedule (Seconds (1.25), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device3, sta_device3, m_payloadSize3);
277   Simulator::Schedule (Seconds (1.5), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device3, ap_device3, m_payloadSize3);
278 
279   // We test PHY state and verify whether a CCA reset did occur.
280 
281   // AP2 sends a packet 0.5s later.
282   Simulator::Schedule (Seconds (2.0), &TestInterBssConstantObssPdAlgo::ClearDropReasons, this);
283   Simulator::Schedule (Seconds (2.0), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2);
284   Simulator::Schedule (Seconds (2.0) + MicroSeconds (5), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device2, WifiPhyState::TX);
285   // All other PHYs should have stay idle until 4us (preamble detection time).
286   Simulator::Schedule (Seconds (2.0) + MicroSeconds (6), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, WifiPhyState::IDLE);
287   Simulator::Schedule (Seconds (2.0) + MicroSeconds (6), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::IDLE);
288   Simulator::Schedule (Seconds (2.0) + MicroSeconds (6), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, WifiPhyState::IDLE);
289   // All PHYs should be receiving the PHY header (i.e. PHY state is CCA_BUSY) if preamble has been detected (always the case in this test).
290   Simulator::Schedule (Seconds (2.0) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, WifiPhyState::CCA_BUSY);
291   Simulator::Schedule (Seconds (2.0) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::CCA_BUSY);
292   Simulator::Schedule (Seconds (2.0) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, WifiPhyState::CCA_BUSY);
293   // PHYs of AP1 and STA1 should be idle after HE-SIG-A if they were reset by OBSS_PD SR, otherwise they should be CCA_busy until beginning of payload.
294   Simulator::Schedule (Seconds (2.0) + MicroSeconds (35), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, sta_device1, dropReasons);
295   Simulator::Schedule (Seconds (2.0) + MicroSeconds (35), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY);
296   Simulator::Schedule (Seconds (2.0) + MicroSeconds (35), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, ap_device1, dropReasons);
297   Simulator::Schedule (Seconds (2.0) + MicroSeconds (35), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, expectPhyReset ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY);
298   // PHYs of AP1 and STA1 should be idle if they were reset by OBSS_PD SR, otherwise they should be CCA_busy/Rx (since filtered/not filtered, resp.).
299   Simulator::Schedule (Seconds (2.0) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::IDLE : stateDuringPayloadNeighboringBss);
300   Simulator::Schedule (Seconds (2.0) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, expectPhyReset ? WifiPhyState::IDLE : stateDuringPayloadNeighboringBss);
301   // STA2 should be receiving
302   Simulator::Schedule (Seconds (2.0) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX);
303 
304   // We test whether two networks can transmit simultaneously, and whether transmit power restrictions are applied.
305 
306   // AP2 sends another packet 0.1s later.
307   Simulator::Schedule (Seconds (2.1), &TestInterBssConstantObssPdAlgo::ClearDropReasons, this);
308   Simulator::Schedule (Seconds (2.1), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2);
309   // STA1 sends a packet 42us later (i.e. right after HE-SIG-A of AP2). Even though AP2 is still transmitting, STA1 can transmit simultaneously if it's PHY was reset by OBSS_PD SR.
310   Simulator::Schedule (Seconds (2.1) + MicroSeconds (42), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1);
311   if (expectPhyReset)
312     {
313       // In this case, we check the TX power is restricted (and set the expected value slightly before transmission should occur)
314       double expectedTxPower = std::min (m_txPowerDbm, 21 - (m_obssPdLevelDbm + 82));
315       Simulator::Schedule (Seconds (2.1) + MicroSeconds (41), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, expectedTxPower);
316     }
317   // Check simultaneous transmissions
318   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device2, WifiPhyState::TX);
319   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, sta_device1, dropReasons);
320   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::TX : stateDuringPayloadNeighboringBss);
321   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX);
322   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, ap_device1, dropReasons);
323   Simulator::Schedule (Seconds (2.1) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, stateDuringPayloadNeighboringBss);
324   Simulator::Schedule (Seconds (2.1) + MicroSeconds (142), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, expectPhyReset ? WifiPhyState::RX : stateDuringPayloadNeighboringBss);
325 
326   // AP2 sends another packet 0.1s later, and STA1 wanting to send a packet during the payload of the former.
327   Simulator::Schedule (Seconds (2.2), &TestInterBssConstantObssPdAlgo::ClearDropReasons, this);
328   Simulator::Schedule (Seconds (2.2), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, m_txPowerDbm);
329   Simulator::Schedule (Seconds (2.2), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2);
330   // STA1 sends a packet 90us later (i.e. during payload of AP2). Even though AP2 is still transmitting, STA1 can transmit simultaneously if it's PHY was reset by OBSS_PD SR.
331   Simulator::Schedule (Seconds (2.2) + MicroSeconds (90), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1);
332   if (expectPhyReset)
333     {
334       // In this case, we check the TX power is restricted (and set the expected value slightly before transmission should occur)
335       double expectedTxPower = std::min (m_txPowerDbm, 21 - (m_obssPdLevelDbm + 82));
336       Simulator::Schedule (Seconds (2.2) + MicroSeconds (89), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, expectedTxPower);
337     }
338   // Check simultaneous transmissions
339   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device2, WifiPhyState::TX);
340   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, sta_device1, dropReasons);
341   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::TX : stateDuringPayloadNeighboringBss);
342   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX);
343   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyDropReasons, this, ap_device1, dropReasons);
344   Simulator::Schedule (Seconds (2.2) + MicroSeconds (105), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, stateDuringPayloadNeighboringBss);
345   Simulator::Schedule (Seconds (2.2) + MicroSeconds (195), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, expectPhyReset ? WifiPhyState::RX : stateDuringPayloadNeighboringBss);
346 
347 
348   // Verify transmit power restrictions are not applied if access to the channel is requested after ignored OBSS transmissions.
349 
350   Simulator::Schedule (Seconds (2.3), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, m_txPowerDbm);
351   // AP2 sends another packet 0.1s later. Power restriction should not be applied.
352   Simulator::Schedule (Seconds (2.3), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2);
353   // STA1 sends a packet 0.1s later. Power restriction should not be applied.
354   Simulator::Schedule (Seconds (2.4), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1);
355 
356   // Verify a scenario that involves 3 networks in order to verify corner cases for transmit power restrictions.
357   // First, there is a transmission on network 2 from STA to AP, followed by a response from AP to STA.
358   // During that time, the STA on network 1 has a packet to send and request access to the channel.
359   // If a CCA reset occurred, it starts deferring while transmissions are ongoing from network 2.
360   // Before its backoff expires, a transmission on network 3 occurs, also eventually triggering another CCA reset (depending on the scenario that is being run).
361   // This test checks whether this sequence preserves transmit power restrictions if CCA resets occurred, since STA 1 has been deferring during ignored OBSS transmissions.
362 
363   Simulator::Schedule (Seconds (2.5), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device2, ap_device2, m_payloadSize2 / 10);
364   Simulator::Schedule (Seconds (2.5) + MicroSeconds (15), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2 / 10);
365   Simulator::Schedule (Seconds (2.5) + MicroSeconds (270), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device1, sta_device1, m_payloadSize1 / 10);
366   Simulator::Schedule (Seconds (2.5) + MicroSeconds (300), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device3, sta_device3, m_payloadSize3 / 10);
367   if (expectPhyReset)
368     {
369       // In this case, we check the TX power is restricted (and set the expected value slightly before transmission should occur)
370       double expectedTxPower = std::min (m_txPowerDbm, 21 - (m_obssPdLevelDbm + 82));
371       Simulator::Schedule (Seconds (2.5) + MicroSeconds (338), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, expectedTxPower);
372     }
373 
374   Simulator::Stop (Seconds (2.6));
375 }
376 
377 void
ResetResults()378 TestInterBssConstantObssPdAlgo::ResetResults ()
379 {
380   m_numSta1PacketsSent = 0;
381   m_numSta2PacketsSent = 0;
382   m_numAp1PacketsSent = 0;
383   m_numAp2PacketsSent = 0;
384   m_numSta1PacketsReceived = 0;
385   m_numSta2PacketsReceived = 0;
386   m_numAp1PacketsReceived = 0;
387   m_numAp2PacketsReceived = 0;
388   ClearDropReasons ();
389   m_expectedTxPowerDbm = m_txPowerDbm;
390 }
391 
392 void
ClearDropReasons()393 TestInterBssConstantObssPdAlgo::ClearDropReasons ()
394 {
395   m_dropReasonsSta1.clear ();
396   m_dropReasonsSta2.clear ();
397   m_dropReasonsAp1.clear ();
398   m_dropReasonsAp2.clear ();
399 }
400 
401 void
CheckResults()402 TestInterBssConstantObssPdAlgo::CheckResults ()
403 {
404   NS_TEST_ASSERT_MSG_EQ (m_numSta1PacketsSent, 4, "The number of packets sent by STA1 is not correct!");
405   NS_TEST_ASSERT_MSG_EQ (m_numSta2PacketsSent, 2, "The number of packets sent by STA2 is not correct!");
406   NS_TEST_ASSERT_MSG_EQ (m_numAp1PacketsSent, 2, "The number of packets sent by AP1 is not correct!");
407   NS_TEST_ASSERT_MSG_EQ (m_numAp2PacketsSent, 6, "The number of packets sent by AP2 is not correct!");
408   NS_TEST_ASSERT_MSG_EQ (m_numSta1PacketsReceived, 2, "The number of packets received by STA1 is not correct!");
409   NS_TEST_ASSERT_MSG_EQ (m_numSta2PacketsReceived, 6, "The number of packets received by STA2 is not correct!");
410   NS_TEST_ASSERT_MSG_EQ (m_numAp1PacketsReceived, 4, "The number of packets received by AP1 is not correct!");
411   NS_TEST_ASSERT_MSG_EQ (m_numAp2PacketsReceived, 2, "The number of packets received by AP2 is not correct!");
412 }
413 
414 void
NotifyPhyTxBegin(std::string context,Ptr<const Packet> p,double txPowerW)415 TestInterBssConstantObssPdAlgo::NotifyPhyTxBegin (std::string context, Ptr<const Packet> p, double txPowerW)
416 {
417   uint32_t idx = ConvertContextToNodeId (context);
418   uint32_t pktSize = p->GetSize () - 38;
419   if ((idx == 0) && ((pktSize == m_payloadSize1) || (pktSize == (m_payloadSize1 / 10))))
420     {
421       m_numSta1PacketsSent++;
422       NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!");
423     }
424   else if ((idx == 1) && ((pktSize == m_payloadSize2) || (pktSize == (m_payloadSize2 / 10))))
425     {
426       m_numSta2PacketsSent++;
427       NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!");
428     }
429   else if ((idx == 3) && ((pktSize == m_payloadSize1) || (pktSize == (m_payloadSize1 / 10))))
430     {
431       m_numAp1PacketsSent++;
432       NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!");
433     }
434   else if ((idx == 4) && ((pktSize == m_payloadSize2) || (pktSize == (m_payloadSize2 / 10))))
435     {
436       m_numAp2PacketsSent++;
437       NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!");
438     }
439 }
440 
441 void
NotifyPhyRxEnd(std::string context,Ptr<const Packet> p)442 TestInterBssConstantObssPdAlgo::NotifyPhyRxEnd (std::string context, Ptr<const Packet> p)
443 {
444   uint32_t idx = ConvertContextToNodeId (context);
445   uint32_t pktSize = p->GetSize () - 38;
446   if ((idx == 0) && ((pktSize == m_payloadSize1) || (pktSize == (m_payloadSize1 / 10))))
447     {
448       m_numSta1PacketsReceived++;
449     }
450   else if ((idx == 1) && ((pktSize == m_payloadSize2) || (pktSize == (m_payloadSize2 / 10))))
451     {
452       m_numSta2PacketsReceived++;
453     }
454   else if ((idx == 3) && ((pktSize == m_payloadSize1) || (pktSize == (m_payloadSize1 / 10))))
455     {
456       m_numAp1PacketsReceived++;
457     }
458   else if ((idx == 4) && ((pktSize == m_payloadSize2) || (pktSize == (m_payloadSize2 / 10))))
459     {
460       m_numAp2PacketsReceived++;
461     }
462 }
463 
464 void
NotifyPhyRxDrop(std::string context,Ptr<const Packet> p,WifiPhyRxfailureReason reason)465 TestInterBssConstantObssPdAlgo::NotifyPhyRxDrop (std::string context, Ptr<const Packet> p,
466                                                  WifiPhyRxfailureReason reason)
467 {
468   uint32_t idx = ConvertContextToNodeId (context);
469   uint32_t pktSize = p->GetSize () - 38;
470   if ((idx == 0) && ((pktSize != m_payloadSize1) && (pktSize != (m_payloadSize1 / 10))))
471     {
472       m_dropReasonsSta1.push_back (reason);
473     }
474   else if ((idx == 1) && ((pktSize != m_payloadSize2) && (pktSize != (m_payloadSize2 / 10))))
475     {
476       m_dropReasonsSta2.push_back (reason);
477     }
478   else if ((idx == 3) && ((pktSize != m_payloadSize1) && (pktSize != (m_payloadSize1 / 10))))
479     {
480       m_dropReasonsAp1.push_back (reason);
481     }
482   else if ((idx == 4) && ((pktSize != m_payloadSize2) && (pktSize != (m_payloadSize2 / 10))))
483     {
484       m_dropReasonsAp2.push_back (reason);
485     }
486 }
487 
488 void
SendOnePacket(Ptr<WifiNetDevice> tx_dev,Ptr<WifiNetDevice> rx_dev,uint32_t payloadSize)489 TestInterBssConstantObssPdAlgo::SendOnePacket (Ptr<WifiNetDevice> tx_dev, Ptr<WifiNetDevice> rx_dev, uint32_t payloadSize)
490 {
491   Ptr<Packet> p = Create<Packet> (payloadSize);
492   tx_dev->Send (p, rx_dev->GetAddress (), 1);
493 }
494 
495 void
SetExpectedTxPower(double txPowerDbm)496 TestInterBssConstantObssPdAlgo::SetExpectedTxPower (double txPowerDbm)
497 {
498   m_expectedTxPowerDbm = txPowerDbm;
499 }
500 
501 void
CheckPhyState(Ptr<WifiNetDevice> device,WifiPhyState expectedState)502 TestInterBssConstantObssPdAlgo::CheckPhyState (Ptr<WifiNetDevice> device, WifiPhyState expectedState)
503 {
504   WifiPhyState currentState;
505   PointerValue ptr;
506   Ptr<WifiPhy> phy = DynamicCast<WifiPhy> (device->GetPhy ());
507   phy->GetAttribute ("State", ptr);
508   Ptr <WifiPhyStateHelper> state = DynamicCast <WifiPhyStateHelper> (ptr.Get<WifiPhyStateHelper> ());
509   currentState = state->GetState ();
510   NS_TEST_ASSERT_MSG_EQ (currentState, expectedState, "PHY State " << currentState << " does not match expected state " << expectedState << " at " << Simulator::Now ());
511 }
512 
513 void
CheckPhyDropReasons(Ptr<WifiNetDevice> device,std::vector<WifiPhyRxfailureReason> expectedDropReasons)514 TestInterBssConstantObssPdAlgo::CheckPhyDropReasons (Ptr<WifiNetDevice> device,
515                                                      std::vector<WifiPhyRxfailureReason> expectedDropReasons)
516 {
517   std::vector<WifiPhyRxfailureReason> currentDropReasons;
518   uint32_t nodeId = device->GetNode ()->GetId ();
519   switch (nodeId)
520     {
521       case 0: //STA1
522         currentDropReasons = m_dropReasonsSta1;
523         break;
524       case 1: //STA2
525         currentDropReasons = m_dropReasonsSta2;
526         break;
527       case 3: //AP1
528         currentDropReasons = m_dropReasonsAp1;
529         break;
530       case 4: //AP2
531         currentDropReasons = m_dropReasonsAp2;
532         break;
533       default: //others, no attribute
534         return;
535     }
536   NS_TEST_ASSERT_MSG_EQ (currentDropReasons.size (), expectedDropReasons.size (), "Number of drop reasons " << currentDropReasons.size () << " does not match expected one " << expectedDropReasons.size () << " at " << Simulator::Now ());
537   for (std::size_t i = 0; i < currentDropReasons.size (); ++i)
538     {
539       NS_TEST_ASSERT_MSG_EQ (currentDropReasons[i], expectedDropReasons[i], "Drop reason " << i << ": " << currentDropReasons[i] << " does not match expected reason " << expectedDropReasons[i] << " at " << Simulator::Now ());
540     }
541 }
542 
543 void
RunOne(void)544 TestInterBssConstantObssPdAlgo::RunOne (void)
545 {
546   RngSeedManager::SetSeed (1);
547   RngSeedManager::SetRun (1);
548   int64_t streamNumber = 2;
549 
550   Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_MaxAmpduSize", UintegerValue (0));
551 
552   ResetResults ();
553 
554   NodeContainer wifiStaNodes;
555   wifiStaNodes.Create (3);
556 
557   NodeContainer wifiApNodes;
558   wifiApNodes.Create (3);
559 
560   Ptr<MatrixPropagationLossModel> lossModel = CreateObject<MatrixPropagationLossModel> ();
561   lossModel->SetDefaultLoss (m_txPowerDbm - m_obssRxPowerDbm); //Force received RSSI to be equal to m_obssRxPowerDbm
562 
563   SpectrumWifiPhyHelper phy;
564   phy.DisablePreambleDetectionModel ();
565   phy.SetFrameCaptureModel ("ns3::SimpleFrameCaptureModel");
566   Ptr<MultiModelSpectrumChannel> channel = CreateObject<MultiModelSpectrumChannel> ();
567   channel->SetPropagationDelayModel (CreateObject<ConstantSpeedPropagationDelayModel> ());
568   channel->AddPropagationLossModel (lossModel);
569   phy.SetChannel (channel);
570   phy.Set ("TxPowerStart", DoubleValue (m_txPowerDbm));
571   phy.Set ("TxPowerEnd", DoubleValue (m_txPowerDbm));
572   phy.Set ("ChannelWidth", UintegerValue (20));
573 
574   WifiHelper wifi;
575   wifi.SetStandard (WIFI_STANDARD_80211ax_5GHZ);
576   wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
577                                 "DataMode", StringValue ("HeMcs5"),
578                                 "ControlMode", StringValue ("HeMcs0"));
579 
580   wifi.SetObssPdAlgorithm ("ns3::ConstantObssPdAlgorithm",
581                            "ObssPdLevel", DoubleValue (m_obssPdLevelDbm));
582 
583   WifiMacHelper mac;
584   Ssid ssid = Ssid ("ns-3-ssid");
585   mac.SetType ("ns3::StaWifiMac",
586                "Ssid", SsidValue (ssid));
587   m_staDevices = wifi.Install (phy, mac, wifiStaNodes);
588 
589   // Assign fixed streams to random variables in use
590   wifi.AssignStreams (m_staDevices, streamNumber);
591 
592   mac.SetType ("ns3::ApWifiMac",
593                "Ssid", SsidValue (ssid));
594   m_apDevices = wifi.Install (phy, mac, wifiApNodes);
595 
596   // Assign fixed streams to random variables in use
597   wifi.AssignStreams (m_apDevices, streamNumber);
598 
599   for (uint32_t i = 0; i < m_apDevices.GetN (); i++)
600     {
601       Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_apDevices.Get (i));
602       Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration ();
603       if (i == 0)
604         {
605           heConfiguration->SetAttribute ("BssColor", UintegerValue (m_bssColor1));
606         }
607       else if (i == 1)
608         {
609           heConfiguration->SetAttribute ("BssColor", UintegerValue (m_bssColor2));
610         }
611       else
612         {
613           heConfiguration->SetAttribute ("BssColor", UintegerValue (m_bssColor3));
614         }
615     }
616 
617   MobilityHelper mobility;
618   Ptr<ListPositionAllocator> positionAlloc = AllocatePositions (10, 50, 10, 50, 10); //distances do not really matter since we set RSSI per TX-RX pair to have full control
619   mobility.SetPositionAllocator (positionAlloc);
620   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
621   mobility.Install (wifiApNodes);
622   mobility.Install (wifiStaNodes);
623 
624   lossModel->SetLoss (wifiStaNodes.Get (0)->GetObject<MobilityModel> (), wifiApNodes.Get (0)->GetObject<MobilityModel> (), m_txPowerDbm + 30); //Low attenuation for IBSS transmissions
625   lossModel->SetLoss (wifiStaNodes.Get (1)->GetObject<MobilityModel> (), wifiApNodes.Get (1)->GetObject<MobilityModel> (), m_txPowerDbm + 30); //Low attenuation for IBSS transmissions
626   lossModel->SetLoss (wifiStaNodes.Get (2)->GetObject<MobilityModel> (), wifiApNodes.Get (2)->GetObject<MobilityModel> (), m_txPowerDbm + 30); //Low attenuation for IBSS transmissions
627 
628   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin", MakeCallback (&TestInterBssConstantObssPdAlgo::NotifyPhyTxBegin, this));
629   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd", MakeCallback (&TestInterBssConstantObssPdAlgo::NotifyPhyRxEnd, this));
630   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxDrop", MakeCallback (&TestInterBssConstantObssPdAlgo::NotifyPhyRxDrop, this));
631 
632   SetupSimulation ();
633 
634   Simulator::Run ();
635   Simulator::Destroy ();
636 
637   CheckResults ();
638 }
639 
640 void
DoRun(void)641 TestInterBssConstantObssPdAlgo::DoRun (void)
642 {
643   //Test case 1: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm
644   m_obssPdLevelDbm = -72;
645   m_obssRxPowerDbm = -82;
646   m_bssColor1 = 1;
647   m_bssColor2 = 2;
648   m_bssColor3 = 3;
649   RunOne ();
650 
651   //Test case 2: CCA CS Threshold < m_obssPdLevelDbm < m_obssRxPowerDbm
652   m_obssPdLevelDbm = -72;
653   m_obssRxPowerDbm = -62;
654   m_bssColor1 = 1;
655   m_bssColor2 = 2;
656   m_bssColor3 = 3;
657   RunOne ();
658 
659   //Test case 3: CCA CS Threshold < m_obssPdLevelDbm = m_obssRxPowerDbm
660   m_obssPdLevelDbm = -72;
661   m_obssRxPowerDbm = -72;
662   m_bssColor1 = 1;
663   m_bssColor2 = 2;
664   m_bssColor3 = 3;
665   RunOne ();
666 
667   //Test case 4: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm with BSS color 2 and 3 set to 0
668   m_obssPdLevelDbm = -72;
669   m_obssRxPowerDbm = -82;
670   m_bssColor1 = 1;
671   m_bssColor2 = 0;
672   m_bssColor3 = 0;
673   RunOne ();
674 
675   //Test case 5: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm with BSS color 1 set to 0
676   m_obssPdLevelDbm = -72;
677   m_obssRxPowerDbm = -82;
678   m_bssColor1 = 0;
679   m_bssColor2 = 2;
680   m_bssColor3 = 3;
681   RunOne ();
682 }
683 
684 /**
685  * \ingroup wifi-test
686  * \ingroup tests
687  *
688  * \brief Inter BSS Test Suite
689  */
690 
691 class InterBssTestSuite : public TestSuite
692 {
693 public:
694   InterBssTestSuite ();
695 };
696 
InterBssTestSuite()697 InterBssTestSuite::InterBssTestSuite ()
698   : TestSuite ("wifi-inter-bss", UNIT)
699 {
700   AddTestCase (new TestInterBssConstantObssPdAlgo, TestCase::QUICK);
701 }
702 
703 // Do not forget to allocate an instance of this TestSuite
704 static InterBssTestSuite interBssTestSuite;
705