A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
power-save-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Davide Magrin <davide@magr.in>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/assert.h"
11#include "ns3/boolean.h"
12#include "ns3/config.h"
13#include "ns3/frame-exchange-manager.h"
14#include "ns3/header-serialization-test.h"
15#include "ns3/log.h"
16#include "ns3/mgt-action-headers.h"
17#include "ns3/minstrel-ht-wifi-manager.h"
18#include "ns3/mobility-helper.h"
19#include "ns3/multi-model-spectrum-channel.h"
20#include "ns3/node-list.h"
21#include "ns3/packet-socket-address.h"
22#include "ns3/packet-socket-client.h"
23#include "ns3/packet-socket-helper.h"
24#include "ns3/packet-socket-server.h"
25#include "ns3/pointer.h"
26#include "ns3/power-save-manager.h"
27#include "ns3/rng-seed-manager.h"
28#include "ns3/socket.h"
29#include "ns3/spectrum-wifi-helper.h"
30#include "ns3/sta-wifi-mac.h"
31#include "ns3/test.h"
32#include "ns3/tim.h"
33#include "ns3/wifi-mac-queue.h"
34#include "ns3/wifi-mpdu.h"
35#include "ns3/wifi-net-device.h"
36#include "ns3/wifi-ns3-constants.h"
37#include "ns3/wifi-phy.h"
38#include "ns3/wifi-static-setup-helper.h"
39
40#include <algorithm>
41#include <array>
42#include <iomanip>
43#include <iterator>
44#include <list>
45#include <sstream>
46#include <vector>
47
48using namespace ns3;
49
50NS_LOG_COMPONENT_DEFINE("PowerSaveTest");
51
52/**
53 * @ingroup wifi-test
54 * @ingroup tests
55 *
56 * @brief Test TIM Information element serialization and deserialization
57 */
59{
60 public:
61 /**
62 * @brief Constructor
63 */
65
66 void DoRun() override;
67 /**
68 * Reset the passed TIM to have the provided parameters.
69 *
70 * @param tim the TIM element to set
71 * @param dtimCount the DTIM count value
72 * @param dtimPeriod the DTIM period value
73 * @param multicastPending whether group addressed frames are queued
74 * @param aidValues the AID values to set
75 */
76 void SetTim(Tim& tim,
77 uint8_t dtimCount,
78 uint8_t dtimPeriod,
79 bool multicastPending,
80 const std::list<uint16_t>& aidValues);
81
82 /**
83 * Test that the Bitmap Control and the Partial Virtual Bitmap
84 * fields of the provided TIM match the passed bufferContents.
85 *
86 * @param tim the provided TIM
87 * @param bufferContents the expected content of the buffer
88 */
89 void CheckSerializationAgainstBuffer(Tim& tim, const std::vector<uint8_t>& bufferContents);
90
91 /**
92 * Test that the GetAidSet() method return the expected set of AID values.
93 *
94 * @param tim the TIM element
95 * @param aid the AID value passed to GetAidSet()
96 * @param expectedSet the expected set of AID values returned by GetAidSet()
97 */
98 void CheckAidSet(const Tim& tim, uint16_t aid, const std::set<uint16_t>& expectedSet);
99};
100
102 : HeaderSerializationTestCase("Test for the TIM Information Element implementation")
103{
104}
105
106void
108 uint8_t dtimCount,
109 uint8_t dtimPeriod,
110 bool multicastPending,
111 const std::list<uint16_t>& aidValues)
112{
113 tim = Tim();
114 tim.m_dtimCount = dtimCount;
115 tim.m_dtimPeriod = dtimPeriod;
116 tim.m_hasMulticastPending = multicastPending;
117 tim.AddAid(aidValues.begin(), aidValues.end());
118}
119
120void
122 Tim& tim,
123 const std::vector<uint8_t>& bufferContents)
124{
125 // Serialize the TIM
126 Buffer buffer;
127 buffer.AddAtStart(tim.GetSerializedSize());
128 tim.Serialize(buffer.Begin());
129
130 // Check the two Buffer instances
131 Buffer::Iterator bufferIterator = buffer.Begin();
132 for (uint32_t j = 0; j < buffer.GetSize(); j++)
133 {
134 // We skip the first four bytes, since they contain known information
135 if (j > 3)
136 {
137 NS_TEST_EXPECT_MSG_EQ(bufferIterator.ReadU8(),
138 bufferContents.at(j - 4),
139 "Serialization is different than provided known serialization");
140 }
141 else
142 {
143 // Advance the serialized buffer, which also contains
144 // the Element ID, Length, DTIM Count, DTIM Period fields
145 bufferIterator.ReadU8();
146 }
147 }
148}
149
150void
152 uint16_t aid,
153 const std::set<uint16_t>& expectedSet)
154{
155 auto ret = tim.GetAidSet(aid);
156
157 {
158 std::vector<uint16_t> diff;
159
160 // Expected set minus returned set provides expected elements that are not returned
161 std::set_difference(expectedSet.cbegin(),
162 expectedSet.cend(),
163 ret.cbegin(),
164 ret.cend(),
165 std::back_inserter(diff));
166
167 std::stringstream ss;
168 std::copy(diff.cbegin(), diff.cend(), std::ostream_iterator<uint16_t>(ss, " "));
169
170 NS_TEST_EXPECT_MSG_EQ(diff.size(),
171 0,
172 "Expected elements not returned by GetAidSet(): " << ss.str());
173 }
174 {
175 std::vector<uint16_t> diff;
176
177 // Returned set minus expected set provides returned elements that are not expected
178 std::set_difference(ret.cbegin(),
179 ret.cend(),
180 expectedSet.cbegin(),
181 expectedSet.cend(),
182 std::back_inserter(diff));
183
184 std::stringstream ss;
185 std::copy(diff.cbegin(), diff.cend(), std::ostream_iterator<uint16_t>(ss, " "));
186
187 NS_TEST_EXPECT_MSG_EQ(diff.size(),
188 0,
189 "Returned elements not expected by GetAidSet(): " << ss.str());
190 }
191}
192
193void
195{
196 Tim tim;
197
198 // The first three examples from 802.11-2020, Annex L
199 //
200 // 1. No group addressed MSDUs, but there is traffic for STAs with AID 2 and AID 7
201 SetTim(tim, 0, 3, false, {2, 7});
203 CheckSerializationAgainstBuffer(tim, {0b00000000, 0b10000100});
204 CheckAidSet(tim, 0, {2, 7});
205 CheckAidSet(tim, 1, {2, 7});
206 CheckAidSet(tim, 2, {7});
207 CheckAidSet(tim, 7, {});
208 //
209 // 2. There are group addressed MSDUs, DTIM count = 0, the nodes
210 // with AID 2, 7, 22, and 24 have data buffered in the AP
211 SetTim(tim, 0, 3, true, {2, 7, 22, 24});
214 {
215 0b00000001,
216 // NOTE The following byte is different from the example
217 // in the standard. This is because the example sets the
218 // AID 0 bit in the partial virtual bitmap to 1. Our code
219 // and the example code provided in the Annex, instead, do
220 // not set this bit. Relevant Note from 802.11-2020,
221 // Section 9.4.2.5.1: "The bit numbered 0 in the traffic
222 // indication virtual bitmap need not be included in the
223 // Partial Virtual Bitmap field even if that bit is set."
224 0b10000100,
225 0b00000000,
226 0b01000000,
227 0b00000001,
228 });
229 CheckAidSet(tim, 0, {2, 7, 22, 24});
230 CheckAidSet(tim, 2, {7, 22, 24});
231 CheckAidSet(tim, 7, {22, 24});
232 CheckAidSet(tim, 22, {24});
233 CheckAidSet(tim, 24, {});
234 //
235 // 3. There are group addressed MSDUs, DTIM count = 0, only the node
236 // with AID 24 has data buffered in the AP
237 SetTim(tim, 0, 3, true, {24});
239 CheckSerializationAgainstBuffer(tim, {0b00000011, 0b00000000, 0b00000001});
240
241 // Other arbitrary examples just to make sure
242 // Serialization -> Deserialization -> Serialization works
243 SetTim(tim, 0, 3, false, {2000});
245 SetTim(tim, 1, 3, true, {1, 134});
247 SetTim(tim, 1, 3, false, {1, 2});
249
250 // Edge cases
251 //
252 // What if there is group addressed data only?
253 //
254 // In this case, we should still have an empty byte in the Partial Virtual Bitmap.
255 // From 802.11-2020: in the event that all bits other than bit 0 in the traffic indication
256 // virtual bitmap are 0, the Partial Virtual Bitmap field is encoded as a single octet
257 // equal to 0, the Bitmap Offset subfield is 0, and the Length field is 4.
258 SetTim(tim, 0, 3, true, {});
260 CheckSerializationAgainstBuffer(tim, {0b00000001, 0b00000000});
261 NS_TEST_EXPECT_MSG_EQ(tim.GetSerializedSize() - 2, 4, "Unexpected TIM Length");
262 //
263 // What if there is no group addressed data and no unicast data?
264 //
265 // From 802.11-2020: When the TIM is carried in a non-S1G PPDU, in the event that all bits
266 // other than bit 0 in the traffic indication virtual bitmap are 0, the Partial Virtual Bitmap
267 // field is encoded as a single octet equal to 0, the Bitmap Offset subfield is 0, and the
268 // Length field is 4.
269 SetTim(tim, 0, 3, false, {});
271 CheckSerializationAgainstBuffer(tim, {0b00000000, 0b00000000});
272 NS_TEST_EXPECT_MSG_EQ(tim.GetSerializedSize() - 2, 4, "Unexpected TIM Length");
273}
274
275/**
276 * @ingroup wifi-test
277 * @ingroup tests
278 *
279 * @brief Test rate manager that differs from MinstrelHT in that it allows to arbitrarily drop
280 * frames by overriding the DoGetMpdusToDropOnTxFailure method.
281 */
283{
284 public:
285 /**
286 * @brief Get the type ID.
287 * @return the object TypeId
288 */
290 {
291 static TypeId tid = TypeId("ns3::PowerSaveTestRateManager")
293 .SetGroupName("Wifi")
294 .AddConstructor<PowerSaveTestRateManager>();
295 return tid;
296 }
297
298 bool m_drop{false}; ///< whether to drop the given MPDUs
299
300 private:
301 std::list<Ptr<WifiMpdu>> DoGetMpdusToDropOnTxFailure(WifiRemoteStation* station,
302 Ptr<WifiPsdu> psdu) override
303 {
304 if (!m_drop)
305 {
306 return {};
307 }
308
309 std::list<Ptr<WifiMpdu>> mpdusToDrop;
310
311 for (const auto& mpdu : *PeekPointer(psdu))
312 {
313 mpdusToDrop.push_back(mpdu);
314 }
315
316 return mpdusToDrop;
317 }
318};
319
321
322/**
323 * @ingroup wifi-test
324 * @ingroup tests
325 *
326 * @brief Test transmission of broadcast and unicast frames with STAs in Power Save mode
327 *
328 * The test scenario comprises an AP MLD with two links, a non-AP STA (operating on link 0) and a
329 * non-AP MLD with two links. The non-AP MLD negotiates a TID-to-Link Mapping such that (both in
330 * DL and UL) TID 0 is mapped on both links and TID 2 is mapped on link 1 only. The sequence of
331 * events is depicted in the diagram below. Note that, for most of the time, the non-AP STA
332 * affiliated with the non-AP MLD and operating on link 0 is in active mode, while the non-AP STA
333 * affiliated with the non-AP MLD and operating on link 1 is in power save mode.
334 *
335 * The standard supported by the non-AP STA is a parameter of this test, while the non-AP MLD
336 * supports the 802.11be standard.
337 *
338 \verbatim
339 (1) (2) (3) (4) non-AP STA
340 is set to go
341 ┌──────┐ ┌──────┐ Broadcast ┌─────────┐ ┌──────┐to PS mode
342 │Beacon│ non-AP STA performs │Beacon│ frame queued │Broadcast│ │Beacon││ ┌───┐
343 [link 0] │ DTIM │ association │ TIM │ at AP │ │QoS Data │ │ DTIM ││ │Ack│
344 ─────────┴──────┴───────────────────────┴──────┴───────────▼──┴─────────┴──┴──────┴▼┬────┬┴───┴─
345 │Not buffered │Data│
346 non-AP MLD performs │(no STA in PS mode) │Null│
347 ┌──────┐ association and sends Data ┌──────┐ │ ┌─────────┐ ┌──────┐ └────┘
348 │Beacon│ Null for other non-AP STA │Beacon│ │ │Broadcast│ │Beacon│ ┌───┐
349 [link 1] │ DTIM │ to switch to active mode │ TIM │ │ │QoS Data │ │ DTIM │ │Ack│
350 ─────────────┴──────┴────────────────────────────┴──────┴──▼──┴─────────┴──┴──────┴▲┬────┬┴───┴─
351 ││Data│
352 ││Null│
353 │└────┘
354 non-AP STA affiliated
355 with non-AP MLD on link 1
356 is set to go to PS mode
357 (CONTINUED)
358
359 (5) (6) (7) (8) (9)
360 QoS data frame with another broadcast frame 2 frames for non-AP
361 1 broadcast TID 4 queued for | |queued at AP STA are queued at
362 frame queued ┌──────┐ non-AP ┌──────┐ ┌─────────┐ ┌────────────────┐ AP and buffered
363 at AP │ │Beacon│ MLD │Beacon│ │Broadcast│ │ BA agreement + │ │
364 [link 0] │ │ TIM │ │ DTIM │ │QoS Data │ │unicast QoS Data│ │
365 ───────────▼────────┴──────┴────────┴▼─────┴─┴▼────────┴─┴────────────────┴─▼───────────────────
366 │ │ │
367 non-AP STA -sleep--│ │------│ │ │ │----------------------------------------
368 non-AP STA │ │ │
369 affiliated ---sleep--------│ │------------------------│ │-
370 on link 1 │ No DTIM, │
371 │Buffered because frames still │
372 │STAs in PS mode buffered │
373 │ ┌──────┐ │ │ ┌──────┐ ┌─────────┐ ┌─────────┐
374 │ │Beacon│ │ │ │Beacon│ │Broadcast│ │Broadcast│
375 [link 1] │ │ TIM │ │ │ │ DTIM │ │QoS Data │ │QoS Data │
376 ───────────▼────────────────┴──────┴─▼────────▼───────────────┴──────┴─┴─────────┴─┴─────────┴──
377
378
379
380 (CONTINUED)
381 (10) (11) (12) (13)
382
383 ┌──────┐ ┌────────┐ ┌──────┐ ┌────────┐
384 │Beacon│ │QoS Data│ PS-Poll │Beacon│ │QoS Data│
385 [link 0] │ TIM │ │ to STA │ dropped │ DTIM │ │ to STA │
386 ─────────┴──────┴─┬────┬┴────────┴┬───┬─┬────X───┬────X──────────┴──────┴─┬────┬┴────────┴┬───┬─
387 │ PS │ │ACK│ │ PS │...│ PS │ │ PS │ │ACK│
388 │Poll│ └───┘ │Poll│ │Poll│ │Poll│ └───┘
389 └────┘ └────┘ └────┘ └────┘
390 non-AP STA │--sleep-│ │-
391 non-AP STA
392 affiliated --------sleep-------------------------------│ │-------------------------------
393 on link 1
394 ┌──────┐ drop broadcast
395 │Beacon│ frame queued for
396 [link 1] │ TIM │ TX on link 0
397 ────────────────────────────────────────────────────────┴──────┴────────────────────────────────
398
399
400 (CONTINUED)
401
402 (14) (15) (16) (17)
403 2 QoS Data frames with 2 QoS Data frames
404 TID 0 for non-AP MLD with TID 2 for
405 are queued at AP but non-AP MLD are
406 not buffered as STA on ┌────────┬────────┐ queued and ┌──────┐
407 link 0 is in active mode │QoS Data│QoS Data│ buffered │Beacon│
408 [link 0] │ │ to MLD │ to MLD │ │ │ TIM │
409 ───────────────────▼──────┴────────┴────────┴┬──┬────────┴──────┴───────────────────────────────
410 │ Block Ack │BA│ │
411 │ agreement └──┘ │
412 │ establishment │
413 non-AP STA ------------------sleep----------------------│ │------------------------------
414 non-AP STA │ │
415 affiliated │--------sleep-----------------------------------│
416 on link 1 │ │
417 ┌──────┐ │ │ ┌──────┐ ┌────────┐
418 │Beacon│ │ │ │Beacon│ │QoS Data│
419 [link 1] │ DTIM │ │ │ │ TIM │ │ to MLD │
420 ─────────┴──────┴──▼──────────────────────────────▼────────────────┴──────┴─┬────┬┴────────X────
421 │ PS │
422 │Poll│
423 └────┘
424
425
426 (CONTINUED)
427 (17) (18)
428 2 QoS Data frames
429 are queued at
430 non-AP STA ADDBA
431 │ ┌───┐Resp ┌───┐ ┌───┐
432 [link 0] │ │Ack│timer │Ack│ │Ack│
433 ───────────────────────────────────────────────────────▼┬─────┬┴───┴────┬────┬┴───┴┬────┬┴───┴──
434 │ADDBA│ │QoS │ │QoS │
435 │ Req │ │Data│ │Data│
436 └─────┘ └────┘ └────┘
437 non-AP STA ------------------sleep---------------------│ │--│ │-
438 non-AP STA
439 affiliated │--------sleep---------------------------
440 on link 1
441 ┌────────┐ ┌────────┐
442 │QoS Data│ │QoS Data│
443 [link 1] │ to MLD │ │ to MLD │
444 ───────────┬────┬┴────────┴┬───┬──┬────┬┴────────┴┬───┬─────────────────────────────────────────
445 │ PS │ │ACK│ │ PS │ │ACK│
446 │Poll│ └───┘ │Poll│ └───┘
447 └────┘ └────┘
448
449
450
451 (CONTINUED)
452 (19) (20) (21)
453 2 QoS Data frames
454 ┌──────┐ ┌─────┐ with TID 0 are queued ┌─────┐
455 │Beacon│ │ADDBA│ at non-AP MLD ┌───┐ │ADDBA│
456 [link 0] │ DTIM │ │Resp │ | │Ack│ │Resp │
457 ─────────┴──────┴──┬────┬┴─────┴┬───┬▼───┬─────┬┴───┴────┴─────┴┬───┬───────────────────────────
458 │ PS │ │Ack│| │ADDBA│ │Ack│
459 │Poll│ └───┘| │ Req │ └───┘
460 └────┘ | └─────┘
461 non-AP STA │------------------sleep-----------------------------------
462 non-AP STA |
463 affiliated --------sleep-------------| backoff |------sleep-----| |--sleep--
464 on link 1 | can also
465 | occur on ┌──┐
466 [link 1] | link 0 │BA│
467 ─────────────────────────────────────▼──────────────────────────────────┬────┬────┬┴──┴─────────
468 │QoS │QoS │
469 │Data│Data│
470 └────┴────┘
471
472
473
474 (CONTINUED)
475 (22) (23)
476 a QoS Data frame frame dropped a QoS Data frame with
477 with TID 0 for non-AP at AckTimeout, TID 0 for non-AP MLD
478 MLD is queued at AP non-AP STA on is queued and buffered
479 MLD but not ┌────┐ link 0 set to at AP ┌──────┐ ┌────┐
480 buffered | │QoS │ go to ┌───┐ MLD │Beacon│ ┌───┐ │QoS │
481 [link 0] | │Data│ PS mode│Ack│ |│ TIM │ │BAR│ │Data│
482 ────────────▼─┴────X─────┬────┬┴───┴──────────▼┴──────┴──┬────┬┴───┴┬──┬──┬────┬┴────┴┬───┬─────
483 | │Data│ | │ PS │ │BA│ │ PS │ │Ack│
484 | │Null│ | │Poll│ └──┘ │Poll│ └───┘
485 | └────┘ | └────┘ └────┘
486 non-AP STA ------------sleep------------------| |----------------------------------------
487 non-AP STA | |
488 affiliated | |--sleep--| |----
489 on link 0 | |
490 non-AP STA | |
491 affiliated ---------------sleep------| |-------sleep-------------------------------------
492 on link 1 | ┌──────┐|
493 | │Beacon│|
494 [link 1] | │ DTIM │|
495 ────────────▼─────────────────────────┴──────┴▼─────────────────────────────────────────────────
496
497 \endverbatim
498 */
500{
501 public:
502 /**
503 * Constructor
504 * @param standard the standard supported by the non-AP STA
505 */
507
508 /**
509 * Callback invoked when the PHY state helper reports a change in PHY state
510 *
511 * @param nodeId the ID of the node
512 * @param phyId the ID of the PHY that changed state
513 * @param stateStart the start time of the period elapsed in the given PHY state
514 * @param stateDuration the duration of the period elapsed in the given PHY state
515 * @param state the given PHY state
516 */
517 void NotifyStateChange(uint32_t nodeId,
518 uint8_t phyId,
519 Time stateStart,
520 Time stateDuration,
521 WifiPhyState state);
522
523 /**
524 * Notify that the given MPDU was enqueued at the AP.
525 *
526 * @param mpdu the given MPDU
527 */
529
530 /**
531 * Callback invoked when PHY receives a PSDU to transmit
532 *
533 * @param mac the MAC transmitting the PSDUs
534 * @param phyId the ID of the PHY transmitting the PSDUs
535 * @param psduMap the PSDU map
536 * @param txVector the TX vector
537 * @param txPower the tx power
538 */
539 void Transmit(Ptr<WifiMac> mac,
540 uint8_t phyId,
541 WifiConstPsduMap psduMap,
542 WifiTxVector txVector,
543 Watt_u txPower);
544
545 protected:
546 /**
547 * Function to trace packets received by the server application
548 * @param nodeId the ID of the node that received the packet
549 * @param p the packet
550 * @param addr the address
551 */
552 void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
553
554 /**
555 * @param sockAddr the packet socket address identifying local outgoing interface
556 * and remote address
557 * @param count the number of packets to generate
558 * @param pktSize the size of the packets to generate
559 * @param delay the delay with which traffic generation starts
560 * @param priority user priority for generated packets
561 * @return an application generating the given number packets of the given size destined
562 * to the given packet socket address
563 */
565 std::size_t count,
566 std::size_t pktSize,
567 Time delay = Time{0},
568 uint8_t priority = 0) const;
569
570 /// Actions and checks to perform upon the transmission of each frame
571 struct Events
572 {
573 /**
574 * Constructor.
575 *
576 * @param type the frame MAC header type
577 * @param f function to perform actions and checks
578 */
580 std::function<void(Ptr<const WifiPsdu>, const Time&, uint8_t)>&& f = {})
581 : hdrType(type),
582 func(f)
583 {
584 }
585
586 WifiMacType hdrType; ///< MAC header type of frame being transmitted
587 std::function<void(Ptr<const WifiPsdu>, const Time&, uint8_t)>
588 func; ///< function to perform actions and checks
589 };
590
591 /// Set the list of events to expect in this test run.
592 void SetEvents();
593
594 private:
595 void DoSetup() override;
596 void DoRun() override;
597
598 WifiStandard m_standard; //!< the wifi standard for AP and STA
599 Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
600 std::vector<Ptr<StaWifiMac>> m_staMacs; ///< STA wifi MACs
601 std::list<Events> m_events; //!< list of events for a test run
602 std::size_t m_processedEvents{0}; //!< number of processed events
603 Time m_duration{Seconds(5)}; ///< simulation duration
604 std::array<std::size_t, 3> m_rxPkts{{0, 0, 0}}; ///< number of packets received at application
605 ///< layer by each node (index is node ID)
606 std::vector<double> m_jitter{0.2, 0.6}; ///< jitter for the initial Beacon frames on the links
607 Ptr<ListErrorModel> m_apErrorModel; ///< error model to install on the AP MLD
608 Ptr<ListErrorModel> m_nonApStaErrorModel; ///< error model to install on the non-AP STA
609 Ptr<ListErrorModel> m_nonApMldErrorModel; ///< error model to install on the non-AP MLD
610};
611
620
623 std::size_t count,
624 std::size_t pktSize,
625 Time delay,
626 uint8_t priority) const
627{
628 auto client = CreateObject<PacketSocketClient>();
629 client->SetAttribute("PacketSize", UintegerValue(pktSize));
630 client->SetAttribute("MaxPackets", UintegerValue(count));
631 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
632 client->SetAttribute("Priority", UintegerValue(priority));
633 client->SetRemote(sockAddr);
634 client->SetStartTime(delay);
635 client->SetStopTime(m_duration - Simulator::Now());
636
637 return client;
638}
639
640void
642{
645 int64_t streamNumber = 100;
646
647 NodeContainer wifiApNode(1);
648 NodeContainer wifiStaNodes(2);
649
650 // create MLDs
651 WifiHelper wifi;
652 wifi.SetStandard(WIFI_STANDARD_80211be);
653 wifi.SetRemoteStationManager("ns3::PowerSaveTestRateManager");
654
657 phy.SetChannel(channel);
658 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
659 phy.Set(0, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
660 phy.Set(1, "ChannelSettings", StringValue("{120, 0, BAND_5GHZ, 0}"));
661
662 WifiMacHelper mac;
663 mac.SetType("ns3::ApWifiMac",
664 "QosSupported",
665 BooleanValue(true),
666 "BeaconDtimPeriod",
667 UintegerValue(2),
668 "FrameRetryLimit",
669 UintegerValue(5), // ensure PS-Poll is retransmitted 5 times
670 "Ssid",
671 SsidValue(Ssid("power-save-ssid")));
672
673 auto apDev = wifi.Install(phy, mac, wifiApNode);
674
675 // Force non-AP MLD to perform association on link 1, while non-AP STA performs association
676 // on link 0, so that there is no risk of collision among association frames
677 phy.Set(0, "ChannelSettings", StringValue("{60, 0, BAND_5GHZ, 0}"));
678
679 mac.SetType("ns3::StaWifiMac",
680 "QosSupported",
681 BooleanValue(true),
682 "Ssid",
683 SsidValue(Ssid("power-save-ssid")));
684 mac.SetPowerSaveManager("ns3::DefaultPowerSaveManager");
685
686 // TID 0 is mapped on both links, TID 2 is mapped on link 1 only
687 wifi.ConfigEhtOptions("TidToLinkMappingDl", StringValue("0 0,1; 2 1"));
688 wifi.ConfigEhtOptions("TidToLinkMappingUl", StringValue("0 0,1; 2 1"));
689
690 auto staDev = wifi.Install(phy, mac, wifiStaNodes.Get(0));
691
692 // create SLD
693 wifi.SetStandard(m_standard);
694 phy = SpectrumWifiPhyHelper{};
695 phy.SetChannel(channel);
696 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
697 phy.Set(0, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
698
699 staDev.Add(wifi.Install(phy, mac, wifiStaNodes.Get(1)));
700
701 // Assign fixed streams to random variables in use
702 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(staDev, apDev), streamNumber);
703
704 auto positionAlloc = CreateObject<ListPositionAllocator>();
705 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
706 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
707 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
708 MobilityHelper mobility;
709 mobility.SetPositionAllocator(positionAlloc);
710 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
711 mobility.Install(wifiApNode);
712 mobility.Install(wifiStaNodes);
713
715 m_staMacs.push_back(
716 DynamicCast<StaWifiMac>(DynamicCast<WifiNetDevice>(staDev.Get(0))->GetMac()));
717 m_staMacs.push_back(
718 DynamicCast<StaWifiMac>(DynamicCast<WifiNetDevice>(staDev.Get(1))->GetMac()));
719
720 // define the jitter for the initial Beacon frames on the two links, so that Beacon frames
721 // on the two links are spaced enough, as expected by the checks in this test
722 auto beaconJitter = CreateObject<DeterministicRandomVariable>();
723 beaconJitter->SetValueArray(m_jitter);
724 m_apMac->SetAttribute("BeaconJitter", PointerValue(beaconJitter));
725
726 // Trace PSDUs passed to the PHY on all devices
727 for (const auto& mac : std::list<Ptr<WifiMac>>{m_apMac, m_staMacs[0], m_staMacs[1]})
728 {
729 for (uint8_t phyId = 0; phyId < mac->GetDevice()->GetNPhys(); ++phyId)
730 {
731 mac->GetDevice()->GetPhy(phyId)->TraceConnectWithoutContext(
732 "PhyTxPsduBegin",
733 MakeCallback(&WifiPowerSaveModeTest::Transmit, this).Bind(mac, phyId));
734 }
735 }
736
737 // install packet socket on all nodes
738 PacketSocketHelper packetSocket;
739 packetSocket.Install(wifiApNode);
740 packetSocket.Install(wifiStaNodes);
741
742 // install a packet socket server on all nodes
743 for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); ++nodeIt)
744 {
745 PacketSocketAddress srvAddr;
746 auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
747 NS_TEST_ASSERT_MSG_NE(device, nullptr, "Expected a WifiNetDevice");
748 srvAddr.SetSingleDevice(device->GetIfIndex());
749 srvAddr.SetProtocol(1);
750
751 auto server = CreateObject<PacketSocketServer>();
752 server->SetLocal(srvAddr);
753 (*nodeIt)->AddApplication(server);
754 server->SetStartTime(Seconds(0)); // now
755 server->SetStopTime(m_duration);
756 }
757
758 for (std::size_t nodeId = 0; nodeId < NodeList::GetNNodes(); nodeId++)
759 {
761 "/NodeList/" + std::to_string(nodeId) +
762 "/ApplicationList/*/$ns3::PacketSocketServer/Rx",
764 }
765
766 // Trace PHY state changes at the non-AP STAs
767 for (uint32_t id = 0; id < 2; ++id)
768 {
769 for (uint8_t phyId = 0; phyId < m_staMacs[id]->GetDevice()->GetNPhys(); ++phyId)
770 {
771 m_staMacs[id]->GetDevice()->GetPhy(phyId)->GetState()->TraceConnectWithoutContext(
772 "State",
774 }
775 }
776
777 // Trace MPDUs enqueued at the AP
779 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_Txop/Queue/Enqueue",
782 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/BK_Txop/Queue/Enqueue",
784
785 // Install post reception error models
786 m_apMac->GetWifiPhy(0)->SetPostReceptionErrorModel(m_apErrorModel);
787 m_apMac->GetWifiPhy(1)->SetPostReceptionErrorModel(m_apErrorModel);
788 m_staMacs[0]->GetWifiPhy(0)->SetPostReceptionErrorModel(m_nonApMldErrorModel);
789 m_staMacs[0]->GetWifiPhy(1)->SetPostReceptionErrorModel(m_nonApMldErrorModel);
790 m_staMacs[1]->GetWifiPhy(0)->SetPostReceptionErrorModel(m_nonApStaErrorModel);
791
792 SetEvents();
793}
794
795void
797 uint8_t phyId,
798 WifiConstPsduMap psduMap,
799 WifiTxVector txVector,
800 Watt_u txPower)
801{
802 const auto linkId = mac->GetLinkForPhy(phyId);
803 NS_TEST_ASSERT_MSG_EQ(linkId.has_value(), true, "No link found for PHY ID " << +phyId);
804 const auto psdu = psduMap.cbegin()->second;
805 const auto& hdr = psduMap.begin()->second->GetHeader(0);
806 const auto txDuration =
807 WifiPhy::CalculateTxDuration(psdu, txVector, mac->GetWifiPhy(*linkId)->GetPhyBand());
808
809 const auto checkFrame =
810 (hdr.IsBeacon() || (m_apMac->IsAssociated(m_staMacs[0]->GetAddress()).has_value() &&
811 m_apMac->IsAssociated(m_staMacs[1]->GetAddress()).has_value()));
812
813 for (const auto& [aid, psdu] : psduMap)
814 {
815 std::stringstream ss;
816 if (checkFrame && !m_events.empty())
817 {
818 ss << "PSDU #" << ++m_processedEvents;
819 }
820
821 ss << std::setprecision(10) << " Link ID " << +linkId.value() << " Phy ID " << +phyId
822 << " TX duration=" << txDuration.As(Time::MS) << " #MPDUs " << psdu->GetNMpdus();
823 for (auto it = psdu->begin(); it != psdu->end(); ++it)
824 {
825 ss << "\n" << **it;
826 }
827 NS_LOG_INFO(ss.str());
828 }
829 NS_LOG_INFO("TXVECTOR = " << txVector << "\n");
830
831 if (!checkFrame)
832 {
833 return;
834 }
835
836 if (!m_events.empty())
837 {
838 // check that the expected frame is being transmitted
840 hdr.GetTypeString(),
841 "Unexpected MAC header type for frame transmitted at time "
842 << Simulator::Now().As(Time::US));
843 // perform actions/checks, if any
844 if (m_events.front().func)
845 {
846 m_events.front().func(psdu, txDuration, *linkId);
847 }
848
849 m_events.pop_front();
850 }
851}
852
853void
855{
856 NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
857 m_rxPkts[nodeId]++;
858}
859
860void
862{
865
866 NS_TEST_EXPECT_MSG_EQ(m_events.empty(), true, "Not all events took place");
867
869}
870
871void
873 uint8_t phyId,
874 Time stateStart,
875 Time stateDuration,
876 WifiPhyState state)
877{
878 if (state == WifiPhyState::SLEEP)
879 {
880 NS_LOG_DEBUG("PHY " << +phyId << " of STA " << nodeId << " was in sleep mode from "
881 << stateStart.As(Time::S) << " to "
882 << (stateStart + stateDuration).As(Time::S) << "\n");
883 }
884}
885
886void
888{
889 NS_LOG_DEBUG("QUEUED " << *mpdu << "\n");
890}
891
892void
894{
895 constexpr auto DTIM = true;
896 constexpr auto NO_DTIM = false;
897 constexpr auto MCAST_PENDING = true;
898 constexpr auto MCAST_NOT_PENDING = false;
899 constexpr std::size_t NON_AP_MLD = 0;
900 constexpr std::size_t NON_AP_STA = 1;
901 constexpr auto SLEEP = true;
902 constexpr auto AWAKE = false;
903
904 // lambda to check the TIM element contained in the given Beacon frame
905 auto checkTim = [this](Ptr<WifiMpdu> mpdu,
906 bool isDtim,
907 bool hasMulticastPending,
908 const std::map<uint16_t, bool>& aidIsSetMap) {
909 const auto now = Simulator::Now();
910 NS_TEST_ASSERT_MSG_EQ(mpdu->GetHeader().IsBeacon(),
911 true,
912 "Expected PSDU transmitted at " << now << " to be a Beacon frame");
913 MgtBeaconHeader beacon;
914 mpdu->GetPacket()->PeekHeader(beacon);
915 auto& tim = beacon.Get<Tim>();
916 NS_TEST_ASSERT_MSG_EQ(tim.has_value(),
917 true,
918 "Expected beacon in PSDU transmitted at "
919 << now << " to contain a TIM element");
920 NS_TEST_EXPECT_MSG_EQ((tim->m_dtimCount == 0),
921 isDtim,
922 "Unexpected DTIM count value for PSDU transmitted at " << now);
923 NS_TEST_EXPECT_MSG_EQ(tim->m_hasMulticastPending,
924 hasMulticastPending,
925 "Unexpected multicast pending bit value for PSDU transmitted at "
926 << now);
927 for (const auto& [aid, isSet] : aidIsSetMap)
928 {
929 NS_TEST_EXPECT_MSG_EQ(tim->HasAid(aid),
930 isSet,
931 "Unexpected AID " << aid << " bit value for PSDU transmitted at "
932 << now);
933 }
934 };
935
936 // lambda to check that a non-AP STA affiliated with a given device and operating on the
937 // given link is in the given PM mode and in the awake or sleep state
938 auto checkSleep = [this](std::size_t staId,
939 uint8_t linkId,
941 bool sleep) {
943 m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(
944 m_staMacs[staId]->GetAddress()),
946 "[PSDU #" << m_processedEvents << "] "
947 << "Unexpected power management mode stored at the AP MLD for the non-AP STA"
948 << (staId == 0 ? " affiliated with the non-AP MLD and operating on link " +
949 std::to_string(linkId)
950 : ""));
952 +m_staMacs[staId]->GetPmMode(linkId),
953 +pmMode,
954 "[PSDU #" << m_processedEvents << "] "
955 << "Unexpected power management mode for non-AP STA"
956 << (staId == 0 ? " affiliated with the non-AP MLD and operating on link " +
957 std::to_string(linkId)
958 : ""));
960 m_staMacs[staId]->GetWifiPhy(linkId)->IsStateSleep(),
961 sleep,
962 "[" << Simulator::Now() << "] "
963 << "Unexpected sleep state for the PHY of the non-AP STA"
964 << (staId == 0 ? " affiliated with the non-AP MLD and operating on link " +
965 std::to_string(linkId)
966 : ""));
967 };
968
969 // lambda to drop all MPDUs in the given PSDU
970 auto dropPsdu = [](Ptr<const WifiPsdu> psdu, Ptr<ListErrorModel> model) {
971 std::list<uint64_t> uids;
972 for (const auto& mpdu : *PeekPointer(psdu))
973 {
974 uids.push_back(mpdu->GetPacket()->GetUid());
975 }
976 model->SetList(uids);
977 };
978
979 /**
980 * (1) The AP MLD sends a Beacon frame on each of its two links. Both Beacon frames contain
981 * a DTIM and the multicast pending bit is not set. After receiving these Beacon frames,
982 * the non-AP STA and the non-AP MLD start the association procedure.
983 */
984 m_events.emplace_back(WIFI_MAC_MGT_BEACON,
985 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
986 checkTim(*psdu->begin(), DTIM, MCAST_NOT_PENDING, {});
987 });
988
989 m_events.emplace_back(WIFI_MAC_MGT_BEACON,
990 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
991 checkTim(*psdu->begin(), DTIM, MCAST_NOT_PENDING, {});
992 });
993
994 /**
995 * (2) Frames (other than Beacon frames) exchanged before non-AP STA and non-AP MLD are
996 * considered associated by the AP MLD are ignored. The following frames are the Data Null/Ack
997 * exchange for the non-AP STA affiliated with the non-AP MLD to switch to active mode.
998 */
999 m_events.emplace_back(
1001 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1002 // check that non-AP STA and non-AP MLD are associated and received an AID of 2
1003 // or 3 (AID 1 is reserved by the AP MLD for groupcast traffic on the other
1004 // link)
1005 NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->IsAssociated(),
1006 true,
1007 "Expected non-AP MLD to be associated");
1008 const auto nonApMldAid = m_staMacs[0]->GetAssociationId();
1009 NS_TEST_EXPECT_MSG_EQ((nonApMldAid == 2 || nonApMldAid == 3),
1010 true,
1011 "Unexpected AID for non-AP MLD (" << nonApMldAid << ")");
1012 NS_TEST_EXPECT_MSG_EQ(m_staMacs[1]->IsAssociated(),
1013 true,
1014 "Expected non-AP STA to be associated");
1015 const auto nonApStaAid = m_staMacs[1]->GetAssociationId();
1016 NS_TEST_EXPECT_MSG_EQ((nonApStaAid == 2 || nonApStaAid == 3),
1017 true,
1018 "Unexpected AID for non-AP STA (" << nonApStaAid << ")");
1019 // check that the Power Management flag is set to 0
1020 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
1021 false,
1022 "Expected the Power Management flag not to be set");
1023 });
1024 m_events.emplace_back(
1026 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1027 // check that all non-AP STAs affiliated with the AP MLD are in active
1028 // mode after the reception of the Ack in response to the Data Null
1029 // frame
1030 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1031 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1032 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1033 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1034 });
1035 });
1036
1037 /**
1038 * (3) After two other Beacon frames (each sent on a distinct link), a broadcast frame is
1039 * queued at the AP MLD, which immediately transmits it on both links, given that no STA
1040 * is in power save mode.
1041 */
1042
1043 PacketSocketAddress broadcastAddr;
1044 broadcastAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
1046 broadcastAddr.SetProtocol(1);
1047
1048 const auto delay = MilliSeconds(5); // about a TXOP duration
1049
1050 m_events.emplace_back(WIFI_MAC_MGT_BEACON,
1051 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1052 checkTim(*psdu->begin(),
1053 NO_DTIM,
1054 MCAST_NOT_PENDING,
1055 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1056 });
1057
1058 m_events.emplace_back(
1060 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1061 checkTim(*psdu->begin(),
1062 NO_DTIM,
1063 MCAST_NOT_PENDING,
1064 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1065 // queue a broadcast frame
1066 m_apMac->GetDevice()->GetNode()->AddApplication(
1067 GetApplication(broadcastAddr, 1, 1000, delay));
1068 });
1069
1070 m_events.emplace_back(
1072 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1073 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1075 "Expected a broadcast frame");
1076 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1077 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1078 1,
1079 "Non-AP MLD expected to receive a broadcast frame");
1080 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1081 (linkId == 0 ? 1 : 0),
1082 "Non-AP STA expected to receive a broadcast frame");
1083 });
1084 });
1085
1086 m_events.emplace_back(
1088 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1089 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1091 "Expected a broadcast frame");
1092 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1093 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1094 2,
1095 "Non-AP MLD expected to receive another broadcast frame");
1096 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1097 1,
1098 "Non-AP STA expected to receive a broadcast frame");
1099 });
1100 });
1101
1102 /**
1103 * (4) After two other Beacon frames (each sent on a distinct link), the non-AP STA
1104 * (operating on link 0) and the non-AP STA affiliated with the non-AP MLD and operating
1105 * on link 1 switch to power save mode by sending a Data Null frame with the PM flag set to 1.
1106 * After receiving the Ack response, the non-AP STAs put their PHYs to sleep.
1107 * Also, after transmitting the last Ack response, a broadcast frame is queued at the AP
1108 * MLD, but it is buffered because there are STAs in power save mode on both links.
1109 */
1110 m_events.emplace_back(WIFI_MAC_MGT_BEACON,
1111 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1112 checkTim(*psdu->begin(),
1113 DTIM,
1114 MCAST_NOT_PENDING,
1115 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1116 });
1117
1118 m_events.emplace_back(
1120 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1121 checkTim(*psdu->begin(),
1122 DTIM,
1123 MCAST_NOT_PENDING,
1124 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1125 // switch non-AP STAs to Power Save mode
1126 Simulator::Schedule(delay, [=, this]() {
1127 m_staMacs[0]->SetPowerSaveMode({true, 1});
1128 m_staMacs[1]->SetPowerSaveMode({true, 0});
1129 });
1130 });
1131
1132 m_events.emplace_back(
1134 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1135 // check that the Power Management flag is set to 1
1136 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
1137 true,
1138 "Expected the Power Management flag to be set");
1139 });
1140 m_events.emplace_back(
1142 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1143 // check that the Power Management flag is set to 1
1144 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
1145 true,
1146 "Expected the Power Management flag to be set");
1147 });
1148
1149 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1150
1151 m_events.emplace_back(
1153 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1154 // check that all non-AP STAs are in the expected power management mode and their PHYs
1155 // are in the expected sleep state after the reception of the Ack in response to the
1156 // last Data Null frame
1157 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1158 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1159 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1160 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1161 });
1162
1163 // queue one broadcast frame at the AP MLD when Ack transmission is completed
1164 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1165 m_apMac->GetDevice()->GetNode()->AddApplication(
1166 GetApplication(broadcastAddr, 1, 1000, delay));
1167 });
1168 });
1169
1170 /**
1171 * (5) The next two Beacon frames (on the two links) do not contain a DTIM, thus the broadcast
1172 * frames are still buffered. Check that all non-AP STAs operating on the link on which the
1173 * Beacon frame is transmitted are awake to listen to the Beacon frame and that the non-AP STAs
1174 * in power save mode return to sleep after the Beacon frame.
1175 */
1176 m_events.emplace_back(
1178 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1179 checkTim(*psdu->begin(),
1180 NO_DTIM,
1181 MCAST_NOT_PENDING,
1182 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1183 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1184 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1185 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1186
1187 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1188 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1189 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1190 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1191 });
1192 });
1193 m_events.emplace_back(
1195 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1196 checkTim(*psdu->begin(),
1197 NO_DTIM,
1198 MCAST_NOT_PENDING,
1199 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1200 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1201 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1202 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1203
1204 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1205 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1206 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1207 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1208 });
1209 });
1210
1211 /**
1212 * (6) The next Beacon frame includes a DTIM and the AID bits in the virtual bitmap
1213 * corresponding to both AID 0 (buffered group addressed frames on the same link) and AID 1
1214 * (buffered group addressed frames on the other link) are both set. Therefore, after receiving
1215 * the Beacon frame, the non-AP STAs operating on the link on which the Beacon frame was
1216 * received stay awake to receive the broadcast frames. When the transmission of the Beacon
1217 * frame starts, a QoS data frame with TID 4 for the non-AP MLD is queued at the AP MLD.
1218 */
1219 PacketSocketAddress nonApMldAddr;
1220 nonApMldAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
1221 nonApMldAddr.SetPhysicalAddress(m_staMacs[0]->GetDevice()->GetAddress());
1222 nonApMldAddr.SetProtocol(1);
1223
1224 m_events.emplace_back(
1226 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1227 checkTim(*psdu->begin(),
1228 DTIM,
1229 MCAST_PENDING,
1230 /* AID bits */ {{1, true}, {2, false}, {3, false}});
1231 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1232 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1233 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1234
1235 // queue a unicast frame with TID 4 at the AP MLD addressed to the non-AP MLD
1236 m_apMac->GetDevice()->GetNode()->AddApplication(
1237 GetApplication(nonApMldAddr, 1, 1000, Time{0}, 4));
1238
1239 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1240 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1241 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1242 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1243 });
1244 });
1245
1246 /**
1247 * (7) After the Beacon frame including a DTIM, the broadcast frame is sent with the More Data
1248 * flag set to 0, because at the time the frame is sent no other broadcast frame is queued.
1249 * Right after starting its transmission, another broadcast frame is queued. The non-AP STA
1250 * operating on the same link goes to sleep after the reception of the broadcast frame because
1251 * the More Data flag is set to 0. Given that a broadcast frame with the More Data flag set to
1252 * 0 is sent, the AP blocks the transmission of group addressed frames and transmits the unicast
1253 * data frame for the non-AP MLD, which has an affiliated STA in active mode on link 0.
1254 * The jitter between the initial Beacon frames sent on the two links has been set large enough
1255 * to have these frames transmitted on the same link as the first Beacon frame before a Beacon
1256 * frame is transmitted on the other link.
1257 */
1258 m_events.emplace_back(
1260 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1261 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1263 "Expected a broadcast frame");
1264 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1265 false,
1266 "Expected the More Data flag not to be set");
1267
1268 // queue another broadcast frame at the AP MLD, which is not transmitted after this
1269 // frame because this frame has the More Data flag set to zero and STAs may go to sleep
1270 // after receiving this broadcast frame
1271 m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(broadcastAddr, 1, 1000));
1272
1273 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1274 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1275 3,
1276 "Non-AP MLD expected to receive a broadcast frame");
1277 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1278 2,
1279 "Non-AP STA expected to receive a broadcast frame");
1280 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1281 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1282 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1283 });
1284 });
1285
1286 // Block Ack agreement establishment for TID 4
1287 m_events.emplace_back(WIFI_MAC_MGT_ACTION);
1288 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1289 m_events.emplace_back(WIFI_MAC_CTL_END);
1290 m_events.emplace_back(WIFI_MAC_MGT_ACTION);
1291 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1292 m_events.emplace_back(WIFI_MAC_CTL_END);
1293
1294 m_events.emplace_back(
1296 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1298 psdu->GetHeader(0).GetAddr1(),
1299 m_staMacs[NON_AP_MLD]->GetFrameExchangeManager(linkId)->GetAddress(),
1300 "Expected a unicast frame addressed to the STA affiliated with non-AP MLD on link "
1301 << +linkId);
1302 });
1303
1304 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1305 m_events.emplace_back(WIFI_MAC_CTL_END);
1306
1307 /**
1308 * (8) Next, a Beacon frame is transmitted on the other link. It includes a DTIM and the AID bit
1309 * in the virtual bitmap corresponding to AID 0 (buffered group addressed frames on the same
1310 * link) and to AID 1 (buffered group addressed frames on the other link) are both set, because
1311 * the second broadcast frame has not been transmitted on link 0. Again, after receiving the
1312 * Beacon frame, the non-AP STAs operating on the link on which the Beacon frame was received
1313 * stay awake to receive the broadcast frames. Also, two unicast frames addressed to the non-AP
1314 * STA are queued at the AP MLD, but they are buffered because the non-AP STA is in power save
1315 * mode.
1316 */
1317 PacketSocketAddress nonApStaAddr;
1318 nonApStaAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
1319 nonApStaAddr.SetPhysicalAddress(m_staMacs[1]->GetDevice()->GetAddress());
1320 nonApStaAddr.SetProtocol(1);
1321
1322 m_events.emplace_back(
1324 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1325 checkTim(*psdu->begin(),
1326 DTIM,
1327 MCAST_PENDING,
1328 /* AID bits */ {{1, true}, {2, false}, {3, false}});
1329 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1330 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1331 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1332 // queue two unicast frames at the AP MLD addressed to the non-AP STA
1333 m_apMac->GetDevice()->GetNode()->AddApplication(
1334 GetApplication(nonApStaAddr, 2, 1000, Time{0}));
1335
1336 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1337 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1338 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1339 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1340 });
1341 });
1342
1343 /**
1344 * (9) We check that the first broadcast frame has the More Data flag set to 1 and the non-AP
1345 * STAs operating on the same link stay awake after its reception. The second broadcast frame
1346 * has the More Data flag set to 0 and the non-AP STAs operating on the same link go to sleep
1347 * after its reception.
1348 */
1349
1350 m_events.emplace_back(
1352 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1353 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1355 "Expected a broadcast frame");
1356 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1357 true,
1358 "Expected the More Data flag to be set");
1359
1360 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1361 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1362 5,
1363 "Non-AP MLD expected to receive a broadcast frame");
1364 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1365 2,
1366 "Non-AP STA expected to receive a broadcast frame");
1367 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1368 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 1);
1369 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, linkId != 0);
1370 });
1371 });
1372
1373 m_events.emplace_back(
1375 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1376 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1378 "Expected a broadcast frame");
1379 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1380 false,
1381 "Expected the More Data flag not to be set");
1382
1383 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1384 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1385 6,
1386 "Non-AP MLD expected to receive a broadcast frame");
1387 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1388 2,
1389 "Non-AP STA expected to receive a broadcast frame");
1390 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1391 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1392 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1393 });
1394 });
1395
1396 /**
1397 * (10) We assume that the Beacon frame on link 0 is sent first. This Beacon frame has the AID
1398 * bit in the virtual bitmap corresponding to the AID of the non-AP STA set to 1. The non-AP STA
1399 * is awake before the transmission of the Beacon frame and stays awake afterwards. The non-AP
1400 * STA sends a PS Poll frame, receives a QoS data frame from the AP (having the More Data flag
1401 * set to 1) and transmits an Ack. Then, it stays awake to send another PS Poll frame.
1402 */
1403 m_events.emplace_back(
1405 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1407 +linkId,
1408 0,
1409 "Beacon on link 0 should be sent first; try to modify the Beacon jitter");
1410
1411 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
1412 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
1413 checkTim(*psdu->begin(),
1414 NO_DTIM,
1415 MCAST_NOT_PENDING,
1416 /* AID bits */ {{1, false}, {aidNonApMld, false}, {aidNonApSta, true}});
1417 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1418 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1419 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1420
1421 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1422 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1423 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1424 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1425 });
1426 });
1427
1428 m_events.emplace_back(
1430 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1431 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1432 m_staMacs[1]->GetAddress(),
1433 "Unexpected transmitter address for PS Poll frame");
1434 });
1435
1436 m_events.emplace_back(
1438 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1439 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1440 m_staMacs[1]->GetAddress(),
1441 "Unexpected receiver address for QoS Data frame after PS Poll");
1442 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1443 true,
1444 "Expected the More Data flag to be set");
1445
1446 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1447 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1448 3,
1449 "Non-AP STA expected to receive a unicast frame");
1450 });
1451 });
1452
1453 m_events.emplace_back(
1455 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1456 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1457 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1458 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1459 // non-AP stays awake to send another PS Poll frame
1460 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1461 });
1462 });
1463
1464 /**
1465 * (11) The second PS Poll frame is discarded multiple times by the AP MLD for a post reception
1466 * error. We configure the remote station manager on the non-AP STA to drop the PS Poll after
1467 * the 5th unsuccessful transmission.
1468 */
1469
1470 m_events.emplace_back(
1472 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1473 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1474 m_staMacs[1]->GetAddress(),
1475 "Unexpected transmitter address for PS Poll frame");
1476 dropPsdu(psdu, m_apErrorModel);
1477 });
1478
1479 m_events.emplace_back(WIFI_MAC_CTL_PSPOLL);
1480 m_events.emplace_back(WIFI_MAC_CTL_PSPOLL);
1481 m_events.emplace_back(WIFI_MAC_CTL_PSPOLL);
1482
1483 m_events.emplace_back(
1485 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1486 auto rsm =
1487 DynamicCast<PowerSaveTestRateManager>(m_staMacs[1]->GetWifiRemoteStationManager(0));
1488 NS_TEST_ASSERT_MSG_NE(rsm, nullptr, "Unexpected type of remote station manager");
1489 rsm->m_drop = true;
1490
1491 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1492 // reset list of UIDs to drop at the AP MLD
1493 m_apErrorModel->SetList({});
1494 });
1495 });
1496
1497 /**
1498 * (12) The next transmitted frame is the Beacon frame on link 1. The non-AP STA turned to the
1499 * sleep state after giving up sending the PS Poll frame (which was dropped) and is still in
1500 * the sleep state. Drop the broadcast frame that is still buffered for transmission on link 0,
1501 * so as to avoid a possible collision after the next Beacon frame including a DTIM sent on link
1502 * 0 between the AP (trying to send the broadcast frame) and the non-AP STA (trying to send a
1503 * PS-Poll frame)
1504 */
1505
1506 m_events.emplace_back(
1508 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1509 NS_TEST_EXPECT_MSG_EQ(+linkId, 1, "Expected a Beacon frame on link 1");
1510
1511 checkTim(*psdu->begin(),
1512 NO_DTIM,
1513 MCAST_NOT_PENDING,
1514 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1515 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1516 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1517 // the non-AP STA is in sleep state after giving up sending the PS Poll frame
1518 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1519
1520 // reset the configuration on the remote station manager of the non-AP STA
1521 auto rsm =
1522 DynamicCast<PowerSaveTestRateManager>(m_staMacs[1]->GetWifiRemoteStationManager(0));
1523 NS_TEST_ASSERT_MSG_NE(rsm, nullptr, "Unexpected type of remote station manager");
1524 rsm->m_drop = false;
1525
1526 // drop queued broadcast frame
1529 m_apMac->GetFrameExchangeManager(0)->GetAddress(),
1530 0);
1531 auto mpdu = m_apMac->GetTxopQueue(AC_BE)->PeekByQueueId(queueId);
1532 NS_TEST_ASSERT_MSG_NE(mpdu, nullptr, "Broadcast data frame not found");
1533 m_apMac->GetTxopQueue(AC_BE)->Remove(mpdu);
1534
1535 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1536 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1537 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1538 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1539 });
1540 });
1541
1542 /**
1543 * (13) The next Beacon frame is sent again on link 0. This Beacon frame has again the AID bit
1544 * in the virtual bitmap corresponding to the AID of the non-AP STA set to 1. The non-AP STA is
1545 * awake before the transmission of the Beacon frame and stays awake afterwards. The non-AP STA
1546 * sends a PS Poll frame, receives a QoS data frame from the AP (having the More Data flag set
1547 * to 0) and transmits an Ack. Then, it goes to sleep because no other QoS data frame is
1548 * expected to be received from the AP.
1549 */
1550 m_events.emplace_back(
1552 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1553 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a Beacon frame on link 0");
1554
1555 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
1556 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
1557 checkTim(*psdu->begin(),
1558 DTIM,
1559 MCAST_NOT_PENDING,
1560 /* AID bits */ {{1, false}, {aidNonApMld, false}, {aidNonApSta, true}});
1561 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1562 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1563 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1564
1565 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1566 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1567 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1568 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1569 });
1570 });
1571
1572 m_events.emplace_back(
1574 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1575 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1576 m_staMacs[1]->GetAddress(),
1577 "Unexpected transmitter address for PS Poll frame");
1578 });
1579
1580 m_events.emplace_back(
1582 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1583 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1584 m_staMacs[1]->GetAddress(),
1585 "Unexpected receiver address for QoS Data frame after PS Poll");
1586 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1587 false,
1588 "Expected the More Data flag not to be set");
1589
1590 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1591 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[2],
1592 4,
1593 "Non-AP STA expected to receive a unicast frame");
1594 });
1595 });
1596
1597 m_events.emplace_back(
1599 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1600 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1601 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1602 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1603 // non-AP STAs goes to sleep
1604 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1605 });
1606 });
1607
1608 /**
1609 * (14) The next Beacon frame is sent on link 1. Non-AP STAs operating on link 1 wake up to
1610 * listen to the Beacon and go to sleep afterwards. After the transmission of the Beacon frame,
1611 * two unicast data frames with TID 0 are queued at the AP MLD and addressed to the non-AP MLD.
1612 * Given that TID 0 is mapped on both links and, specifically, is mapped onto link 0, on which
1613 * an affiliated non-AP STA is operating in active mode, the unicast frames are not buffered and
1614 * are transmitted on link 0 (aggregated in an A-MPDU) after the frame exchanges to establish
1615 * the Block Ack agreement in the DL direction. These MPDUs have both the Power Management flag
1616 * and the More Data flag not set, because the More Data flag is used by the AP MLD when
1617 * transmitting frames to a non-AP STA in PS mode.
1618 */
1619 m_events.emplace_back(
1621 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1622 NS_TEST_EXPECT_MSG_EQ(+linkId, 1, "Expected a Beacon frame on link 1");
1623
1624 checkTim(*psdu->begin(),
1625 DTIM,
1626 MCAST_NOT_PENDING,
1627 /* AID bits */ {{1, false}, {2, false}, {3, false}});
1628 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1629 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1630 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1631
1632 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1633 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, false);
1634 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, true);
1635 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, true);
1636 // queue two unicast frames with TID 0 at the AP MLD addressed to the non-AP MLD
1637 m_apMac->GetDevice()->GetNode()->AddApplication(
1638 GetApplication(nonApMldAddr, 2, 1000, Time{0}));
1639 });
1640 });
1641
1642 m_events.emplace_back(
1644 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1645 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected an Action frame on link 0");
1646
1647 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1648 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
1649 "Unexpected receiver address for first Action frame");
1650
1651 {
1652 WifiActionHeader actionHdr;
1653 psdu->GetPayload(0)->PeekHeader(actionHdr);
1656 "Expected an Action frame of BLOCK_ACK category");
1659 "Expected an ADDBA Request frame");
1660 }
1661
1662 // non-AP STAs in power save mode are sleeping
1663 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1664 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1665 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1666 });
1667
1668 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1669
1670 m_events.emplace_back(
1672 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1673 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected an Action frame on link 0");
1674
1675 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1676 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
1677 "Unexpected transmitter address for second Action frame");
1678 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1679 false,
1680 "Expected the More Data flag not to be set");
1681 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
1682 false,
1683 "Expected the Power Management flag not to be set");
1684 {
1685 WifiActionHeader actionHdr;
1686 psdu->GetPayload(0)->PeekHeader(actionHdr);
1689 "Expected an Action frame of BLOCK_ACK category");
1692 "Expected an ADDBA Response frame");
1693 }
1694
1695 // non-AP STAs in power save mode are sleeping
1696 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1697 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1698 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1699 });
1700
1701 m_events.emplace_back(WIFI_MAC_CTL_ACK);
1702
1703 m_events.emplace_back(
1705 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1706 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a QoS Data frame on link 0");
1707
1708 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
1709 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
1710 "Unexpected receiver address for unicast QoS Data frame");
1711 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1712 m_apMac->GetFrameExchangeManager(0)->GetAddress(),
1713 "Unexpected transmitter address for unicast QoS Data frame");
1714 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(), 2, "Expected an A-MPDU to be sent");
1715 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1716 false,
1717 "Expected the More Data flag of the first MPDU not to be set");
1718 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(1).IsMoreData(),
1719 false,
1720 "Expected the More Data flag of the second MPDU not to be set");
1722 psdu->GetHeader(0).IsPowerManagement(),
1723 false,
1724 "Expected the Power Management flag of the first MPDU not to be set");
1726 psdu->GetHeader(1).IsPowerManagement(),
1727 false,
1728 "Expected the Power Management flag of the second MPDU not to be set");
1729 NS_TEST_EXPECT_MSG_EQ(+psdu->GetHeader(0).GetQosTid(),
1730 0,
1731 "Unexpected TID value for the first MPDU");
1732 NS_TEST_EXPECT_MSG_EQ(+psdu->GetHeader(1).GetQosTid(),
1733 0,
1734 "Unexpected TID value for the second MPDU");
1735
1736 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1737 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1738 8,
1739 "Non-AP MLD expected to receive two more (unicast) frames");
1740 });
1741 });
1742
1743 /**
1744 * (15) The non-AP STA affiliated with the non-AP MLD and operating on link 0 transmits a
1745 * BlockAck response. Afterwards, two unicast Data frames with TID 2 are queued at the AP MLD
1746 * and addressed to the non-AP MLD. These frames are buffered because TID 2 is only mapped to
1747 * link 1, on which an affiliated non-AP STA in PS mode is operating.
1748 */
1749 m_events.emplace_back(
1751 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1752 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a BlockAck response on link 0");
1753
1754 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1755 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1756 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1757
1758 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1759 // queue two unicast frames with TID 2 at the AP MLD addressed to the non-AP MLD
1760 m_apMac->GetDevice()->GetNode()->AddApplication(
1761 GetApplication(nonApMldAddr, 2, 1000, Time{0}, 2));
1762 });
1763 });
1764
1765 /**
1766 * (16) The next frame is a Beacon sent on link 0. The AID bit in the virtual bitmap
1767 * corresponding to the AID of the non-AP MLD is set to 1 because there are buffered units. The
1768 * non-AP STA affiliated with the non-AP MLD and operating on link 0 is in active mode, hence it
1769 * is not supposed to send a PS Poll frame.
1770 */
1771 m_events.emplace_back(
1773 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1774 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a Beacon frame on link 0");
1775
1776 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
1777 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
1778 checkTim(*psdu->begin(),
1779 NO_DTIM,
1780 MCAST_NOT_PENDING,
1781 /* AID bits */ {{1, false}, {aidNonApMld, true}, {aidNonApSta, false}});
1782
1783 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1784 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1785 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1786
1787 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1788 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1789 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1790 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1791 });
1792 });
1793
1794 /**
1795 * (17) The next frame is thus a Beacon sent on link 1. The AID bit in the virtual bitmap
1796 * corresponding to the AID of the non-AP MLD is still set to 1 because there are buffered
1797 * units. The non-AP STA affiliated with the non-AP MLD and operating on link 1 in PS mode
1798 * stays awake to send a PS Poll frame. The AP MLD sends the first buffered unit, which is
1799 * corrupted at the receiver. After the timeout, the non-AP STA affiliated with the non-AP MLD
1800 * and operating on link 1 sends again a PS Poll, receives a buffered unit and sends the Ack
1801 * response (repeated twice because the two buffered units are sent one at a time).
1802 * After the last Ack response, two QoS Data frames are queued at the non-AP STA and addressed
1803 * to the AP MLD.
1804 */
1805 m_events.emplace_back(
1807 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1808 NS_TEST_EXPECT_MSG_EQ(+linkId, 1, "Expected a Beacon frame on link 1");
1809
1810 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
1811 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
1812 checkTim(*psdu->begin(),
1813 NO_DTIM,
1814 MCAST_NOT_PENDING,
1815 /* AID bits */ {{1, false}, {aidNonApMld, true}, {aidNonApSta, false}});
1816
1817 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1818 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1819 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1820
1821 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1822 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1823 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1824 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1825 });
1826 });
1827
1828 m_events.emplace_back(
1830 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1831 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1832 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1833 "Unexpected transmitter address for PS Poll frame");
1834 });
1835
1836 m_events.emplace_back(
1838 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1839 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1840 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1841 "Unexpected receiver address for QoS Data frame after PS Poll");
1842 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1843 true,
1844 "Expected the More Data flag to be set");
1845
1846 // corrupt the reception of the frame at the non-AP STA
1847 dropPsdu(psdu, m_nonApMldErrorModel);
1848
1849 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1850 // reset error list, so that the frame is corrupted only once
1851 m_nonApMldErrorModel->SetList({});
1852 });
1853 });
1854
1855 m_events.emplace_back(
1857 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1858 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1859 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1860 "Unexpected transmitter address for PS Poll frame");
1861 });
1862
1863 m_events.emplace_back(
1865 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1866 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1867 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1868 "Unexpected receiver address for QoS Data frame after PS Poll");
1869 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1870 true,
1871 "Expected the More Data flag to be set");
1872
1873 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1874 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1875 9,
1876 "Non-AP MLD expected to receive another unicast frame");
1877 });
1878 });
1879
1880 m_events.emplace_back(
1882 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1883 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
1884 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1885 // non-AP STA on link 1 stays awake
1886 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1887 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1888 });
1889 });
1890
1891 m_events.emplace_back(
1893 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1894 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1895 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1896 "Unexpected transmitter address for PS Poll frame");
1897 });
1898
1899 m_events.emplace_back(
1901 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1902 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
1903 m_staMacs[0]->GetFrameExchangeManager(1)->GetAddress(),
1904 "Unexpected receiver address for QoS Data frame after PS Poll");
1905 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
1906 false,
1907 "Expected the More Data flag not to be set");
1908
1909 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1910 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
1911 10,
1912 "Non-AP MLD expected to receive another unicast frame");
1913 });
1914 });
1915
1916 PacketSocketAddress apMldAddr;
1917 apMldAddr.SetSingleDevice(m_staMacs[1]->GetDevice()->GetIfIndex());
1918 apMldAddr.SetPhysicalAddress(m_apMac->GetDevice()->GetAddress());
1919 apMldAddr.SetProtocol(1);
1920
1921 m_events.emplace_back(
1923 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1924 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1925 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1926 // non-AP STA on link 1 goes to sleep
1927 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1928 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1929 // queue two unicast frames at the non-AP STA addressed to the AP MLD
1930 m_staMacs[1]->GetDevice()->GetNode()->AddApplication(
1931 GetApplication(apMldAddr, 2, 1000, Time{0}));
1932 });
1933 });
1934
1935 /**
1936 * (18) Two QoS data frames have been queued at the non-AP STA, which is in sleep state. The
1937 * non-AP STA does not wait until the next Beacon, but it is immediately awaken to start a TXOP.
1938 * Actually, the queued frames trigger the establishment of a Block Ack agreement in the uplink
1939 * direction; the non-AP STA sends an ADDBA Request, which is acknowledged by the AP. Then, the
1940 * AP buffers the ADDBA Response, because the non-AP STA is in power save mode; the non-AP STA
1941 * has blocked transmission of QoS data frames (while waiting for ADDBA Response) and thus
1942 * releases the channel, generates backoff and restarts channel access. When the non-AP STA is
1943 * granted channel access again, it still has nothing to transmit and this time it does not
1944 * restart channel access and goes to sleep. When the ADDBA Response timer expires, the
1945 * transmission of the QoS data frames is unblocked, the non-AP STA wakes up and transmits the
1946 * two QoS data frames using normal acknowledgment; afterwards, the non-AP STA goes back to
1947 * sleep.
1948 */
1949 if (m_standard >= WIFI_STANDARD_80211n)
1950 {
1951 m_events.emplace_back(
1953 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1954 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected an Action frame on link 0");
1955
1956 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
1957 m_staMacs[1]->GetFrameExchangeManager(0)->GetAddress(),
1958 "Unexpected transmitter address for Action frame");
1960 psdu->GetHeader(0).IsPowerManagement(),
1961 true,
1962 "Expected the Power Management flag of the ADDBA Request to be set");
1963
1964 WifiActionHeader actionHdr;
1965 psdu->GetPayload(0)->PeekHeader(actionHdr);
1968 "Expected an Action frame of BLOCK_ACK category");
1971 "Expected an ADDBA Request frame");
1972
1973 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1974 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
1975 // non-AP STA woke up to transmit this frame
1976 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
1977 });
1978
1979 m_events.emplace_back(
1981 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
1982 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
1983 // check sleep state after the backoff counter has reached zero (the non-AP STA
1984 // releases the channel and does not restart channel access)
1985 auto acBe = m_staMacs[1]->GetQosTxop(AC_BE);
1986 auto backoffEnd =
1987 m_staMacs[1]->GetChannelAccessManager()->GetBackoffEndFor(acBe);
1988 Simulator::Schedule(backoffEnd - Simulator::Now() + TimeStep(1), [=] {
1989 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
1990 checkSleep(NON_AP_MLD,
1991 1,
1993 SLEEP);
1994 // non-AP STA goes to sleep because no QoS data frames can be sent
1995 checkSleep(NON_AP_STA,
1996 0,
1998 SLEEP);
1999 });
2000 });
2001 });
2002 }
2003
2004 m_events.emplace_back(
2006 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2007 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2008 m_staMacs[1]->GetFrameExchangeManager(0)->GetAddress(),
2009 "Unexpected transmitted address for QoS Data frame");
2010 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
2011 true,
2012 "Expected the Power Management flag to be set");
2013
2014 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2015 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2016 // non-AP STA woke up to transmit this frame
2017 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2018
2019 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2020 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[0],
2021 1,
2022 "AP MLD expected to receive the first unicast frame");
2023 });
2024 });
2025
2026 m_events.emplace_back(WIFI_MAC_CTL_ACK);
2027
2028 m_events.emplace_back(
2030 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2031 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2032 m_staMacs[1]->GetFrameExchangeManager(0)->GetAddress(),
2033 "Unexpected transmitted address for QoS Data frame");
2034 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
2035 true,
2036 "Expected the Power Management flag to be set");
2037
2038 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2039 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[0],
2040 2,
2041 "AP MLD expected to receive the second unicast frame");
2042 });
2043 });
2044
2045 m_events.emplace_back(
2047 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2048 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
2049 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2050 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2051 // non-AP STA goes to sleep because no queued frames
2052 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2053 });
2054 });
2055
2056 /**
2057 * (19) The next Beacon frame sent on link 0 indicates that the AP has a buffered unit (the
2058 * ADDBA Response) for the non-AP STA, which sends a PS-Poll to request the AP to transmit it.
2059 */
2060 m_events.emplace_back(
2062 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2063 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
2064 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
2065 const auto is11n = (m_standard >= WIFI_STANDARD_80211n);
2066
2067 checkTim(*psdu->begin(),
2068 DTIM,
2069 MCAST_NOT_PENDING,
2070 /* AID bits */ {{1, false}, {aidNonApMld, false}, {aidNonApSta, is11n}});
2071
2072 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2073 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2074 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2075
2076 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2077 // non-AP STA stays awake to transmit the PS-Poll
2078 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2079 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2080 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, !is11n);
2081
2082 if (m_standard < WIFI_STANDARD_80211n)
2083 {
2084 // queue two unicast frames with TID 0 at the non-AP MLD addressed to the AP MLD
2085 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2086 GetApplication(apMldAddr, 2, 1000, Time{0}));
2087 }
2088 });
2089 });
2090
2091 if (m_standard >= WIFI_STANDARD_80211n)
2092 {
2093 m_events.emplace_back(
2095 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2096 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2097 m_staMacs[1]->GetFrameExchangeManager(0)->GetAddress(),
2098 "Unexpected transmitter address for PS Poll frame");
2099 });
2100
2101 m_events.emplace_back(
2103 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2104 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
2105 m_staMacs[1]->GetFrameExchangeManager(0)->GetAddress(),
2106 "Unexpected receiver address for Action frame");
2107
2108 WifiActionHeader actionHdr;
2109 psdu->GetPayload(0)->PeekHeader(actionHdr);
2112 "Expected an Action frame of BLOCK_ACK category");
2115 "Expected an ADDBA Response frame");
2116
2117 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2118 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2119 // non-AP STA stays awake to receive this frame
2120 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2121 });
2122
2123 apMldAddr.SetSingleDevice(m_staMacs[0]->GetDevice()->GetIfIndex());
2124
2125 m_events.emplace_back(
2127 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2128 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2129 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2130 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2131 // non-AP STA goes to sleep because no queued frames
2132 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2133 // queue two unicast frames with TID 0 at the non-AP MLD addressed to the AP MLD
2134 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2135 GetApplication(apMldAddr, 2, 1000, Time{0}));
2136 });
2137 });
2138 }
2139
2140 /**
2141 * (20) Frames with TID 0 can be transmitted on both links, hence the non-AP MLD requests
2142 * channel access on both links. This implies that the non-AP STA affiliated with the non-AP MLD
2143 * and operating on link 1 awakens and generates a new backoff value. The backoff counter of the
2144 * non-AP STA affiliated with the non-AP MLD and operating on link 0 has likely reached zero
2145 * already, hence the management frames to establish the BA agreement are sent on link 0.
2146 * During such frame exchange, the backoff counter on link 1 reaches zero, channel access is
2147 * granted but no frame is available for transmission (queues are blocked while BA is being
2148 * established), hence the non-AP STA affiliated with the non-AP MLD and operating on link 1
2149 * is put to sleep.
2150 * When the non-AP MLD completes the transmission of the Ack in response to the ADDBA Response
2151 * frame, transmissions are unblocked and channel access is requested on both links. Hence, the
2152 * non-AP STA affiliated with the non-AP MLD and operating on link 1 awakens and generates a
2153 * new backoff value.
2154 */
2155 m_events.emplace_back(
2157 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2159 +linkId,
2160 0,
2161 "Expected an Action frame on link 0, try changing RNG seed and run values");
2162
2163 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2164 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2165 "Unexpected transmitter address for Action frame");
2167 psdu->GetHeader(0).IsPowerManagement(),
2168 false,
2169 "Expected the Power Management flag of the ADDBA Request not to be set");
2170
2171 WifiActionHeader actionHdr;
2172 psdu->GetPayload(0)->PeekHeader(actionHdr);
2175 "Expected an Action frame of BLOCK_ACK category");
2178 "Expected an ADDBA Request frame");
2179
2180 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2181 // non-AP STA on link 1 awakened upon channel access request
2182 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2183 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2184 });
2185
2186 m_events.emplace_back(WIFI_MAC_CTL_ACK);
2187
2188 m_events.emplace_back(
2190 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2191 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected an Action frame on link 0");
2192
2193 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
2194 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2195 "Unexpected receiver address for Action frame");
2196
2197 WifiActionHeader actionHdr;
2198 psdu->GetPayload(0)->PeekHeader(actionHdr);
2201 "Expected an Action frame of BLOCK_ACK category");
2204 "Expected an ADDBA Response frame");
2205 });
2206
2207 m_events.emplace_back(
2209 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2210 // we assume that, when the Ack transmission starts, the backoff on link 1 has
2211 // reached zero and the non-AP STA operating on link 1 has been put to sleep
2212 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2213 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2214 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2215
2216 // when the Ack transmission ends, transmissions of QoS Data frames are unblocked,
2217 // channel access is requested and the non-AP STA operating on link 1 awakens
2218 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
2219 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2220 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2221 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2222 });
2223 });
2224
2225 /**
2226 * (21) UL QoS Data frames can now be sent in an A-MPDU on either link 0 or 1 (depends on the
2227 * generated backoff values)
2228 */
2229 m_events.emplace_back(
2231 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2232 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
2233 m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
2234 "Unexpected transmitter address for unicast QoS Data frame");
2235 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2236 m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress(),
2237 "Unexpected receiver address for unicast QoS Data frame");
2238 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(), 2, "Expected an A-MPDU to be sent");
2240 psdu->GetHeader(0).IsPowerManagement(),
2241 (linkId == 1),
2242 "Unexpected value for the Power Management flag of the first MPDU");
2244 psdu->GetHeader(1).IsPowerManagement(),
2245 (linkId == 1),
2246 "Unexpected value for the Power Management flag of the second MPDU");
2247 NS_TEST_EXPECT_MSG_EQ(+psdu->GetHeader(0).GetQosTid(),
2248 0,
2249 "Unexpected TID value for the first MPDU");
2250 NS_TEST_EXPECT_MSG_EQ(+psdu->GetHeader(1).GetQosTid(),
2251 0,
2252 "Unexpected TID value for the second MPDU");
2253
2254 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2255 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[0],
2256 4,
2257 "AP MLD expected to receive two more (unicast) frames");
2258 });
2259 });
2260
2261 m_events.emplace_back(
2263 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2264 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2265 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_ACTIVE, AWAKE);
2266 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2267 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2268 // queue a unicast frame with TID 0 at the AP MLD addressed to the non-AP MLD
2269 m_apMac->GetDevice()->GetNode()->AddApplication(
2270 GetApplication(nonApMldAddr, 1, 1000, Time{0}));
2271 });
2272 });
2273
2274 /**
2275 * (22) The AP MLD transmits the QoS data with TID 0 for the non-AP MLD on link 0, but we force
2276 * a receive error at the non-AP MLD. The frame retry limit on the AP is set to 1, so that the
2277 * QoS data frame is dropped when the Ack timeout occurs; consequently, a BlockAckReq is
2278 * enqueued. The non-AP MLD is then configured to switch the affiliated non-AP STA operating
2279 * on link 0, too, to powersave mode. The affiliated non-AP STA operating on link 0 is put to
2280 * sleep after receiving the Ack in response to the sent Data Null frame.
2281 */
2282 m_events.emplace_back(
2284 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2285 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
2286 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2287 "Unexpected receiver address for QoS Data frame");
2288 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
2289 false,
2290 "Expected the More Data flag not to be set");
2291
2292 // corrupt the reception of the PSDU at the non-AP MLD
2293 dropPsdu(psdu, m_nonApMldErrorModel);
2294
2295 // set the frame retry limit on the AP to 1, so that the QoS data frame is dropped
2296 // when the Ack timeout occurs
2297 m_apMac->SetAttribute("FrameRetryLimit", UintegerValue(1));
2298 auto rsm =
2299 DynamicCast<PowerSaveTestRateManager>(m_apMac->GetWifiRemoteStationManager(linkId));
2300 NS_TEST_ASSERT_MSG_NE(rsm, nullptr, "Unexpected type of remote station manager");
2301 rsm->m_drop = true;
2302
2303 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2304 // reset error list
2305 m_nonApMldErrorModel->SetList({});
2306 // switch affiliated non-AP STA on link 0 to powersave mode
2307 m_staMacs[0]->SetPowerSaveMode({true, 0});
2308 });
2309 });
2310
2311 m_events.emplace_back(
2313 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2314 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2315 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2316 "Unexpected transmitter address for Data Null frame");
2317 // check that the Power Management flag is set to 1
2318 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsPowerManagement(),
2319 true,
2320 "Expected the Power Management flag to be set");
2321 // when AckTimeout occurred, the QoS data frame was dropped and a BlockAckReq
2322 // was enqueued at the AP MLD
2324 m_apMac->GetTxopQueue(AC_BE)->GetNPackets(),
2325 1,
2326 "Expected only one frame (BlockAckReq) to be queued at the AP MLD");
2327 auto mpdu = m_apMac->GetTxopQueue(AC_BE)->Peek();
2328 NS_TEST_ASSERT_MSG_NE(mpdu, nullptr, "Expected a frame to be queued at the AP MLD");
2329 NS_TEST_EXPECT_MSG_EQ(std::string(mpdu->GetHeader().GetTypeString()),
2330 "CTL_BACKREQ",
2331 "Expected a BlockAckReq to be queued at the non-AP MLD");
2332 });
2333
2334 m_events.emplace_back(
2336 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2337 // check that all non-AP STAs affiliated with the AP MLD are in powersave mode and
2338 // in the sleep state after the reception of the Ack
2339 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
2340 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2341 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2342 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2343 });
2344 });
2345
2346 /**
2347 * (23) When the Beacon frame is sent on link 1, another QoS data with TID 0 for the non-AP MLD
2348 * is queued at the AP MLD, which is now buffered because both STAs affiliated with the non-AP
2349 * MLD are in powersave mode. The next Beacon frame, on link 0, indicates that frames are
2350 * buffered for the non-AP MLD, which sends a two PS-Poll frames: the AP sends the BlockAckReq
2351 * (ack'ed by a BlockAck frame) in response to the first PS-Poll and the QoS Data frame (ack'ed
2352 * by a Normal Ack) in response to the second PS-Poll frame.
2353 */
2354
2355 m_events.emplace_back(
2357 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2358 NS_TEST_EXPECT_MSG_EQ(+linkId, 1, "Expected a Beacon frame on link 1");
2359
2360 checkTim(*psdu->begin(),
2361 DTIM,
2362 MCAST_NOT_PENDING,
2363 /* AID bits */ {{1, false}, {2, false}, {3, false}});
2364
2365 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2366 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2367 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2368
2369 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2370 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2371 // affiliated non-AP STA on link 0 is put to sleep again
2372 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2373 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2374
2375 // queue another unicast frames with TID 0 at the AP MLD for the non-AP MLD
2376 m_apMac->GetDevice()->GetNode()->AddApplication(
2377 GetApplication(nonApMldAddr, 1, 1000, Time{0}));
2378 });
2379 });
2380
2381 m_events.emplace_back(
2383 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2384 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a Beacon frame on link 0");
2385 const auto aidNonApMld = m_staMacs[0]->GetAssociationId();
2386 const auto aidNonApSta = m_staMacs[1]->GetAssociationId();
2387
2388 checkTim(*psdu->begin(),
2389 NO_DTIM,
2390 MCAST_NOT_PENDING,
2391 /* AID bits */ {{1, false}, {aidNonApMld, true}, {aidNonApSta, false}});
2392
2393 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2394 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2395 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2396
2397 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
2398 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, AWAKE);
2399 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2400 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2401 });
2402 });
2403
2404 m_events.emplace_back(
2406 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2407 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a PS-Poll frame on link 0");
2408 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2409 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2410 "Unexpected transmitter address for PS Poll frame");
2411 });
2412
2413 m_events.emplace_back(
2415 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2416 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a BlockAckReq frame on link 0");
2417 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
2418 true,
2419 "Expected the More Data flag to be set");
2420 });
2421
2422 m_events.emplace_back(
2424 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2425 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a BlockAck frame on link 0");
2426 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2427 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2428 "Unexpected transmitter address for PS Poll frame");
2429 });
2430
2431 m_events.emplace_back(
2433 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2434 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Expected a PS-Poll frame on link 0");
2435 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2436 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2437 "Unexpected transmitter address for PS Poll frame");
2438 });
2439
2440 m_events.emplace_back(
2442 [=, this](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2443 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).GetAddr1(),
2444 m_staMacs[0]->GetFrameExchangeManager(0)->GetAddress(),
2445 "Unexpected receiver address for QoS Data frame");
2446 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(0).IsMoreData(),
2447 false,
2448 "Expected the More Data flag not to be set");
2449 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=, this]() {
2450 NS_TEST_EXPECT_MSG_EQ(m_rxPkts[1],
2451 11,
2452 "Non-AP MLD expected to receive another unicast frame");
2453 });
2454 });
2455
2456 m_events.emplace_back(
2458 [=](Ptr<const WifiPsdu> psdu, const Time& txDuration, uint8_t linkId) {
2459 // all non-AP STAs are in the sleep state after Normal Ack
2460 Simulator::Schedule(txDuration + MAX_PROPAGATION_DELAY, [=]() {
2461 checkSleep(NON_AP_MLD, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2462 checkSleep(NON_AP_MLD, 1, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2463 checkSleep(NON_AP_STA, 0, WifiPowerManagementMode::WIFI_PM_POWERSAVE, SLEEP);
2464 });
2465 });
2466}
2467
2468/**
2469 * @ingroup wifi-test
2470 * @ingroup tests
2471 *
2472 * @brief Test transmission of broadcast and unicast frames with STAs in Power Save mode
2473 *
2474 * This test considers an AP MLD having two links and two devices: a device under test (DUT), which
2475 * is a 2-link non-AP MLD, and a single-link non-AP STA. The DUT can have EMLSR mode enabled or
2476 * disabled on both links and static setup helper can be used or not. Both STAs affiliated with the
2477 * DUT are switched to powersave mode after completing ML setup or enabling EMLSR mode.
2478 *
2479 * It is verified that:
2480 *
2481 * - upon completion of association (EML OMN) procedure, both STAs affiliated with the DUT are in PS
2482 * mode and their PHYs are in sleep state (except, in case static setup helper is not used, the
2483 * PHY of the STA operating on the link that is not used for association, which is put to sleep
2484 * after receiving the first Beacon frame)
2485 * - while the AP MLD sends a PPDU to the other non-AP STA, a packet is enqueued at the DUT; the
2486 * PHYs of both STAs affiliated with the DUT are awaken from sleep and the state of the PHY
2487 * operating on the same link as the other non-AP STA is CCA_BUSY
2488 * - when a non-null PSM timeout is configured, the PHY is kept in awake state for such interval
2489 * after releasing (and not requesting again) the channel and after receiving a Beacon frame that
2490 * does not indicate that the AP has pending frames for the DUT
2491 * - if channel access is requested (to transmit a frame) during a PSM timeout, the latter is
2492 * cancelled
2493 * - when a non-null Listen Advance is configured, the STA wakes up such interval prior to the TBTT
2494 *
2495 \verbatim
2496
2497 1 frame queued
2498 at DUT
2499 │ channel access
2500 ┌───────────┐ granted, no TX, 1 frame queued
2501 ┌──────┐ │QoS Data to│ no channel request at DUT
2502 [link 0] │Beacon│ │ other STA │ │ │
2503 ─────────┴──────┴────┴─────▼─────┴┬───┬─────────────────────────────────▼───────────────────────
2504 │CCA │ACK│ │ │
2505 non-AP STA |---sleep--│BUSY └───┘ │------sleep-------│ │---------
2506 on link 0 │ │
2507 non-AP STA -----sleep------│ │----│ │ │-
2508 on link 1 │ │
2509 │ PSM Listen PSM PSM
2510 │ ┌───┐timeout Advance┌──────┐timeout ┌───┐timeout
2511 [link 1] │ │ACK│------│ │------│Beacon│---X │ACK│------│
2512 ───────────────────────────▼─┬────────┬┴───┴──────────────────┴──────┴──▼┬────────┬┴───┴────────
2513 │QoS Data│ │QoS Data│
2514 │from DUT│ │from DUT│
2515 └────────┘ └────────┘
2516
2517 \endverbatim
2518 */
2520{
2521 public:
2522 /**
2523 * Constructor.
2524 *
2525 * @param enableEmlsr whether to enable EMLSR on the DUT
2526 * @param staticSetup whether static setup helper is used to configure association
2527 */
2528 WifiPsModeAttributesTest(bool enableEmlsr, bool staticSetup);
2529
2530 /**
2531 * Callback invoked when PHY receives a PSDU to transmit
2532 *
2533 * @param mac the MAC transmitting the PSDUs
2534 * @param phyId the ID of the PHY transmitting the PSDUs
2535 * @param psduMap the PSDU map
2536 * @param txVector the TX vector
2537 * @param txPower the tx power
2538 */
2539 void Transmit(Ptr<WifiMac> mac,
2540 uint8_t phyId,
2541 WifiConstPsduMap psduMap,
2542 WifiTxVector txVector,
2543 Watt_u txPower);
2544
2545 protected:
2546 /**
2547 * @param dir the traffic direction (downlink/uplink)
2548 * @param staId the index of the non-AP MLD generating/receiving packets
2549 * @param count the number of packets to generate
2550 * @param pktSize the size of the packets to generate
2551 * @param priority user priority for generated packets
2552 * @return an application generating the given number packets of the given size from/to the
2553 * AP MLD to/from the given non-AP MLD
2554 */
2556 std::size_t staId,
2557 std::size_t count,
2558 std::size_t pktSize,
2559 uint8_t priority = 0) const;
2560
2561 /// Actions and checks to perform upon the transmission of each frame
2562 struct Events
2563 {
2564 /**
2565 * Constructor.
2566 *
2567 * @param type the frame MAC header type
2568 * @param f function to perform actions and checks
2569 */
2571 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&, linkId_t)>&& f = {})
2572 : hdrType(type),
2573 func(f)
2574 {
2575 }
2576
2577 WifiMacType hdrType; ///< MAC header type of frame being transmitted
2578 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&, linkId_t)>
2579 func; ///< function to perform actions and checks
2580 };
2581
2582 /// Insert elements in the list of expected events (transmitted frames)
2583 void InsertEvents();
2584
2585 void DoSetup() override;
2586 void DoRun() override;
2587
2588 private:
2589 /// number of links for ML devices
2590 static constexpr std::size_t N_LINKS = 2;
2591 /// frequency channels for the two links
2592 const std::array<std::string, N_LINKS> m_channels{"{42, 80, BAND_5GHZ, 0}",
2593 "{23, 80, BAND_6GHZ, 0}"};
2594 /// channel used to initialize the PHY of the DUT operating on the link that shall not be
2595 /// used for ML setup
2596 const std::string m_otherChannel{"{100, 20, BAND_5GHZ, 0}"};
2597 /// jitter for the initial Beacon frame sent on the link used by the DUT for association
2598 static constexpr double DUT_BEACON_JITTER = 0.6;
2599 /// jitter for the initial Beacon frame sent on the link used by the other STA for association
2600 static constexpr double STA_BEACON_JITTER = 0.2;
2601 /// the time a STA listens for a Beacon is the percentage of the Beacon interval given by the
2602 /// sum of the beacon jitter and this surplus
2603 static constexpr double WAIT_BEACON_SURPLUS = 0.1;
2604
2605 const Time m_psmTimeout{MicroSeconds(100)}; ///< the PSM timeout
2606 const Time m_listenAdvance{MicroSeconds(50)}; ///< the value for the ListenAdvance attribute
2607 const Time m_switchDelay{MicroSeconds(64)}; ///< channel switch, transition and padding delay
2608 bool m_enableEmlsr; ///< whether to enable EMLSR on the DUT
2609 bool m_staticSetup; ///< whether static setup helper is used to configure association
2610 static constexpr std::size_t DUT_INDEX = 0; ///< DUT index
2611 static constexpr std::size_t STA_INDEX = 1; ///< index of the other non-AP STA
2612 Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
2613 std::array<Ptr<StaWifiMac>, 2> m_staMacs; ///< wifi MACs of the STAs
2614 std::vector<PacketSocketAddress> m_dlSockets; ///< packet socket addresses for DL traffic
2615 std::vector<PacketSocketAddress> m_ulSockets; ///< packet socket addresses for UL traffic
2616 std::list<Events> m_events; ///< list of events for a test run
2617 bool m_checkTxPsdus{false}; ///< whether to check transmitted PSDUs against
2618 ///< the inserted events
2619 Time m_duration{Seconds(0.5)}; ///< simulation duration
2620};
2621
2623 : TestCase("Test that medium is sensed busy after waking up from sleep mode (enableEmlsr=" +
2624 std::to_string(+enableEmlsr) + ", staticSetup=" + std::to_string(+staticSetup) +
2625 ")"),
2626 m_enableEmlsr(enableEmlsr),
2627 m_staticSetup(staticSetup)
2628{
2629}
2630
2633 std::size_t staId,
2634 std::size_t count,
2635 std::size_t pktSize,
2636 uint8_t priority) const
2637{
2638 auto client = CreateObject<PacketSocketClient>();
2639 client->SetAttribute("PacketSize", UintegerValue(pktSize));
2640 client->SetAttribute("MaxPackets", UintegerValue(count));
2641 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2642 client->SetAttribute("Priority", UintegerValue(priority));
2643 client->SetRemote(dir == WifiDirection::DOWNLINK ? m_dlSockets.at(staId)
2644 : m_ulSockets.at(staId));
2645 client->SetStartTime(Time{0});
2646 client->SetStopTime(m_duration - Simulator::Now());
2647
2648 return client;
2649}
2650
2651void
2653{
2656 int64_t streamNumber = 100;
2657 SsidValue ssidValue(Ssid("power-save-ssid"));
2658
2659 NodeContainer wifiApNode(1);
2660 NodeContainer wifiStaNodes(2);
2661
2662 Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(m_switchDelay));
2663 Config::SetDefault("ns3::EmlsrManager::EmlsrPaddingDelay", TimeValue(m_switchDelay));
2664 Config::SetDefault("ns3::EmlsrManager::EmlsrTransitionDelay", TimeValue(m_switchDelay));
2665
2666 WifiHelper wifi;
2667 wifi.SetStandard(WIFI_STANDARD_80211be);
2668 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager");
2669 wifi.ConfigEhtOptions("EmlsrActivated", BooleanValue(m_enableEmlsr));
2670
2671 // create a spectrum channel for each link
2672 std::array<Ptr<MultiModelSpectrumChannel>, N_LINKS> spectrumChannels;
2673 for (std::size_t id = 0; id < spectrumChannels.size(); ++id)
2674 {
2675 spectrumChannels[id] = CreateObject<MultiModelSpectrumChannel>();
2676 }
2677
2678 // AP MLD
2680 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
2681
2682 for (std::size_t id = 0; id < m_channels.size(); ++id)
2683 {
2684 phy.Set(id, "ChannelSettings", StringValue(m_channels[id]));
2685 const auto phyBand = WifiChannelConfig::FromString(m_channels[id]).front().band;
2686 const auto freqRange = GetFrequencyRange(phyBand);
2687 phy.AddChannel(spectrumChannels[id], freqRange);
2688 // do not create multiple spectrum interfaces for STR devices
2689 phy.AddPhyToFreqRangeMapping(id, freqRange);
2690 }
2691
2692 WifiMacHelper mac;
2693 mac.SetType("ns3::ApWifiMac",
2694 "BeaconInterval",
2696 "Ssid",
2697 ssidValue);
2698
2699 auto apDev = wifi.Install(phy, mac, wifiApNode);
2700
2701 // other non-AP STA
2702 wifi.ConfigEhtOptions("EmlsrActivated", BooleanValue(false));
2703
2704 SpectrumWifiPhyHelper staPhy;
2706 staPhy.Set("ChannelSettings", StringValue(m_channels[0]));
2707 staPhy.SetChannel(spectrumChannels[0]);
2708
2709 mac.SetType("ns3::StaWifiMac",
2710 "Ssid",
2711 ssidValue,
2712 "WaitBeaconTimeout",
2714
2715 auto staDevs = wifi.Install(staPhy, mac, wifiStaNodes.Get(STA_INDEX));
2716
2717 // DUT
2718 wifi.ConfigEhtOptions("EmlsrActivated", BooleanValue(m_enableEmlsr));
2719
2720 if (!m_staticSetup)
2721 {
2722 // channel on link 0 does not match the AP's channel, hence ML setup is guaranteed to occur
2723 // on link 1, thus preventing potential collisions with the other non-AP STA, which only
2724 // operates on link 0
2725 phy.Set(0, "ChannelSettings", StringValue(m_otherChannel));
2726 }
2727
2728 if (m_enableEmlsr)
2729 {
2730 phy.ResetPhyToFreqRangeMapping();
2731 mac.SetType("ns3::StaWifiMac",
2732 "Ssid",
2733 ssidValue,
2734 "WaitBeaconTimeout",
2736 mac.SetEmlsrManager("ns3::AdvancedEmlsrManager",
2737 "EmlsrLinkSet",
2738 StringValue("0,1"),
2739 "MainPhyId",
2740 UintegerValue(1));
2741 }
2742
2743 // set power save mode on both STAs of the DUT
2744 mac.SetPowerSaveManager("ns3::DefaultPowerSaveManager",
2745 "PowerSaveMode",
2746 StringValue("0 true, 1 true"));
2747
2748 staDevs.Add(wifi.Install(phy, mac, wifiStaNodes.Get(DUT_INDEX)));
2749
2750 // Assign fixed streams to random variables in use
2751 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(staDevs, apDev), streamNumber);
2752
2753 auto positionAlloc = CreateObject<ListPositionAllocator>();
2754 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2755 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2756 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2757 MobilityHelper mobility;
2758 mobility.SetPositionAllocator(positionAlloc);
2759 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2760 mobility.Install(wifiApNode);
2761 mobility.Install(wifiStaNodes);
2762
2765 DynamicCast<WifiNetDevice>(wifiStaNodes.Get(DUT_INDEX)->GetDevice(0))->GetMac());
2767 DynamicCast<WifiNetDevice>(wifiStaNodes.Get(STA_INDEX)->GetDevice(0))->GetMac());
2768
2769 // define the jitter for the initial Beacon frames on the two links, so that Beacon frames are
2770 // sent on the two links at different moments and the other non-AP STA starts association before
2771 // the DUT
2772 auto beaconJitter = CreateObject<DeterministicRandomVariable>();
2773 beaconJitter->SetValueArray({STA_BEACON_JITTER, DUT_BEACON_JITTER});
2774 m_apMac->SetAttribute("BeaconJitter", PointerValue(beaconJitter));
2775
2776 if (m_staticSetup)
2777 {
2778 /* static setup of association and EMLSR mode (if needed) */
2780 if (m_enableEmlsr)
2781 {
2782 WifiStaticSetupHelper::SetStaticEmlsr(m_apMac->GetDevice(), staDevs);
2783 }
2784 }
2785
2786 // Trace PSDUs passed to the PHY on all devices
2787 for (const auto& mac : std::list<Ptr<WifiMac>>{m_apMac, m_staMacs[0], m_staMacs[1]})
2788 {
2789 for (uint8_t phyId = 0; phyId < mac->GetDevice()->GetNPhys(); ++phyId)
2790 {
2791 mac->GetDevice()->GetPhy(phyId)->TraceConnectWithoutContext(
2792 "PhyTxPsduBegin",
2793 MakeCallback(&WifiPsModeAttributesTest::Transmit, this).Bind(mac, phyId));
2794 }
2795 }
2796
2797 // install packet socket on all nodes
2798 PacketSocketHelper packetSocket;
2799 packetSocket.Install(wifiApNode);
2800 packetSocket.Install(wifiStaNodes);
2801
2802 // install a packet socket server on all nodes
2803 for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); ++nodeIt)
2804 {
2805 PacketSocketAddress srvAddr;
2806 auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
2807 NS_TEST_ASSERT_MSG_NE(device, nullptr, "Expected a WifiNetDevice");
2808 srvAddr.SetSingleDevice(device->GetIfIndex());
2809 srvAddr.SetProtocol(1);
2810
2811 auto server = CreateObject<PacketSocketServer>();
2812 server->SetLocal(srvAddr);
2813 (*nodeIt)->AddApplication(server);
2814 server->SetStartTime(Time{0}); // now
2815 server->SetStopTime(m_duration);
2816 }
2817
2818 // set DL and UL packet sockets
2819 for (const auto& staMac : m_staMacs)
2820 {
2821 m_dlSockets.emplace_back();
2822 m_dlSockets.back().SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
2823 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
2824 m_dlSockets.back().SetProtocol(1);
2825
2826 m_ulSockets.emplace_back();
2827 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
2828 m_ulSockets.back().SetPhysicalAddress(m_apMac->GetDevice()->GetAddress());
2829 m_ulSockets.back().SetProtocol(1);
2830 }
2831}
2832
2833void
2835 uint8_t phyId,
2836 WifiConstPsduMap psduMap,
2837 WifiTxVector txVector,
2838 Watt_u txPower)
2839{
2840 const auto linkId = mac->GetLinkForPhy(phyId);
2841 NS_TEST_ASSERT_MSG_EQ(linkId.has_value(), true, "No link found for PHY ID " << +phyId);
2842
2843 for (const auto& [aid, psdu] : psduMap)
2844 {
2845 std::stringstream ss;
2846 ss << std::setprecision(10) << " Link ID " << +linkId.value() << " Phy ID " << +phyId
2847 << " #MPDUs " << psdu->GetNMpdus();
2848 for (auto it = psdu->begin(); it != psdu->end(); ++it)
2849 {
2850 ss << "\n" << **it;
2851 }
2852 NS_LOG_INFO(ss.str());
2853 }
2854 NS_LOG_INFO("TXVECTOR = " << txVector << "\n");
2855
2856 const auto psdu = psduMap.cbegin()->second;
2857 const auto& hdr = psdu->GetHeader(0);
2858
2859 if (!m_checkTxPsdus)
2860 {
2861 return;
2862 }
2863
2864 if (!m_events.empty())
2865 {
2866 // check that the expected frame is being transmitted
2868 hdr.GetTypeString(),
2869 "Unexpected MAC header type for frame transmitted at time "
2870 << Simulator::Now().As(Time::US));
2871 // perform actions/checks, if any
2872 if (m_events.front().func)
2873 {
2874 m_events.front().func(psdu, txVector, linkId.value());
2875 }
2876
2877 m_events.pop_front();
2878 }
2879}
2880
2881void
2883{
2884 m_checkTxPsdus = true;
2885
2886 // lambda to statically establish a BlockAck agreement and generate a packet for the given STA
2887 auto generatePacket = [this](WifiDirection dir, std::size_t staId) {
2888 Ptr<WifiMac> mac;
2890 {
2891 mac = m_apMac;
2893 m_staMacs[staId]->GetDevice(),
2894 0);
2895 }
2896 else
2897 {
2898 mac = m_staMacs[staId];
2900 m_apMac->GetDevice(),
2901 0);
2902 }
2903
2904 mac->GetDevice()->GetNode()->AddApplication(GetApplication(dir, staId, 1, 1000));
2905 };
2906
2907 // lambda to check PM mode and PHY state of a STA affiliated with the DUT
2908 auto checkPmModeAndPhyState =
2909 [this](linkId_t linkId, WifiPowerManagementMode pmMode, WifiPhyState state) {
2910 const auto now = Simulator::Now();
2911 // check PM mode
2912 NS_TEST_EXPECT_MSG_EQ(m_staMacs[DUT_INDEX]->GetPmMode(linkId),
2913 pmMode,
2914 "Unexpected PM mode for STA affiliated with the DUT and "
2915 "operating on link "
2916 << +linkId << "(non-AP MLD side) at time " << now);
2917 NS_TEST_EXPECT_MSG_EQ(m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(
2918 m_staMacs[DUT_INDEX]->GetAddress()),
2920 "Unexpected PM mode for STA affiliated with the DUT and "
2921 "operating on link "
2922 << +linkId << "(AP MLD side) at time " << now);
2923 // check PHY state
2924 NS_TEST_EXPECT_MSG_EQ(m_staMacs[DUT_INDEX]->GetWifiPhy(linkId)->GetState()->GetState(),
2925 state,
2926 "Unexpected state of DUT PHY on link " << +linkId << " at time "
2927 << now);
2928 };
2929
2930 if (!m_staticSetup)
2931 {
2932 if (m_enableEmlsr)
2933 {
2934 // EML OMN request
2935 m_events.emplace_back(WIFI_MAC_MGT_ACTION);
2936 m_events.emplace_back(WIFI_MAC_CTL_ACK);
2937 m_events.emplace_back(WIFI_MAC_CTL_END);
2938 // EML OMN response
2939 m_events.emplace_back(WIFI_MAC_CTL_TRIGGER);
2940 m_events.emplace_back(WIFI_MAC_CTL_CTS);
2941 m_events.emplace_back(WIFI_MAC_MGT_ACTION);
2942 m_events.emplace_back(WIFI_MAC_CTL_ACK);
2943 m_events.emplace_back(
2945 [this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
2946 // EML OMN exchange has switched all STAs affiliated with the EMLSR client to
2947 // active mode, hence we need to switch them to power save mode (one at a time
2948 // to have full control on the sequence of transmitted frames)
2949 m_staMacs[DUT_INDEX]->GetPowerSaveManager()->SetPowerSaveMode({{0, true}});
2950 });
2951 // Data null frame to switch STA on link 0 (auxiliary link) to power save mode
2952 m_events.emplace_back(WIFI_MAC_CTL_RTS);
2953 m_events.emplace_back(WIFI_MAC_CTL_CTS);
2954 m_events.emplace_back(WIFI_MAC_DATA_NULL);
2955 m_events.emplace_back(
2957 [this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
2958 // by default, aux PHYs switch link, thus the next Data null frame will also
2959 // be sent on a link on which the aux PHY is operating
2960 m_staMacs[DUT_INDEX]->GetPowerSaveManager()->SetPowerSaveMode({{1, true}});
2961 });
2962 m_events.emplace_back(WIFI_MAC_CTL_RTS);
2963 m_events.emplace_back(WIFI_MAC_CTL_CTS);
2964 }
2965
2966 m_events.emplace_back(WIFI_MAC_DATA_NULL);
2967 m_events.emplace_back(WIFI_MAC_CTL_ACK);
2968 }
2969
2970 // if static setup helper is not used, the STA affiliated with the DUT and operating on the link
2971 // that is not used for association (link 0) has not yet received a Beacon frame, hence it has
2972 // not been put to sleep mode. Therefore, wait until a Beacon frame is received on link 0 before
2973 // generating a packet addressed to the other non-AP STA
2974
2975 m_events.emplace_back(
2977 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
2978 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Beacon frame sent on unexpected link");
2979 generatePacket(WifiDirection::DOWNLINK, STA_INDEX);
2980 });
2981
2982 // data frame addressed to the other non-AP STA (on link 0)
2983 m_events.emplace_back(
2985 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
2986 NS_TEST_EXPECT_MSG_EQ(+linkId, 0, "Downlink QoS data frame sent on unexpected link");
2988 psdu->GetAddr1(),
2989 m_staMacs[STA_INDEX]->GetFrameExchangeManager(SINGLE_LINK_OP_ID)->GetAddress(),
2990 "Downlink QoS data frame not addressed to the other non-AP STA");
2991 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
2992 m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
2993 "Downlink QoS data frame not transmitted by the AP MLD");
2994
2995 // both STAs affiliated with the DUT must be in power save mode and sleep state
2996 for (const auto id : m_staMacs[DUT_INDEX]->GetSetupLinkIds())
2997 {
2998 checkPmModeAndPhyState(id,
3001 }
3002
3003 // schedule the generation of an uplink packet from the DUT when PHY header ends
3005 [=] { generatePacket(WifiDirection::UPLINK, DUT_INDEX); });
3006 });
3007
3008 // first data frame transmitted by the DUT (on link 1)
3009 m_events.emplace_back(
3011 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3012 NS_TEST_EXPECT_MSG_EQ(+linkId,
3013 1,
3014 "First uplink QoS data frame sent on unexpected link");
3015 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
3016 m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
3017 "First uplink QoS data frame not addressed to the AP MLD");
3019 psdu->GetAddr2(),
3020 m_staMacs[DUT_INDEX]->GetFrameExchangeManager(linkId)->GetAddress(),
3021 "First uplink QoS data frame not transmitted by the DUT");
3022
3023 // both STAs affiliated with the DUT must be still in power save mode and both PHYs of
3024 // the DUT must be now in awake state: the one operating on link 0 must be in CCA_BUSY
3025 // state, the one operating on link 1 must be in idle state
3026 for (const auto id : m_staMacs[DUT_INDEX]->GetSetupLinkIds())
3027 {
3028 checkPmModeAndPhyState(id,
3031 }
3032
3033 // Apply the PsmTimeout and ListenAdvance values
3034 auto psManager = m_staMacs[DUT_INDEX]->GetPowerSaveManager();
3035 psManager->SetAttribute("PsmTimeout", TimeValue(m_psmTimeout));
3036 psManager->SetAttribute("ListenAdvance", TimeValue(m_listenAdvance));
3037 });
3038
3039 m_events.emplace_back(
3041 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3042 NS_TEST_EXPECT_MSG_EQ(+linkId,
3043 0,
3044 "Expected Ack on link 0 to be transmitted before link 1");
3045
3046 // the STA operating on link 0 goes to sleep when channel access is no longer requested
3047 // because the DUT has no frames to transmit (it is checked that it is in sleep mode
3048 // when the next beacon on the other link is transmitted -- see below). Here, we
3049 // schedule checks to verify that this STA is in sleep state a ListenAdvance interval
3050 // prior to the next TBTT on this link
3051 const auto timeUntilNextTbtt =
3052 m_staMacs[DUT_INDEX]->GetPowerSaveManager()->GetTimeUntilNextTbtt(linkId);
3053 NS_TEST_ASSERT_MSG_EQ(timeUntilNextTbtt.has_value(),
3054 true,
3055 "Expected next TBTT on link 0 to be known");
3056 Simulator::Schedule(*timeUntilNextTbtt - m_listenAdvance - TimeStep(1), [=] {
3057 checkPmModeAndPhyState(linkId,
3060 });
3061 Simulator::Schedule(*timeUntilNextTbtt - m_listenAdvance + TimeStep(1), [=] {
3062 checkPmModeAndPhyState(linkId,
3065 });
3066 });
3067
3068 m_events.emplace_back(
3070 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3071 NS_TEST_EXPECT_MSG_EQ(+linkId,
3072 1,
3073 "Expected Ack on link 1 to be transmitted after link 0");
3074 const auto band = m_apMac->GetWifiPhy(linkId)->GetPhyBand();
3075 const auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, band);
3076
3077 // the STA operating on link 1 goes to sleep after the PSM timeout
3078 Simulator::Schedule(txDuration + m_psmTimeout - TimeStep(1), [=] {
3079 checkPmModeAndPhyState(linkId,
3082 });
3083 Simulator::Schedule(txDuration + m_psmTimeout + TimeStep(1), [=] {
3084 checkPmModeAndPhyState(linkId,
3087 });
3088 // the STA operating on link 1 stays in sleep state until a ListenAdvance interval prior
3089 // to the next TBTT
3090 const auto timeUntilNextTbtt =
3091 m_staMacs[DUT_INDEX]->GetPowerSaveManager()->GetTimeUntilNextTbtt(linkId);
3092 NS_TEST_ASSERT_MSG_EQ(timeUntilNextTbtt.has_value(),
3093 true,
3094 "Expected next TBTT on link 1 to be known");
3095 Simulator::Schedule(*timeUntilNextTbtt - m_listenAdvance - TimeStep(1), [=] {
3096 checkPmModeAndPhyState(linkId,
3099 });
3100 Simulator::Schedule(*timeUntilNextTbtt - m_listenAdvance + TimeStep(1), [=] {
3101 checkPmModeAndPhyState(linkId,
3104 });
3105 });
3106
3107 m_events.emplace_back(
3109 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3110 NS_TEST_EXPECT_MSG_EQ(+linkId, 1, "Beacon frame sent on unexpected link");
3111
3112 // the STA operating on link 1 is in awake state
3113 checkPmModeAndPhyState(linkId,
3116 // the STA operating on link 0 is in sleep state
3117 checkPmModeAndPhyState(0,
3120
3121 const auto band = m_apMac->GetWifiPhy(linkId)->GetPhyBand();
3122 const auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, band);
3123
3124 // in the middle of the PSM timeout interval following the Beacon frame, generate a
3125 // packet at the DUT, to check that the PSM timeout is cancelled
3126 auto delay = txDuration + m_psmTimeout / 2;
3127 Simulator::Schedule(delay, [=] {
3128 checkPmModeAndPhyState(linkId,
3131 generatePacket(WifiDirection::UPLINK, DUT_INDEX);
3132 });
3133 // check that both STAs are awake after enqueuing the packet
3134 delay += TimeStep(1);
3135 Simulator::Schedule(delay, [=, this] {
3136 for (const auto id : m_staMacs[DUT_INDEX]->GetSetupLinkIds())
3137 {
3138 NS_TEST_EXPECT_MSG_EQ(m_staMacs[DUT_INDEX]->GetWifiPhy(id)->IsStateSleep(),
3139 false,
3140 "Unexpected state for DUT STA on link " << +id);
3141 }
3142 });
3143 // check that STA on link 1 is still awake after the PSM timeout, i.e., the
3144 // PSM timeout has been cancelled
3145 delay += m_psmTimeout / 2;
3146 Simulator::Schedule(delay, [=, this] {
3147 NS_TEST_EXPECT_MSG_EQ(m_staMacs[DUT_INDEX]->GetWifiPhy(linkId)->IsStateSleep(),
3148 false,
3149 "Unexpected state for DUT STA on link " << +linkId);
3150 });
3151 });
3152
3153 // second data frame transmitted by the DUT (on link 1, because the STA on link 0 was awaken
3154 // from sleep state, hence it has to wait for AIFS plus backoff starting from the time it woke
3155 // up)
3156 m_events.emplace_back(
3158 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3159 NS_TEST_EXPECT_MSG_EQ(+linkId,
3160 1,
3161 "Second uplink QoS data frame sent on unexpected link");
3162 NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
3163 m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
3164 "Second uplink QoS data frame not addressed to the AP MLD");
3166 psdu->GetAddr2(),
3167 m_staMacs[DUT_INDEX]->GetFrameExchangeManager(linkId)->GetAddress(),
3168 "Second uplink QoS data frame not transmitted by the DUT");
3169 });
3170
3171 m_events.emplace_back(
3173 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, linkId_t linkId) {
3174 NS_TEST_EXPECT_MSG_EQ(+linkId,
3175 1,
3176 "Expected Ack on link 1 after second uplink QoS data frame");
3177 const auto band = m_apMac->GetWifiPhy(linkId)->GetPhyBand();
3178 const auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, band);
3179
3180 // the STA operating on link 1 goes to sleep after the PSM timeout
3181 Simulator::Schedule(txDuration + m_psmTimeout - TimeStep(1), [=] {
3182 checkPmModeAndPhyState(linkId,
3185 });
3186 Simulator::Schedule(txDuration + m_psmTimeout + TimeStep(1), [=] {
3187 checkPmModeAndPhyState(linkId,
3190 });
3191 });
3192}
3193
3194void
3196{
3197 if (m_staticSetup)
3198 {
3199 InsertEvents();
3200 }
3201 else
3202 {
3203 // if static setup is not used, wait until the DUT receives the Association Response and
3204 // start inserting events right after the Ack is sent
3206 Simulator::Schedule(m_staMacs[DUT_INDEX]->GetWifiPhy()->GetSifs() + TimeStep(1),
3208 this);
3209 });
3210 m_staMacs[DUT_INDEX]->TraceConnectWithoutContext("Assoc", cb);
3211 }
3212
3215
3216 NS_TEST_EXPECT_MSG_EQ(m_events.empty(), true, "Not all events took place");
3217
3219}
3220
3221/**
3222 * @ingroup wifi-test
3223 * @ingroup tests
3224 *
3225 * @brief Power Save Test Suite
3226 */
3228{
3229 public:
3231};
3232
3234 : TestSuite("wifi-power-save", Type::UNIT)
3235{
3237
3238 for (const auto standard :
3240 {
3242 }
3243
3244 for (const auto enableEmlsr : {false, true})
3245 {
3246 for (const auto staticSetup : {false, true})
3247 {
3248 AddTestCase(new WifiPsModeAttributesTest(enableEmlsr, staticSetup),
3250 }
3251 }
3252}
3253
3254static PowerSaveTestSuite g_powerSaveTestSuite; ///< the test suite
Test rate manager that differs from MinstrelHT in that it allows to arbitrarily drop frames by overri...
static TypeId GetTypeId()
Get the type ID.
std::list< Ptr< WifiMpdu > > DoGetMpdusToDropOnTxFailure(WifiRemoteStation *station, Ptr< WifiPsdu > psdu) override
Find the MPDUs to drop (possibly based on their frame retry count) in the given PSDU,...
bool m_drop
whether to drop the given MPDUs
Power Save Test Suite.
Test TIM Information element serialization and deserialization.
TimInformationElementTest()
Constructor.
void SetTim(Tim &tim, uint8_t dtimCount, uint8_t dtimPeriod, bool multicastPending, const std::list< uint16_t > &aidValues)
Reset the passed TIM to have the provided parameters.
void DoRun() override
Implementation to actually run this TestCase.
void CheckSerializationAgainstBuffer(Tim &tim, const std::vector< uint8_t > &bufferContents)
Test that the Bitmap Control and the Partial Virtual Bitmap fields of the provided TIM match the pass...
void CheckAidSet(const Tim &tim, uint16_t aid, const std::set< uint16_t > &expectedSet)
Test that the GetAidSet() method return the expected set of AID values.
Test transmission of broadcast and unicast frames with STAs in Power Save mode.
std::vector< double > m_jitter
jitter for the initial Beacon frames on the links
Ptr< ListErrorModel > m_apErrorModel
error model to install on the AP MLD
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Time m_duration
simulation duration
WifiPowerSaveModeTest(WifiStandard standard)
Constructor.
Ptr< ApWifiMac > m_apMac
AP wifi MAC.
void NotifyMpduEnqueued(Ptr< const WifiMpdu > mpdu)
Notify that the given MPDU was enqueued at the AP.
Ptr< PacketSocketClient > GetApplication(const PacketSocketAddress &sockAddr, std::size_t count, std::size_t pktSize, Time delay=Time{0}, uint8_t priority=0) const
std::vector< Ptr< StaWifiMac > > m_staMacs
STA wifi MACs.
std::array< std::size_t, 3 > m_rxPkts
number of packets received at application layer by each node (index is node ID)
void SetEvents()
Set the list of events to expect in this test run.
std::size_t m_processedEvents
number of processed events
void NotifyStateChange(uint32_t nodeId, uint8_t phyId, Time stateStart, Time stateDuration, WifiPhyState state)
Callback invoked when the PHY state helper reports a change in PHY state.
Ptr< ListErrorModel > m_nonApMldErrorModel
error model to install on the non-AP MLD
std::list< Events > m_events
list of events for a test run
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u txPower)
Callback invoked when PHY receives a PSDU to transmit.
WifiStandard m_standard
the wifi standard for AP and STA
void L7Receive(uint8_t nodeId, Ptr< const Packet > p, const Address &addr)
Function to trace packets received by the server application.
Ptr< ListErrorModel > m_nonApStaErrorModel
error model to install on the non-AP STA
void DoRun() override
Implementation to actually run this TestCase.
Test transmission of broadcast and unicast frames with STAs in Power Save mode.
const std::array< std::string, N_LINKS > m_channels
frequency channels for the two links
static constexpr std::size_t DUT_INDEX
DUT index.
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u txPower)
Callback invoked when PHY receives a PSDU to transmit.
void InsertEvents()
Insert elements in the list of expected events (transmitted frames).
bool m_checkTxPsdus
whether to check transmitted PSDUs against the inserted events
static constexpr double DUT_BEACON_JITTER
jitter for the initial Beacon frame sent on the link used by the DUT for association
bool m_staticSetup
whether static setup helper is used to configure association
static constexpr double STA_BEACON_JITTER
jitter for the initial Beacon frame sent on the link used by the other STA for association
void DoSetup() override
Implementation to do any local setup required for this TestCase.
WifiPsModeAttributesTest(bool enableEmlsr, bool staticSetup)
Constructor.
std::vector< PacketSocketAddress > m_dlSockets
packet socket addresses for DL traffic
const Time m_psmTimeout
the PSM timeout
void DoRun() override
Implementation to actually run this TestCase.
std::list< Events > m_events
list of events for a test run
Ptr< ApWifiMac > m_apMac
AP wifi MAC.
static constexpr double WAIT_BEACON_SURPLUS
the time a STA listens for a Beacon is the percentage of the Beacon interval given by the sum of the ...
bool m_enableEmlsr
whether to enable EMLSR on the DUT
static constexpr std::size_t N_LINKS
number of links for ML devices
Time m_duration
simulation duration
const std::string m_otherChannel
channel used to initialize the PHY of the DUT operating on the link that shall not be used for ML set...
std::array< Ptr< StaWifiMac >, 2 > m_staMacs
wifi MACs of the STAs
std::vector< PacketSocketAddress > m_ulSockets
packet socket addresses for UL traffic
static constexpr std::size_t STA_INDEX
index of the other non-AP STA
const Time m_switchDelay
channel switch, transition and padding delay
Ptr< PacketSocketClient > GetApplication(WifiDirection dir, std::size_t staId, std::size_t count, std::size_t pktSize, uint8_t priority=0) const
const Time m_listenAdvance
the value for the ListenAdvance attribute
a polymophic address class
Definition address.h:114
AttributeValue implementation for Boolean.
Definition boolean.h:26
iterator in a Buffer instance
Definition buffer.h:98
automatically resized byte buffer
Definition buffer.h:92
uint32_t GetSize() const
Definition buffer.h:1084
void AddAtStart(uint32_t start)
Definition buffer.cc:303
Buffer::Iterator Begin() const
Definition buffer.h:1090
Callback template class.
Definition callback.h:428
void TestHeaderSerialization(const T &hdr, Args &&... args)
Serialize the given header in a buffer, then create a new header by deserializing from the buffer and...
HeaderSerializationTestCase(std::string name)
Constructor.
Provide a list of Packet uids to corrupt.
an EUI-48 address
static Mac48Address GetBroadcast()
Implement the header for management frames of type beacon.
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
keep track of a set of node pointers.
static Iterator Begin()
Definition node-list.cc:226
static uint32_t GetNNodes()
Definition node-list.cc:247
static Iterator End()
Definition node-list.cc:233
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static void Run()
Run the simulation.
Definition simulator.cc:161
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
Make it easy to create and manage PHY objects for the spectrum model.
void SetChannel(const Ptr< SpectrumChannel > channel)
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
The Traffic Indication Map Information Element.
Definition tim.h:29
uint8_t m_dtimPeriod
The DTIM Period field.
Definition tim.h:86
uint8_t m_dtimCount
The DTIM Count field.
Definition tim.h:85
void AddAid(uint16_t aid)
Add the provided AID value to the list contained in the Virtual Bitmap.
Definition tim.cc:40
std::set< uint16_t > GetAidSet(uint16_t aid=0) const
Return the AID values, greater than the given AID value, whose corresponding bits are set in the virt...
Definition tim.cc:54
bool m_hasMulticastPending
Whether there is Multicast / Broadcast data.
Definition tim.h:87
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:408
Time TimeStep(uint64_t ts)
Scheduler interface.
Definition nstime.h:1370
@ US
microsecond
Definition nstime.h:108
@ MS
millisecond
Definition nstime.h:107
@ S
second
Definition nstime.h:106
AttributeValue implementation for Time.
Definition nstime.h:1375
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
CategoryValue GetCategory() const
Return the category value.
ActionValue GetAction() const
Return the action value.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
uint16_t GetSerializedSize() const
Get the size of the serialized IE including Element ID and length fields (for every element this IE i...
Buffer::Iterator Serialize(Buffer::Iterator i) const
Serialize entire IE including Element ID and length fields.
Implements the IEEE 802.11 MAC header.
virtual const char * GetTypeString() const
Return a string corresponds to the header type.
create MAC layers for a ns3::WifiNetDevice.
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
void Set(std::string name, const AttributeValue &v)
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1574
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1567
static void SetStaticBlockAckPostInit(Ptr< WifiNetDevice > originatorDev, Ptr< WifiNetDevice > recipientDev, tid_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
Perform ADDBA Request-Response exchange sequence between input devices for given TID post initializat...
static void SetStaticAssociation(Ptr< WifiNetDevice > bssDev, const NetDeviceContainer &clientDevs)
Bypass static capabilities exchange for input devices.
static void SetStaticEmlsr(Ptr< WifiNetDevice > apDev, const NetDeviceContainer &clientDevs)
Bypass EML Operating Mode Notification exchange sequence between AP MLD and input non-AP devices.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:946
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:133
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:240
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition test.h:553
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1307
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
WifiStandard
Identifies the IEEE 802.11 specifications that a Wifi device can be configured to use.
WifiPowerManagementMode
Enumeration for power management modes.
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211n
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ WIFI_PM_POWERSAVE
@ WIFI_PM_ACTIVE
@ AC_BE
Best Effort.
Definition qos-utils.h:66
Every class exported by the ns3 library is enclosed in the ns3 namespace.
FrequencyRange GetFrequencyRange(WifiPhyBand band)
Get the frequency range corresponding to the given PHY band.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:463
const Time MAX_PROPAGATION_DELAY
maximum propagation delay
WifiPhyState
The state of the PHY layer.
@ IDLE
The PHY layer is IDLE.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ SLEEP
The PHY layer is sleeping.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:295
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_BACKREQ
@ WIFI_MAC_DATA_NULL
@ WIFI_MAC_CTL_PSPOLL
@ WIFI_MAC_CTL_RTS
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_CTL_ACK
@ WIFI_MAC_CTL_BACKRESP
@ WIFI_MAC_CTL_END
@ WIFI_MAC_QOSDATA
WifiDirection
Wifi direction.
Definition wifi-utils.h:40
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
uint8_t linkId_t
IEEE 802.11be D7.0 Figure 9-207e—Link ID Info field format.
Definition wifi-utils.h:74
double Watt_u
Watt weak type.
Definition wifi-units.h:25
const Time DEFAULT_BEACON_INTERVAL
Default Beacon interval.
STL namespace.
static PowerSaveTestSuite g_powerSaveTestSuite
the test suite
std::function< void(Ptr< const WifiPsdu >, const Time &, uint8_t)> func
function to perform actions and checks
Events(WifiMacType type, std::function< void(Ptr< const WifiPsdu >, const Time &, uint8_t)> &&f={})
Constructor.
WifiMacType hdrType
MAC header type of frame being transmitted.
WifiMacType hdrType
MAC header type of frame being transmitted.
Events(WifiMacType type, std::function< void(Ptr< const WifiPsdu >, const WifiTxVector &, linkId_t)> &&f={})
Constructor.
std::function< void(Ptr< const WifiPsdu >, const WifiTxVector &, linkId_t)> func
function to perform actions and checks
WifiPhyBand band
PHY band.
Definition wifi-types.h:126
static WifiChannelConfig FromString(const std::string &settings, WifiStandard standard=WIFI_STANDARD_UNSPECIFIED)
Get the wifi channel config from a WifiPhy::ChannelSettings string.
Definition wifi-types.cc:24
const Segment & front() const
Definition wifi-types.h:216
hold per-remote-station state.
std::string dir
BlockAckActionValue blockAck
block ack