A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ctrl-headers.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 MIRKO BANCHI
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mirko Banchi <mk.banchi@gmail.com>
7 */
8
9#include "ctrl-headers.h"
10
11#include "wifi-tx-vector.h"
12#include "wifi-utils.h"
13
14#include "ns3/address-utils.h"
15#include "ns3/he-phy.h"
16
17#include <algorithm>
18
19namespace ns3
20{
21
22/***********************************
23 * Block ack request
24 ***********************************/
25
26NS_OBJECT_ENSURE_REGISTERED(CtrlBAckRequestHeader);
27
29 : m_barAckPolicy(false),
30 m_barType(BlockAckReqType::BASIC)
31{
32}
33
37
40{
41 static TypeId tid = TypeId("ns3::CtrlBAckRequestHeader")
43 .SetGroupName("Wifi")
44 .AddConstructor<CtrlBAckRequestHeader>();
45 return tid;
46}
47
53
54void
55CtrlBAckRequestHeader::Print(std::ostream& os) const
56{
57 os << "TID_INFO=" << m_tidInfo << ", StartingSeq=" << std::hex << m_startingSeq << std::dec;
58}
59
62{
63 uint32_t size = 0;
64 size += 2; // Bar control
65 switch (m_barType.m_variant)
66 {
70 size += 2;
71 break;
73 size += (2 + 2) * (m_tidInfo + 1);
74 break;
75 default:
76 NS_FATAL_ERROR("Invalid BA type");
77 break;
78 }
79 return size;
80}
81
82void
84{
85 Buffer::Iterator i = start;
87 switch (m_barType.m_variant)
88 {
93 break;
95 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
96 break;
97 default:
98 NS_FATAL_ERROR("Invalid BA type");
99 break;
100 }
101}
102
105{
106 Buffer::Iterator i = start;
108 switch (m_barType.m_variant)
109 {
114 break;
116 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
117 break;
118 default:
119 NS_FATAL_ERROR("Invalid BA type");
120 break;
121 }
122 return i.GetDistanceFrom(start);
123}
124
125uint16_t
127{
128 uint16_t res = 0;
129 switch (m_barType.m_variant)
130 {
132 break;
134 res |= (0x02 << 1);
135 break;
137 res |= (0x01 << 1);
138 break;
140 res |= (0x03 << 1);
141 break;
142 default:
143 NS_FATAL_ERROR("Invalid BA type");
144 break;
145 }
146 res |= (m_tidInfo << 12) & (0xf << 12);
147 return res;
148}
149
150void
152{
153 m_barAckPolicy = ((bar & 0x01) == 1);
154 if (((bar >> 1) & 0x0f) == 0x03)
155 {
157 }
158 else if (((bar >> 1) & 0x0f) == 0x01)
159 {
161 }
162 else if (((bar >> 1) & 0x0f) == 0x02)
163 {
165 }
166 else
167 {
169 }
170 m_tidInfo = (bar >> 12) & 0x0f;
171}
172
173uint16_t
175{
176 return (m_startingSeq << 4) & 0xfff0;
177}
178
179void
181{
182 m_startingSeq = (seqControl >> 4) & 0x0fff;
183}
184
185void
187{
188 m_barAckPolicy = immediateAck;
189}
190
191void
196
199{
200 return m_barType;
201}
202
203void
205{
206 m_tidInfo = static_cast<uint16_t>(tid);
207}
208
209void
214
215bool
220
221uint8_t
223{
224 auto tid = static_cast<uint8_t>(m_tidInfo);
225 return tid;
226}
227
228uint16_t
233
234bool
239
240bool
245
246bool
251
252bool
257
258/***********************************
259 * Block ack response
260 ***********************************/
261
263
265 : m_baAckPolicy(false),
266 m_tidInfo(0)
267{
269}
270
274
275TypeId
277{
278 static TypeId tid = TypeId("ns3::CtrlBAckResponseHeader")
279 .SetParent<Header>()
280 .SetGroupName("Wifi")
281 .AddConstructor<CtrlBAckResponseHeader>();
282 return tid;
283}
284
285TypeId
290
291void
292CtrlBAckResponseHeader::Print(std::ostream& os) const
293{
295 {
296 os << "TID_INFO=" << m_tidInfo << ", StartingSeq=0x" << std::hex
297 << m_baInfo[0].m_startingSeq << std::dec;
298 }
299 else
300 {
301 for (std::size_t i = 0; i < m_baInfo.size(); i++)
302 {
303 os << "{AID=" << GetAid11(i) << ", TID=" << GetTidInfo(i) << ", StartingSeq=0x"
304 << std::hex << m_baInfo[i].m_startingSeq << std::dec << "}";
305 }
306 }
307}
308
311{
312 // This method only makes use of the configured BA type, so that functions like
313 // GetBlockAckSize () can easily return the size of a Block Ack of a given type
314 uint32_t size = 0;
315 size += 2; // BA control
316 switch (m_baType.m_variant)
317 {
321 size += (2 + m_baType.m_bitmapLen[0]);
322 break;
324 size += (2 + 2 + 8) * (m_tidInfo + 1); // Multi-TID block ack
325 break;
327 for (auto& bitmapLen : m_baType.m_bitmapLen)
328 {
329 size += 2 /* AID TID Info */ + (bitmapLen > 0 ? 2 : 0) /* BA SSC */ + bitmapLen;
330 }
331 break;
332 default:
333 NS_FATAL_ERROR("Invalid BA type");
334 break;
335 }
336 return size;
337}
338
339void
341{
342 Buffer::Iterator i = start;
344 switch (m_baType.m_variant)
345 {
350 i = SerializeBitmap(i);
351 break;
353 for (std::size_t index = 0; index < m_baInfo.size(); index++)
354 {
355 i.WriteHtolsbU16(m_baInfo[index].m_aidTidInfo);
356 if (GetAid11(index) != 2045)
357 {
358 if (!m_baInfo[index].m_bitmap.empty())
359 {
361 i = SerializeBitmap(i, index);
362 }
363 }
364 else
365 {
366 uint32_t reserved = 0;
367 i.WriteHtolsbU32(reserved);
368 WriteTo(i, m_baInfo[index].m_ra);
369 }
370 }
371 break;
373 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
374 break;
375 default:
376 NS_FATAL_ERROR("Invalid BA type");
377 break;
378 }
379}
380
383{
384 Buffer::Iterator i = start;
386 switch (m_baType.m_variant)
387 {
392 i = DeserializeBitmap(i);
393 break;
395 std::size_t index = 0;
396 while (i.GetRemainingSize() > 0)
397 {
398 m_baInfo.emplace_back();
399 m_baType.m_bitmapLen.push_back(0); // updated by next call to SetStartingSequenceControl
400
401 m_baInfo.back().m_aidTidInfo = i.ReadLsbtohU16();
402
403 if (GetAid11(index) != 2045)
404 {
405 // the Block Ack Starting Sequence Control and Block Ack Bitmap subfields
406 // are only present in Block acknowledgement context, i.e., if the Ack Type
407 // subfield is set to 0 and the TID subfield is set to a value from 0 to 7.
408 if (!GetAckType(index) && GetTidInfo(index) < 8)
409 {
411 i = DeserializeBitmap(i, index);
412 }
413 }
414 else
415 {
416 i.ReadLsbtohU32(); // next 4 bytes are reserved
417 ReadFrom(i, m_baInfo.back().m_ra);
418 // the length of this Per AID TID Info subfield is 12, so set
419 // the bitmap length to 8 to simulate the correct size
420 m_baType.m_bitmapLen.back() = 8;
421 }
422 index++;
423 }
424 }
425 break;
427 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
428 break;
429 default:
430 NS_FATAL_ERROR("Invalid BA type");
431 break;
432 }
433 return i.GetDistanceFrom(start);
434}
435
436void
438{
439 m_baAckPolicy = immediateAck;
440}
441
442void
444{
445 m_baType = type;
446 m_baInfo.clear();
447
448 for (auto& bitmapLen : m_baType.m_bitmapLen)
449 {
450 BaInfoInstance baInfoInstance{.m_aidTidInfo = 0,
451 .m_startingSeq = 0,
452 .m_bitmap = std::vector<uint8_t>(bitmapLen, 0),
453 .m_ra = Mac48Address()};
454
455 m_baInfo.emplace_back(baInfoInstance);
456 }
457}
458
461{
462 return m_baType;
463}
464
465void
466CtrlBAckResponseHeader::SetTidInfo(uint8_t tid, std::size_t index)
467{
469 "index can only be non null for Multi-STA Block Ack");
470 NS_ASSERT(index < m_baInfo.size());
471
473 {
474 m_tidInfo = static_cast<uint16_t>(tid);
475 }
476 else
477 {
478 m_baInfo[index].m_aidTidInfo |= ((static_cast<uint16_t>(tid) & 0x000f) << 12);
479 }
480}
481
482void
483CtrlBAckResponseHeader::SetStartingSequence(uint16_t seq, std::size_t index)
484{
486 "index can only be non null for Multi-STA Block Ack");
487 NS_ASSERT(index < m_baInfo.size());
488
489 m_baInfo[index].m_startingSeq = seq;
490}
491
492bool
497
498uint8_t
500{
502 "index can only be non null for Multi-STA Block Ack");
503 NS_ASSERT(index < m_baInfo.size());
504
505 uint8_t tid = 0;
506
508 {
509 tid = static_cast<uint8_t>(m_tidInfo);
510 }
511 else
512 {
513 tid = static_cast<uint8_t>((m_baInfo[index].m_aidTidInfo >> 12) & 0x000f);
514 }
515 return tid;
516}
517
518uint16_t
520{
522 "index can only be non null for Multi-STA Block Ack");
523 NS_ASSERT(index < m_baInfo.size());
524
525 return m_baInfo[index].m_startingSeq;
526}
527
528bool
533
534bool
539
540bool
545
546bool
551
552bool
557
558void
559CtrlBAckResponseHeader::SetAid11(uint16_t aid, std::size_t index)
560{
562
563 m_baInfo[index].m_aidTidInfo |= (aid & 0x07ff);
564}
565
566uint16_t
567CtrlBAckResponseHeader::GetAid11(std::size_t index) const
568{
570
571 return m_baInfo[index].m_aidTidInfo & 0x07ff;
572}
573
574void
575CtrlBAckResponseHeader::SetAckType(bool type, std::size_t index)
576{
578
579 if (type)
580 {
581 m_baInfo[index].m_aidTidInfo |= (1 << 11);
582 }
583}
584
585bool
587{
589
590 return ((m_baInfo[index].m_aidTidInfo >> 11) & 0x0001) != 0;
591}
592
593void
595{
596 NS_ASSERT(GetAid11(index) == 2045);
597
598 m_baInfo[index].m_ra = ra;
599}
600
603{
604 NS_ASSERT(GetAid11(index) == 2045);
605
606 return m_baInfo[index].m_ra;
607}
608
609std::size_t
615
616std::vector<uint32_t>
618{
620
621 std::vector<uint32_t> ret;
622 ret.reserve(m_baInfo.size());
623 for (uint32_t i = 0; i < m_baInfo.size(); i++)
624 {
625 if (GetAid11(i) == aid)
626 {
627 ret.push_back(i);
628 }
629 }
630 return ret;
631}
632
633uint16_t
635{
636 uint16_t res = 0;
637 if (m_baAckPolicy)
638 {
639 res |= 0x1;
640 }
641 switch (m_baType.m_variant)
642 {
644 break;
646 res |= (0x02 << 1);
647 break;
649 res |= (0x01 << 1);
650 break;
652 res |= (0x03 << 1);
653 break;
655 res |= (0x0b << 1);
656 break;
657 default:
658 NS_FATAL_ERROR("Invalid BA type");
659 break;
660 }
662 {
663 res |= (m_tidInfo << 12) & (0xf << 12);
664 }
665 return res;
666}
667
668void
670{
671 m_baAckPolicy = ((ba & 0x01) == 1);
672 if (((ba >> 1) & 0x0f) == 0x03)
673 {
675 }
676 else if (((ba >> 1) & 0x0f) == 0x01)
677 {
679 }
680 else if (((ba >> 1) & 0x0f) == 0x02)
681 {
683 }
684 else if (((ba >> 1) & 0x0f) == 0)
685 {
687 }
688 else if (((ba >> 1) & 0x0f) == 0x0b)
689 {
691 }
692 else
693 {
694 NS_FATAL_ERROR("Invalid BA type");
695 }
697 {
698 m_tidInfo = (ba >> 12) & 0x0f;
699 }
700}
701
702uint16_t
704{
706 "index can only be non null for Multi-STA Block Ack");
707 NS_ASSERT(index < m_baInfo.size());
708
709 uint16_t ret = (m_baInfo[index].m_startingSeq << 4) & 0xfff0;
710
711 // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA
712 // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0).
713 // Note that Fragmentation Level 3 is not supported.
715 {
716 switch (m_baType.m_bitmapLen[0])
717 {
718 case 8:
719 // do nothing
720 break;
721 case 32:
722 ret |= 0x0004;
723 break;
724 case 64:
725 ret |= 0x0008;
726 break;
727 case 128:
728 ret |= 0x000a;
729 break;
730 default:
731 NS_ABORT_MSG("Unsupported bitmap length: " << +m_baType.m_bitmapLen[0] << " bytes");
732 }
733 }
735 {
736 NS_ASSERT(m_baInfo.size() == m_baType.m_bitmapLen.size());
737 NS_ASSERT_MSG(!m_baInfo[index].m_bitmap.empty(),
738 "This Per AID TID Info subfield has no Starting Sequence Control subfield");
739
740 switch (m_baType.m_bitmapLen[index])
741 {
742 case 8:
743 // do nothing
744 break;
745 case 16:
746 ret |= 0x0002;
747 break;
748 case 32:
749 ret |= 0x0004;
750 break;
751 case 4:
752 ret |= 0x0006;
753 break;
754 case 64:
755 ret |= 0x0008;
756 break;
757 case 128:
758 ret |= 0x000a;
759 break;
760 default:
761 NS_ABORT_MSG("Unsupported bitmap length: " << +m_baType.m_bitmapLen[index] << " bytes");
762 }
763 }
764 return ret;
765}
766
767void
768CtrlBAckResponseHeader::SetStartingSequenceControl(uint16_t seqControl, std::size_t index)
769{
771 "index can only be non null for Multi-STA Block Ack");
772 NS_ASSERT(index < m_baInfo.size());
773
774 // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA
775 // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0).
776 // Note that Fragmentation Level 3 is not supported.
778 {
779 uint16_t fragNumber = seqControl & 0x000f;
780
781 if ((fragNumber & 0x0001) == 1)
782 {
783 NS_FATAL_ERROR("Fragmentation Level 3 unsupported");
784 }
785 switch (fragNumber)
786 {
787 case 0:
789 break;
790 case 4:
792 break;
793 case 8:
795 break;
796 case 10:
798 break;
799 default:
800 NS_ABORT_MSG("Unsupported fragment number: " << fragNumber);
801 }
802 }
804 {
805 uint16_t fragNumber = seqControl & 0x000f;
806
807 if ((fragNumber & 0x0001) == 1)
808 {
809 NS_FATAL_ERROR("Fragmentation Level 3 unsupported");
810 }
811 uint8_t bitmapLen = 0;
812 switch (fragNumber)
813 {
814 case 0:
815 bitmapLen = 8;
816 break;
817 case 2:
818 bitmapLen = 16;
819 break;
820 case 4:
821 bitmapLen = 32;
822 break;
823 case 6:
824 bitmapLen = 4;
825 break;
826 case 8:
827 bitmapLen = 64;
828 break;
829 case 10:
830 bitmapLen = 128;
831 break;
832 default:
833 NS_ABORT_MSG("Unsupported fragment number: " << fragNumber);
834 }
835 m_baType.m_bitmapLen[index] = bitmapLen;
836 m_baInfo[index].m_bitmap.assign(bitmapLen, 0);
837 }
838
839 m_baInfo[index].m_startingSeq = (seqControl >> 4) & 0x0fff;
840}
841
844{
846 "index can only be non null for Multi-STA Block Ack");
847 NS_ASSERT(index < m_baInfo.size());
848
849 Buffer::Iterator i = start;
850 switch (m_baType.m_variant)
851 {
856 for (const auto& byte : m_baInfo[index].m_bitmap)
857 {
858 i.WriteU8(byte);
859 }
860 break;
862 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
863 break;
864 default:
865 NS_FATAL_ERROR("Invalid BA type");
866 break;
867 }
868 return i;
869}
870
873{
875 "index can only be non null for Multi-STA Block Ack");
876 NS_ASSERT(index < m_baInfo.size());
877
878 Buffer::Iterator i = start;
879 switch (m_baType.m_variant)
880 {
885 for (uint8_t j = 0; j < m_baType.m_bitmapLen[index]; j++)
886 {
887 m_baInfo[index].m_bitmap[j] = i.ReadU8();
888 }
889 break;
891 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
892 break;
893 default:
894 NS_FATAL_ERROR("Invalid BA type");
895 break;
896 }
897 return i;
898}
899
900void
901CtrlBAckResponseHeader::SetReceivedPacket(uint16_t seq, std::size_t index)
902{
904 "index can only be non null for Multi-STA Block Ack");
905 NS_ASSERT(index < m_baInfo.size());
906
907 if (!IsInBitmap(seq, index))
908 {
909 return;
910 }
911 switch (m_baType.m_variant)
912 {
914 /* To set correctly basic block ack bitmap we need fragment number too.
915 So if it's not specified, we consider packet not fragmented. */
916 m_baInfo[index].m_bitmap[IndexInBitmap(seq) * 2] |= 0x01;
917 break;
921 uint16_t i = IndexInBitmap(seq, index);
922 m_baInfo[index].m_bitmap[i / 8] |= (uint8_t(0x01) << (i % 8));
923 break;
924 }
926 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
927 break;
928 default:
929 NS_FATAL_ERROR("Invalid BA type");
930 break;
931 }
932}
933
934void
936{
937 NS_ASSERT(frag < 16);
938 if (!IsInBitmap(seq))
939 {
940 return;
941 }
942 switch (m_baType.m_variant)
943 {
945 m_baInfo[0].m_bitmap[IndexInBitmap(seq) * 2 + frag / 8] |= (0x01 << (frag % 8));
946 break;
950 /* We can ignore this...compressed block ack doesn't support
951 acknowledgment of single fragments */
952 break;
954 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
955 break;
956 default:
957 NS_FATAL_ERROR("Invalid BA type");
958 break;
959 }
960}
961
962bool
963CtrlBAckResponseHeader::IsPacketReceived(uint16_t seq, std::size_t index) const
964{
966 "index can only be non null for Multi-STA Block Ack");
967 NS_ASSERT(index < m_baInfo.size());
968
970 GetTidInfo(index) == 14)
971 {
972 // All-ack context
973 return true;
974 }
975 if (!IsInBitmap(seq, index))
976 {
977 return false;
978 }
979 switch (m_baType.m_variant)
980 {
982 /*It's impossible to say if an entire packet was correctly received. */
983 return false;
987 uint16_t i = IndexInBitmap(seq, index);
988 uint8_t mask = uint8_t(0x01) << (i % 8);
989 return (m_baInfo[index].m_bitmap[i / 8] & mask) != 0;
990 }
992 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
993 break;
994 default:
995 NS_FATAL_ERROR("Invalid BA type");
996 break;
997 }
998 return false;
999}
1000
1001bool
1002CtrlBAckResponseHeader::IsFragmentReceived(uint16_t seq, uint8_t frag) const
1003{
1004 NS_ASSERT(frag < 16);
1005 if (!IsInBitmap(seq))
1006 {
1007 return false;
1008 }
1009 switch (m_baType.m_variant)
1010 {
1012 return (m_baInfo[0].m_bitmap[IndexInBitmap(seq) * 2 + frag / 8] & (0x01 << (frag % 8))) !=
1013 0;
1017 /* We can ignore this...compressed block ack doesn't support
1018 acknowledgement of single fragments */
1019 return false;
1021 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
1022 break;
1023 }
1024 default: {
1025 NS_FATAL_ERROR("Invalid BA type");
1026 break;
1027 }
1028 }
1029 return false;
1030}
1031
1032uint16_t
1033CtrlBAckResponseHeader::IndexInBitmap(uint16_t seq, std::size_t index) const
1034{
1035 uint16_t i;
1036 if (seq >= m_baInfo[index].m_startingSeq)
1037 {
1038 i = seq - m_baInfo[index].m_startingSeq;
1039 }
1040 else
1041 {
1042 i = SEQNO_SPACE_SIZE - m_baInfo[index].m_startingSeq + seq;
1043 }
1044
1045 uint16_t nAckedMpdus = m_baType.m_bitmapLen[index] * 8;
1046
1048 {
1049 nAckedMpdus = nAckedMpdus / 16;
1050 }
1051
1052 NS_ASSERT(i < nAckedMpdus);
1053 return i;
1054}
1055
1056bool
1057CtrlBAckResponseHeader::IsInBitmap(uint16_t seq, std::size_t index) const
1058{
1060 "index can only be non null for Multi-STA Block Ack");
1061 NS_ASSERT(index < m_baType.m_bitmapLen.size());
1062
1063 uint16_t nAckedMpdus = m_baType.m_bitmapLen[index] * 8;
1064
1066 {
1067 nAckedMpdus = nAckedMpdus / 16;
1068 }
1069
1070 return (seq - m_baInfo[index].m_startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE <
1071 nAckedMpdus;
1072}
1073
1074const std::vector<uint8_t>&
1076{
1078 "index can only be non null for Multi-STA Block Ack");
1079 NS_ASSERT(index < m_baInfo.size());
1080
1081 return m_baInfo[index].m_bitmap;
1082}
1083
1084void
1086{
1088 "index can only be non null for Multi-STA Block Ack");
1089 NS_ASSERT(index < m_baInfo.size());
1090
1091 m_baInfo[index].m_bitmap.assign(m_baType.m_bitmapLen[index], 0);
1092}
1093
1094/***********************************
1095 * Trigger frame - User Info field
1096 ***********************************/
1097
1099 TriggerFrameVariant variant)
1100 : m_variant(variant),
1101 m_aid12(0),
1102 m_ruAllocation(0),
1103 m_ulFecCodingType(false),
1104 m_ulMcs(0),
1105 m_ulDcm(false),
1106 m_ps160(true),
1107 m_ulTargetRssi(0),
1108 m_triggerType(triggerType),
1109 m_basicTriggerDependentUserInfo(0)
1110{
1111 memset(&m_bits26To31, 0, sizeof(m_bits26To31));
1112}
1113
1117
1120{
1121 NS_ABORT_MSG_IF(m_triggerType != userInfo.m_triggerType, "Trigger Frame type mismatch");
1122
1123 // check for self-assignment
1124 if (&userInfo == this)
1125 {
1126 return *this;
1127 }
1128
1129 m_variant = userInfo.m_variant;
1130 m_aid12 = userInfo.m_aid12;
1131 m_ruAllocation = userInfo.m_ruAllocation;
1133 m_ulMcs = userInfo.m_ulMcs;
1134 m_ulDcm = userInfo.m_ulDcm;
1135 m_ps160 = userInfo.m_ps160;
1136 m_bits26To31 = userInfo.m_bits26To31;
1137 m_ulTargetRssi = userInfo.m_ulTargetRssi;
1140 return *this;
1141}
1142
1143void
1144CtrlTriggerUserInfoField::Print(std::ostream& os) const
1145{
1146 os << ", USER_INFO " << (m_variant == TriggerFrameVariant::HE ? "HE" : "EHT")
1147 << " variant AID=" << m_aid12 << ", RU_Allocation=" << +m_ruAllocation
1148 << ", MCS=" << +m_ulMcs;
1149}
1150
1153{
1154 uint32_t size = 0;
1155 size += 5; // User Info (excluding Trigger Dependent User Info)
1156
1157 switch (m_triggerType)
1158 {
1161 size += 1;
1162 break;
1164 size +=
1165 m_muBarTriggerDependentUserInfo.GetSerializedSize(); // BAR Control and BAR Information
1166 break;
1167 default:;
1168 // The Trigger Dependent User Info subfield is not present in the other variants
1169 }
1170
1171 return size;
1172}
1173
1176{
1178 "BFRP Trigger frame is not supported");
1180 "GCR-MU-BAR Trigger frame is not supported");
1182 "NFRP Trigger frame is not supported");
1183
1184 Buffer::Iterator i = start;
1185
1186 uint32_t userInfo = 0; // User Info except the MSB
1187 userInfo |= (m_aid12 & 0x0fff);
1188 userInfo |= (m_ruAllocation << 12);
1189 userInfo |= (m_ulFecCodingType ? 1 << 20 : 0);
1190 userInfo |= (m_ulMcs & 0x0f) << 21;
1192 {
1193 userInfo |= (m_ulDcm ? 1 << 25 : 0);
1194 }
1195
1196 if (m_aid12 != 0 && m_aid12 != 2045)
1197 {
1198 userInfo |= (m_bits26To31.ssAllocation.startingSs & 0x07) << 26;
1199 userInfo |= (m_bits26To31.ssAllocation.nSs & 0x07) << 29;
1200 }
1201 else
1202 {
1203 userInfo |= (m_bits26To31.raRuInformation.nRaRu & 0x1f) << 26;
1204 userInfo |= (m_bits26To31.raRuInformation.moreRaRu ? 1 << 31 : 0);
1205 }
1206
1207 i.WriteHtolsbU32(userInfo);
1208 // Here we need to write 8 bits covering the UL Target RSSI (7 bits) and B39, which is
1209 // reserved in the HE variant and the PS160 subfield in the EHT variant.
1210 uint8_t bit32To39 = m_ulTargetRssi;
1212 {
1213 bit32To39 |= (m_ps160 ? 1 << 7 : 0);
1214 }
1215
1216 i.WriteU8(bit32To39);
1217
1219 {
1221 }
1223 {
1226 }
1227
1228 return i;
1229}
1230
1233{
1235 "BFRP Trigger frame is not supported");
1237 "GCR-MU-BAR Trigger frame is not supported");
1239 "NFRP Trigger frame is not supported");
1240
1241 Buffer::Iterator i = start;
1242
1243 uint32_t userInfo = i.ReadLsbtohU32();
1244
1245 m_aid12 = userInfo & 0x0fff;
1246 NS_ABORT_MSG_IF(m_aid12 == 4095, "Cannot deserialize a Padding field");
1247 m_ruAllocation = (userInfo >> 12) & 0xff;
1248 m_ulFecCodingType = (userInfo >> 20) & 0x01;
1249 m_ulMcs = (userInfo >> 21) & 0x0f;
1251 {
1252 m_ulDcm = (userInfo >> 25) & 0x01;
1253 }
1254
1255 if (m_aid12 != 0 && m_aid12 != 2045)
1256 {
1257 m_bits26To31.ssAllocation.startingSs = (userInfo >> 26) & 0x07;
1258 m_bits26To31.ssAllocation.nSs = (userInfo >> 29) & 0x07;
1259 }
1260 else
1261 {
1262 m_bits26To31.raRuInformation.nRaRu = (userInfo >> 26) & 0x1f;
1263 m_bits26To31.raRuInformation.moreRaRu = (userInfo >> 31) & 0x01;
1264 }
1265
1266 uint8_t bit32To39 = i.ReadU8();
1267 m_ulTargetRssi = bit32To39 & 0x7f; // B39 is reserved in HE variant
1269 {
1270 m_ps160 = (bit32To39 >> 7) == 1;
1271 }
1272
1274 {
1276 }
1278 {
1280 i.Next(len);
1281 }
1282
1283 return i;
1284}
1285
1288{
1289 return m_triggerType;
1290}
1291
1294{
1295 switch (m_variant)
1296 {
1298 return WIFI_PREAMBLE_HE_TB;
1300 return WIFI_PREAMBLE_EHT_TB;
1301 default:
1302 NS_ABORT_MSG("Unexpected variant: " << +static_cast<uint8_t>(m_variant));
1303 }
1304 return WIFI_PREAMBLE_LONG; // to silence warning
1305}
1306
1307void
1309{
1310 m_aid12 = aid & 0x0fff;
1311}
1312
1313uint16_t
1315{
1316 return m_aid12;
1317}
1318
1319bool
1321{
1322 return (m_aid12 == 0);
1323}
1324
1325bool
1327{
1328 return (m_aid12 == 2045);
1329}
1330
1331void
1333{
1334 NS_ABORT_MSG_IF(ru.GetIndex() == 0, "Valid indices start at 1");
1336 "SetMuRtsRuAllocation() must be used for MU-RTS");
1337
1338 switch (ru.GetRuType())
1339 {
1340 case HeRu::RU_26_TONE:
1341 m_ruAllocation = ru.GetIndex() - 1;
1342 break;
1343 case HeRu::RU_52_TONE:
1344 m_ruAllocation = ru.GetIndex() + 36;
1345 break;
1346 case HeRu::RU_106_TONE:
1347 m_ruAllocation = ru.GetIndex() + 52;
1348 break;
1349 case HeRu::RU_242_TONE:
1350 m_ruAllocation = ru.GetIndex() + 60;
1351 break;
1352 case HeRu::RU_484_TONE:
1353 m_ruAllocation = ru.GetIndex() + 64;
1354 break;
1355 case HeRu::RU_996_TONE:
1356 m_ruAllocation = 67;
1357 break;
1359 m_ruAllocation = 68;
1360 break;
1361 default:
1362 NS_FATAL_ERROR("RU type unknown.");
1363 break;
1364 }
1365
1366 NS_ABORT_MSG_IF(m_ruAllocation > 68, "Reserved value.");
1367
1368 m_ruAllocation <<= 1;
1369 if (!ru.GetPrimary80MHz())
1370 {
1372 }
1373}
1374
1377{
1379 "GetMuRtsRuAllocation() must be used for MU-RTS");
1380
1381 HeRu::RuType ruType;
1382 std::size_t index;
1383
1384 bool primary80MHz = ((m_ruAllocation & 0x01) == 0);
1385
1386 uint8_t val = m_ruAllocation >> 1;
1387
1388 if (val < 37)
1389 {
1390 ruType = HeRu::RU_26_TONE;
1391 index = val + 1;
1392 }
1393 else if (val < 53)
1394 {
1395 ruType = HeRu::RU_52_TONE;
1396 index = val - 36;
1397 }
1398 else if (val < 61)
1399 {
1400 ruType = HeRu::RU_106_TONE;
1401 index = val - 52;
1402 }
1403 else if (val < 65)
1404 {
1405 ruType = HeRu::RU_242_TONE;
1406 index = val - 60;
1407 }
1408 else if (val < 67)
1409 {
1410 ruType = HeRu::RU_484_TONE;
1411 index = val - 64;
1412 }
1413 else if (val == 67)
1414 {
1415 ruType = HeRu::RU_996_TONE;
1416 index = 1;
1417 }
1418 else if (val == 68)
1419 {
1420 ruType = HeRu::RU_2x996_TONE;
1421 index = 1;
1422 }
1423 else
1424 {
1425 NS_FATAL_ERROR("Reserved value.");
1426 }
1427
1428 return HeRu::RuSpec(ruType, index, primary80MHz);
1429}
1430
1431void
1433{
1435 "SetMuRtsRuAllocation() can only be used for MU-RTS");
1437 value < 61 || value > 68,
1438 "Value "
1439 << +value
1440 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1441
1442 m_ruAllocation = (value << 1);
1443 if (value == 68)
1444 {
1445 // set B0 for 160 MHz and 80+80 MHz indication
1447 }
1448}
1449
1450uint8_t
1452{
1454 "GetMuRtsRuAllocation() can only be used for MU-RTS");
1455 uint8_t value = (m_ruAllocation >> 1);
1457 value < 61 || value > 68,
1458 "Value "
1459 << +value
1460 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1461 return value;
1462}
1463
1464void
1469
1470bool
1475
1476void
1478{
1479 uint8_t maxMcs = m_variant == TriggerFrameVariant::EHT ? 13 : 11;
1480 NS_ABORT_MSG_IF(mcs > maxMcs, "Invalid MCS index");
1481 m_ulMcs = mcs;
1482}
1483
1484uint8_t
1486{
1487 return m_ulMcs;
1488}
1489
1490void
1492{
1493 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1494 m_ulDcm = dcm;
1495}
1496
1497bool
1499{
1500 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1501 return m_ulDcm;
1502}
1503
1504void
1505CtrlTriggerUserInfoField::SetSsAllocation(uint8_t startingSs, uint8_t nSs)
1506{
1507 NS_ABORT_MSG_IF(m_aid12 == 0 || m_aid12 == 2045, "SS Allocation subfield not present");
1508 NS_ABORT_MSG_IF(!startingSs || startingSs > 8, "Starting SS must be from 1 to 8");
1509 NS_ABORT_MSG_IF(!nSs || nSs > 8, "Number of SS must be from 1 to 8");
1510
1511 m_bits26To31.ssAllocation.startingSs = startingSs - 1;
1512 m_bits26To31.ssAllocation.nSs = nSs - 1;
1513}
1514
1515uint8_t
1517{
1518 if (m_aid12 == 0 || m_aid12 == 2045)
1519 {
1520 return 1;
1521 }
1522 return m_bits26To31.ssAllocation.startingSs + 1;
1523}
1524
1525uint8_t
1527{
1528 if (m_aid12 == 0 || m_aid12 == 2045)
1529 {
1530 return 1;
1531 }
1532 return m_bits26To31.ssAllocation.nSs + 1;
1533}
1534
1535void
1537{
1538 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1539 NS_ABORT_MSG_IF(!nRaRu || nRaRu > 32, "Number of contiguous RA-RUs must be from 1 to 32");
1540
1541 m_bits26To31.raRuInformation.nRaRu = nRaRu - 1;
1542 m_bits26To31.raRuInformation.moreRaRu = moreRaRu;
1543}
1544
1545uint8_t
1547{
1548 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1549
1550 return m_bits26To31.raRuInformation.nRaRu + 1;
1551}
1552
1553bool
1555{
1556 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1557
1558 return m_bits26To31.raRuInformation.moreRaRu;
1559}
1560
1561void
1563{
1564 m_ulTargetRssi = 127; // see Table 9-25i of 802.11ax amendment D3.0
1565}
1566
1567void
1569{
1570 NS_ABORT_MSG_IF(dBm < -110 || dBm > -20, "Invalid values for signal power");
1571
1572 m_ulTargetRssi = static_cast<uint8_t>(110 + dBm);
1573}
1574
1575bool
1580
1581int8_t
1583{
1584 NS_ABORT_MSG_IF(m_ulTargetRssi == 127, "STA must use its max TX power");
1585
1586 return static_cast<int8_t>(m_ulTargetRssi) - 110;
1587}
1588
1589void
1591 uint8_t tidLimit,
1592 AcIndex prefAc)
1593{
1594 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1595
1596 m_basicTriggerDependentUserInfo = (spacingFactor & 0x03) |
1597 (tidLimit & 0x07) << 2
1598 // B5 is reserved
1599 | (prefAc & 0x03) << 6;
1600}
1601
1602uint8_t
1609
1610uint8_t
1612{
1613 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1614
1615 return (m_basicTriggerDependentUserInfo & 0x1c) >> 2;
1616}
1617
1618AcIndex
1620{
1621 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1622
1623 return AcIndex((m_basicTriggerDependentUserInfo & 0xc0) >> 6);
1624}
1625
1626void
1628{
1630 "Not a MU-BAR Trigger frame");
1633 "BAR Control indicates it is neither the Compressed nor the Multi-TID variant");
1635}
1636
1645
1646/***********************************
1647 * Trigger frame
1648 ***********************************/
1649
1651
1653 : m_variant(TriggerFrameVariant::HE),
1654 m_triggerType(TriggerFrameType::BASIC_TRIGGER),
1655 m_ulLength(0),
1656 m_moreTF(false),
1657 m_csRequired(false),
1658 m_ulBandwidth(0),
1659 m_giAndLtfType(0),
1660 m_apTxPower(0),
1661 m_ulSpatialReuse(0),
1662 m_padding(0)
1663{
1664}
1665
1668{
1670 "This constructor cannot be used for MU-RTS");
1671
1672 switch (txVector.GetPreambleType())
1673 {
1676 break;
1679 break;
1680 default:
1681 NS_ABORT_MSG("Cannot create a TF out of a TXVECTOR with preamble type: "
1682 << txVector.GetPreambleType());
1683 }
1684
1685 m_triggerType = type;
1686 SetUlBandwidth(txVector.GetChannelWidth());
1687 SetUlLength(txVector.GetLength());
1688 const auto gi = txVector.GetGuardInterval().GetNanoSeconds();
1689 if ((gi == 800) || (gi == 1600))
1690 {
1691 m_giAndLtfType = 1;
1692 }
1693 else
1694 {
1695 m_giAndLtfType = 2;
1696 }
1697 for (auto& userInfo : txVector.GetHeMuUserInfoMap())
1698 {
1700 ui.SetAid12(userInfo.first);
1701 ui.SetRuAllocation(userInfo.second.ru);
1702 ui.SetUlMcs(userInfo.second.mcs);
1703 ui.SetSsAllocation(1, userInfo.second.nss); // MU-MIMO is not supported
1704 }
1705}
1706
1710
1713{
1714 // check for self-assignment
1715 if (&trigger == this)
1716 {
1717 return *this;
1718 }
1719
1720 m_variant = trigger.m_variant;
1721 m_triggerType = trigger.m_triggerType;
1722 m_ulLength = trigger.m_ulLength;
1723 m_moreTF = trigger.m_moreTF;
1724 m_csRequired = trigger.m_csRequired;
1725 m_ulBandwidth = trigger.m_ulBandwidth;
1727 m_apTxPower = trigger.m_apTxPower;
1729 m_padding = trigger.m_padding;
1730 m_userInfoFields.clear();
1732 return *this;
1733}
1734
1735TypeId
1737{
1738 static TypeId tid = TypeId("ns3::CtrlTriggerHeader")
1739 .SetParent<Header>()
1740 .SetGroupName("Wifi")
1741 .AddConstructor<CtrlTriggerHeader>();
1742 return tid;
1743}
1744
1745TypeId
1747{
1748 return GetTypeId();
1749}
1750
1751void
1752CtrlTriggerHeader::Print(std::ostream& os) const
1753{
1754 os << "TriggerType=" << GetTypeString() << ", Bandwidth=" << +GetUlBandwidth()
1755 << ", UL Length=" << m_ulLength;
1756
1757 for (auto& ui : m_userInfoFields)
1758 {
1759 ui.Print(os);
1760 }
1761}
1762
1763void
1765{
1767 "Cannot change Common Info field variant if User Info fields are present");
1768 m_variant = variant;
1769}
1770
1773{
1774 return m_variant;
1775}
1776
1779{
1780 uint32_t size = 0;
1781 size += 8; // Common Info (excluding Trigger Dependent Common Info)
1782
1783 // Add the size of the Trigger Dependent Common Info subfield
1785 {
1786 size += 4;
1787 }
1788
1789 for (auto& ui : m_userInfoFields)
1790 {
1791 size += ui.GetSerializedSize();
1792 }
1793
1794 size += m_padding;
1795
1796 return size;
1797}
1798
1799void
1801{
1803 "BFRP Trigger frame is not supported");
1805 "GCR-MU-BAR Trigger frame is not supported");
1807 "NFRP Trigger frame is not supported");
1808
1809 Buffer::Iterator i = start;
1810
1811 uint64_t commonInfo = 0;
1812 commonInfo |= (static_cast<uint8_t>(m_triggerType) & 0x0f);
1813 commonInfo |= (m_ulLength & 0x0fff) << 4;
1814 commonInfo |= (m_moreTF ? 1 << 16 : 0);
1815 commonInfo |= (m_csRequired ? 1 << 17 : 0);
1816 commonInfo |= (m_ulBandwidth & 0x03) << 18;
1817 commonInfo |= (m_giAndLtfType & 0x03) << 20;
1818 commonInfo |= static_cast<uint64_t>(m_apTxPower & 0x3f) << 28;
1819 commonInfo |= static_cast<uint64_t>(m_ulSpatialReuse) << 37;
1821 {
1822 uint64_t ulHeSigA2 = 0x01ff; // nine bits equal to 1
1823 commonInfo |= ulHeSigA2 << 54;
1824 }
1825
1826 i.WriteHtolsbU64(commonInfo);
1827
1828 for (auto& ui : m_userInfoFields)
1829 {
1830 i = ui.Serialize(i);
1831 }
1832
1833 for (std::size_t count = 0; count < m_padding; count++)
1834 {
1835 i.WriteU8(0xff); // Padding field
1836 }
1837}
1838
1841{
1842 Buffer::Iterator i = start;
1843
1844 uint64_t commonInfo = i.ReadLsbtohU64();
1845
1846 m_triggerType = static_cast<TriggerFrameType>(commonInfo & 0x0f);
1847 m_ulLength = (commonInfo >> 4) & 0x0fff;
1848 m_moreTF = (commonInfo >> 16) & 0x01;
1849 m_csRequired = (commonInfo >> 17) & 0x01;
1850 m_ulBandwidth = (commonInfo >> 18) & 0x03;
1851 m_giAndLtfType = (commonInfo >> 20) & 0x03;
1852 m_apTxPower = (commonInfo >> 28) & 0x3f;
1853 m_ulSpatialReuse = (commonInfo >> 37) & 0xffff;
1854 uint8_t bit54and55 = (commonInfo >> 54) & 0x03;
1856 m_userInfoFields.clear();
1857 m_padding = 0;
1858
1860 "BFRP Trigger frame is not supported");
1862 "GCR-MU-BAR Trigger frame is not supported");
1864 "NFRP Trigger frame is not supported");
1865
1866 while (i.GetRemainingSize() >= 2)
1867 {
1868 // read the first 2 bytes to check if we encountered the Padding field
1869 if (i.ReadU16() == 0xffff)
1870 {
1871 m_padding = i.GetRemainingSize() + 2;
1872 }
1873 else
1874 {
1875 // go back 2 bytes to deserialize the User Info field from the beginning
1876 i.Prev(2);
1878 i = ui.Deserialize(i);
1879 }
1880 }
1881
1882 return i.GetDistanceFrom(start);
1883}
1884
1885void
1890
1893{
1894 return m_triggerType;
1895}
1896
1897const char*
1899{
1900 return GetTypeString(GetType());
1901}
1902
1903const char*
1905{
1906#define FOO(x) \
1907 case TriggerFrameType::x: \
1908 return #x;
1909
1910 switch (type)
1911 {
1920 default:
1921 return "ERROR";
1922 }
1923#undef FOO
1924}
1925
1926bool
1931
1932bool
1937
1938bool
1943
1944bool
1949
1950bool
1955
1956bool
1961
1962bool
1967
1968bool
1973
1974void
1976{
1977 m_ulLength = (len & 0x0fff);
1978}
1979
1980uint16_t
1982{
1983 return m_ulLength;
1984}
1985
1988{
1990 "GetHeTbTxVector() cannot be used for MU-RTS");
1991 auto userInfoIt = FindUserInfoWithAid(staId);
1992 NS_ASSERT(userInfoIt != end());
1993
1994 WifiTxVector v;
1995 v.SetPreambleType(userInfoIt->GetPreambleType());
2000 staId,
2001 {userInfoIt->GetRuAllocation(), userInfoIt->GetUlMcs(), userInfoIt->GetNss()});
2002 return v;
2003}
2004
2005void
2007{
2008 m_moreTF = more;
2009}
2010
2011bool
2013{
2014 return m_moreTF;
2015}
2016
2017void
2019{
2020 m_csRequired = cs;
2021}
2022
2023bool
2025{
2026 return m_csRequired;
2027}
2028
2029void
2031{
2032 switch (static_cast<uint16_t>(bw))
2033 {
2034 case 20:
2035 m_ulBandwidth = 0;
2036 break;
2037 case 40:
2038 m_ulBandwidth = 1;
2039 break;
2040 case 80:
2041 m_ulBandwidth = 2;
2042 break;
2043 case 160:
2044 m_ulBandwidth = 3;
2045 break;
2046 default:
2047 NS_FATAL_ERROR("Bandwidth value not allowed.");
2048 break;
2049 }
2050}
2051
2052MHz_u
2054{
2055 return (1 << m_ulBandwidth) * 20;
2056}
2057
2058void
2059CtrlTriggerHeader::SetGiAndLtfType(Time guardInterval, uint8_t ltfType)
2060{
2061 const auto gi = guardInterval.GetNanoSeconds();
2062 if ((ltfType == 1) && (gi == 1600))
2063 {
2064 m_giAndLtfType = 0;
2065 }
2066 else if ((ltfType == 2) && (gi == 1600))
2067 {
2068 m_giAndLtfType = 1;
2069 }
2070 else if ((ltfType == 4) && (gi == 3200))
2071 {
2072 m_giAndLtfType = 2;
2073 }
2074 else
2075 {
2076 NS_FATAL_ERROR("Invalid combination of GI and LTF type");
2077 }
2078}
2079
2080Time
2082{
2083 if (m_giAndLtfType == 0 || m_giAndLtfType == 1)
2084 {
2085 return NanoSeconds(1600);
2086 }
2087 else if (m_giAndLtfType == 2)
2088 {
2089 return NanoSeconds(3200);
2090 }
2091 else
2092 {
2093 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2094 }
2095}
2096
2097uint8_t
2099{
2100 if (m_giAndLtfType == 0)
2101 {
2102 return 1;
2103 }
2104 else if (m_giAndLtfType == 1)
2105 {
2106 return 2;
2107 }
2108 else if (m_giAndLtfType == 2)
2109 {
2110 return 4;
2111 }
2112 else
2113 {
2114 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2115 }
2116}
2117
2118void
2120{
2121 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2122 NS_ABORT_MSG_IF(power < -20 || power > 40, "Out of range power values");
2123
2124 m_apTxPower = static_cast<uint8_t>(power + 20);
2125}
2126
2127int8_t
2129{
2130 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2131 return static_cast<int8_t>(m_apTxPower) - 20;
2132}
2133
2134void
2136{
2137 m_ulSpatialReuse = sr;
2138}
2139
2140uint16_t
2145
2146void
2148{
2149 NS_ABORT_MSG_IF(size == 1, "The Padding field, if present, shall be at least two octets");
2150 m_padding = size;
2151}
2152
2153std::size_t
2155{
2156 return m_padding;
2157}
2158
2161{
2162 // make a copy of this Trigger Frame and remove the User Info fields from the copy
2163 CtrlTriggerHeader trigger(*this);
2164 trigger.m_userInfoFields.clear();
2165 return trigger;
2166}
2167
2174
2177{
2179 userInfo.GetType() != m_triggerType,
2180 "Trying to add a User Info field of a type other than the type of the Trigger Frame");
2181 m_userInfoFields.push_back(userInfo);
2182 return m_userInfoFields.back();
2183}
2184
2187{
2188 return m_userInfoFields.begin();
2189}
2190
2193{
2194 return m_userInfoFields.end();
2195}
2196
2199{
2200 return m_userInfoFields.begin();
2201}
2202
2205{
2206 return m_userInfoFields.end();
2207}
2208
2209std::size_t
2211{
2212 return m_userInfoFields.size();
2213}
2214
2217{
2218 // the lambda function returns true if a User Info field has the AID12 subfield
2219 // equal to the given aid12 value
2220 return std::find_if(start, end(), [aid12](const CtrlTriggerUserInfoField& ui) -> bool {
2221 return (ui.GetAid12() == aid12);
2222 });
2223}
2224
2227{
2228 return FindUserInfoWithAid(m_userInfoFields.begin(), aid12);
2229}
2230
2236
2242
2248
2254
2255bool
2257{
2259 {
2260 return true;
2261 }
2262
2263 // check that allocated RUs do not overlap
2264 // TODO This is not a problem in case of UL MU-MIMO
2265 std::vector<HeRu::RuSpec> prevRus;
2266
2267 for (auto& ui : m_userInfoFields)
2268 {
2269 if (HeRu::DoesOverlap(GetUlBandwidth(), ui.GetRuAllocation(), prevRus))
2270 {
2271 return false;
2272 }
2273 prevRus.push_back(ui.GetRuAllocation());
2274 }
2275 return true;
2276}
2277
2278} // namespace ns3
iterator in a Buffer instance
Definition buffer.h:89
uint32_t GetRemainingSize() const
Definition buffer.cc:1162
void WriteHtolsbU16(uint16_t data)
Definition buffer.cc:891
void WriteU8(uint8_t data)
Definition buffer.h:870
void WriteHtolsbU32(uint32_t data)
Definition buffer.cc:899
uint16_t ReadLsbtohU16()
Definition buffer.cc:1053
uint64_t ReadLsbtohU64()
Definition buffer.cc:1083
void WriteHtolsbU64(uint64_t data)
Definition buffer.cc:909
uint32_t GetDistanceFrom(const Iterator &o) const
Definition buffer.cc:769
void Prev()
go backward by one byte
Definition buffer.h:849
uint16_t ReadU16()
Definition buffer.h:1024
uint32_t ReadLsbtohU32()
Definition buffer.cc:1065
void Next()
go forward by one byte
Definition buffer.h:842
Headers for BlockAckRequest.
uint16_t GetStartingSequence() const
Return the starting sequence number.
uint32_t GetSerializedSize() const override
void Serialize(Buffer::Iterator start) const override
uint16_t m_startingSeq
starting seq
bool m_barAckPolicy
The LSB bit of the BAR control field is used only for the HT (High Throughput) delayed block ack conf...
uint16_t m_tidInfo
TID info.
uint8_t GetTidInfo() const
Return the Traffic ID (TID).
bool IsExtendedCompressed() const
Check if the current Ack Policy is Extended Compressed Block Ack.
void Print(std::ostream &os) const override
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
BlockAckReqType m_barType
BAR type.
void SetStartingSequenceControl(uint16_t seqControl)
Set the starting sequence control with the given sequence control value.
bool IsMultiTid() const
Check if the current Ack Policy has Multi-TID Block Ack.
BlockAckReqType GetType() const
Return the BlockAckRequest type.
void SetHtImmediateAck(bool immediateAck)
Enable or disable HT immediate Ack.
uint32_t Deserialize(Buffer::Iterator start) override
bool IsCompressed() const
Check if the current Ack Policy is Compressed Block Ack and not multi-TID.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
uint16_t GetBarControl() const
Return the Block Ack control.
static TypeId GetTypeId()
Get the type ID.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
uint16_t GetStartingSequenceControl() const
Return the starting sequence control.
void SetBarControl(uint16_t bar)
Set the Block Ack control.
bool MustSendHtImmediateAck() const
Check if the current Ack Policy is immediate.
bool IsBasic() const
Check if the current Ack Policy is Basic Block Ack (i.e.
Headers for BlockAck response.
void SetBaControl(uint16_t ba)
Set the Block Ack control.
bool IsExtendedCompressed() const
Check if the current BA policy is Extended Compressed Block Ack.
void SetStartingSequence(uint16_t seq, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the starting sequence number to the given ...
uint32_t Deserialize(Buffer::Iterator start) override
uint16_t GetStartingSequenceControl(std::size_t index=0) const
Return the value of the Starting Sequence Control subfield.
BlockAckType m_baType
BA type.
bool IsFragmentReceived(uint16_t seq, uint8_t frag) const
Check if the packet with the given sequence number and fragment number was acknowledged in this Block...
void Serialize(Buffer::Iterator start) const override
bool IsPacketReceived(uint16_t seq, std::size_t index=0) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response.
void SetStartingSequenceControl(uint16_t seqControl, std::size_t index=0)
Set the Starting Sequence Control subfield with the given sequence control value.
std::vector< uint32_t > FindPerAidTidInfoWithAid(uint16_t aid) const
For Multi-STA Block Acks, get the indices of the Per AID TID Info subfields carrying the given AID in...
Buffer::Iterator SerializeBitmap(Buffer::Iterator start, std::size_t index=0) const
Serialize bitmap to the given buffer.
std::size_t GetNPerAidTidInfoSubfields() const
For Multi-STA Block Acks, get the number of Per AID TID Info subfields included in this Block Ack.
uint16_t GetStartingSequence(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the starting sequence number.
Mac48Address GetUnassociatedStaAddress(std::size_t index) const
For Multi-STA Block Acks, get the RA subfield of the Per AID TID Info subfield (with AID11 subfield e...
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
bool IsBasic() const
Check if the current BA policy is Basic Block Ack.
const std::vector< uint8_t > & GetBitmap(std::size_t index=0) const
Return a const reference to the bitmap from the BlockAck response header.
bool m_baAckPolicy
The LSB bit of the BA control field is used only for the HT (High Throughput) delayed block ack confi...
bool IsCompressed() const
Check if the current BA policy is Compressed Block Ack.
void SetUnassociatedStaAddress(const Mac48Address &ra, std::size_t index)
For Multi-STA Block Acks, set the RA subfield of the Per AID TID Info subfield (with AID11 subfield e...
bool MustSendHtImmediateAck() const
Check if the current Ack Policy is immediate.
Buffer::Iterator DeserializeBitmap(Buffer::Iterator start, std::size_t index=0)
Deserialize bitmap from the given buffer.
void ResetBitmap(std::size_t index=0)
Reset the bitmap to 0.
void SetAckType(bool type, std::size_t index)
For Multi-STA Block Acks, set the Ack Type subfield of the Per AID TID Info subfield identified by th...
void SetTidInfo(uint8_t tid, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the TID_INFO subfield of the BA Control fi...
uint16_t m_tidInfo
TID info (reserved if Multi-STA Block Ack)
void Print(std::ostream &os) const override
void SetType(BlockAckType type)
Set the block ack type.
uint32_t GetSerializedSize() const override
uint16_t GetBaControl() const
Return the Block Ack control.
BlockAckType GetType() const
Return the block ack type ID.
void SetReceivedFragment(uint16_t seq, uint8_t frag)
Set the bitmap that the packet with the given sequence number and fragment number was received.
static TypeId GetTypeId()
Get the type ID.
void SetReceivedPacket(uint16_t seq, std::size_t index=0)
Record in the bitmap that the packet with the given sequence number was received.
bool IsMultiTid() const
Check if the current BA policy is Multi-TID Block Ack.
void SetHtImmediateAck(bool immediateAck)
Enable or disable HT immediate Ack.
std::vector< BaInfoInstance > m_baInfo
BA Information field.
void SetAid11(uint16_t aid, std::size_t index)
For Multi-STA Block Acks, set the AID11 subfield of the Per AID TID Info subfield identified by the g...
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
uint16_t GetAid11(std::size_t index) const
For Multi-STA Block Acks, get the AID11 subfield of the Per AID TID Info subfield identified by the g...
bool IsMultiSta() const
Check if the BlockAck frame variant is Multi-STA Block Ack.
bool IsInBitmap(uint16_t seq, std::size_t index=0) const
Check if sequence number seq can be acknowledged in the bitmap.
uint16_t IndexInBitmap(uint16_t seq, std::size_t index=0) const
This function is used to correctly index in both bitmap and compressed bitmap, one bit or one block o...
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
Headers for Trigger frames.
std::size_t GetPaddingSize() const
CtrlTriggerUserInfoField & AddUserInfoField()
Append a new User Info field to this Trigger frame and return a non-const reference to it.
uint32_t GetSerializedSize() const override
bool IsBasic() const
Check if this is a Basic Trigger frame.
ConstIterator FindUserInfoWithRaRuAssociated() const
Get a const iterator pointing to the first User Info field found which allocates a Random Access RU f...
void Print(std::ostream &os) const override
bool IsNfrp() const
Check if this is a NDP Feedback Report Poll Trigger frame.
void SetApTxPower(int8_t power)
Set the AP TX Power subfield of the Common Info field.
ConstIterator end() const
Get a const iterator indicating past-the-last User Info field in the list.
uint16_t GetUlSpatialReuse() const
Get the UL Spatial Reuse subfield of the Common Info field.
std::size_t m_padding
the size in bytes of the Padding field
uint8_t m_giAndLtfType
GI And LTF Type subfield.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsMuRts() const
Check if this is a MU-RTS Trigger frame.
TriggerFrameType m_triggerType
Trigger type.
void SetPaddingSize(std::size_t size)
Set the size in bytes of the Padding field.
uint32_t Deserialize(Buffer::Iterator start) override
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
TriggerFrameType GetType() const
Get the Trigger Frame type.
bool IsMuBar() const
Check if this is a MU-BAR Trigger frame.
ConstIterator FindUserInfoWithRaRuUnassociated() const
Get a const iterator pointing to the first User Info field found which allocates a Random Access RU f...
bool IsBfrp() const
Check if this is a Beamforming Report Poll Trigger frame.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
std::size_t GetNUserInfoFields() const
Get the number of User Info fields in this Trigger Frame.
uint8_t GetLtfType() const
Get the LTF type of the solicited HE TB PPDU.
bool GetMoreTF() const
Get the More TF subfield of the Common Info field.
std::list< CtrlTriggerUserInfoField >::const_iterator ConstIterator
User Info fields list const iterator.
bool IsBqrp() const
Check if this is a Bandwidth Query Report Poll Trigger frame.
static TypeId GetTypeId()
Get the type ID.
bool IsValid() const
Check the validity of this Trigger frame.
void SetType(TriggerFrameType type)
Set the Trigger frame type.
ConstIterator FindUserInfoWithAid(ConstIterator start, uint16_t aid12) const
Get a const iterator pointing to the first User Info field found (starting from the one pointed to by...
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
void SetCsRequired(bool cs)
Set the CS Required subfield of the Common Info field.
const char * GetTypeString() const
Return a string corresponding to the Trigger Frame type.
uint16_t GetUlLength() const
Get the UL Length subfield of the Common Info field.
TriggerFrameVariant m_variant
Common Info field.
uint16_t m_ulLength
Value for the L-SIG Length field.
bool m_csRequired
Carrier Sense required.
MHz_u GetUlBandwidth() const
Get the bandwidth of the solicited HE TB PPDU.
TriggerFrameVariant GetVariant() const
Get the Common Info field variant.
CtrlTriggerHeader GetCommonInfoField() const
Get a copy of the Common Info field of this Trigger frame.
Time GetGuardInterval() const
Get the guard interval duration of the solicited HE TB PPDU.
std::list< CtrlTriggerUserInfoField > m_userInfoFields
List of User Info fields.
bool m_moreTF
True if a subsequent Trigger frame follows.
void SetVariant(TriggerFrameVariant variant)
Set the Common Info field variant.
void SetUlSpatialReuse(uint16_t sr)
Set the UL Spatial Reuse subfield of the Common Info field.
uint8_t m_ulBandwidth
UL BW subfield.
bool GetCsRequired() const
Get the CS Required subfield of the Common Info field.
bool IsGcrMuBar() const
Check if this is a Groupcast with Retries (GCR) MU-BAR Trigger frame.
std::list< CtrlTriggerUserInfoField >::iterator Iterator
User Info fields list iterator.
void SetGiAndLtfType(Time guardInterval, uint8_t ltfType)
Set the GI And LTF Type subfield of the Common Info field.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
void Serialize(Buffer::Iterator start) const override
int8_t GetApTxPower() const
Get the power value (dBm) indicated by the AP TX Power subfield of the Common Info field.
uint8_t m_apTxPower
Tx Power used by AP to transmit the Trigger Frame.
CtrlTriggerHeader & operator=(const CtrlTriggerHeader &trigger)
Copy assignment operator.
uint16_t m_ulSpatialReuse
Value for the Spatial Reuse field in HE-SIG-A.
void SetMoreTF(bool more)
Set the More TF subfield of the Common Info field.
void SetUlBandwidth(MHz_u bw)
Set the bandwidth of the solicited HE TB PPDU.
User Info field of Trigger frames.
bool GetUlFecCodingType() const
Get the UL FEC Coding Type subfield, which indicates whether BCC or LDPC is used.
bool GetUlDcm() const
Get the UL DCM subfield, which indicates whether or not DCM is used This method can only be used with...
AcIndex GetPreferredAc() const
Get the Preferred AC subfield.
uint8_t GetMpduMuSpacingFactor() const
Get the MPDU MU spacing factor.
int8_t GetUlTargetRssi() const
Get the expected receive signal power for the solicited HE TB PPDU.
uint8_t startingSs
Starting spatial stream.
TriggerFrameType m_triggerType
Trigger frame type.
uint8_t GetUlMcs() const
Get the UL MCS subfield, which indicates the MCS of the solicited HE TB PPDU.
WifiPreamble GetPreambleType() const
uint32_t GetSerializedSize() const
Get the expected size of this User Info field.
void SetMuRtsRuAllocation(uint8_t value)
Set the RU Allocation subfield based on the given value for the B7-B1 bits.
CtrlTriggerUserInfoField(TriggerFrameType triggerType, TriggerFrameVariant variant)
Constructor.
void Print(std::ostream &os) const
Print the content of this User Info field.
uint8_t nRaRu
Number of Random Access RUs.
union ns3::CtrlTriggerUserInfoField::@69 m_bits26To31
Fields occupying bits 26-31 in the User Info field.
void SetAid12(uint16_t aid)
Set the AID12 subfield, which carries the 12 LSBs of the AID of the station for which this User Info ...
bool m_ps160
identifies the location of the RU (EHT variant only)
const CtrlBAckRequestHeader & GetMuBarTriggerDepUserInfo() const
Get the Trigger Dependent User Info subfield for the MU-BAR variant of Trigger frames,...
void SetUlFecCodingType(bool ldpc)
Set the UL FEC Coding Type subfield, which indicates whether BCC or LDPC is used.
bool HasRaRuForUnassociatedSta() const
Check if this User Info field allocates a Random Access RU for stations not associated with the AP th...
void SetUlTargetRssiMaxTxPower()
Set the UL Target RSSI subfield to indicate to the station to transmit an HE TB PPDU response at its ...
void SetUlMcs(uint8_t mcs)
Set the UL MCS subfield, which indicates the MCS of the solicited HE TB PPDU.
void SetMuBarTriggerDepUserInfo(const CtrlBAckRequestHeader &bar)
Set the Trigger Dependent User Info subfield for the MU-BAR variant of Trigger frames,...
void SetUlDcm(bool dcm)
Set the UL DCM subfield, which indicates whether or not DCM is used.
void SetSsAllocation(uint8_t startingSs, uint8_t nSs)
Set the SS Allocation subfield, which is present when the AID12 subfield is neither 0 nor 2045.
uint16_t m_aid12
Association ID of the addressed station.
uint8_t nSs
Number of spatial streams.
uint8_t m_basicTriggerDependentUserInfo
Basic Trigger variant of Trigger Dependent User Info subfield.
TriggerFrameVariant m_variant
User Info field variant.
uint8_t GetTidAggregationLimit() const
Get the TID Aggregation Limit.
uint8_t m_ulMcs
MCS to be used by the addressed station.
TriggerFrameType GetType() const
Get the type of the Trigger Frame this User Info field belongs to.
uint8_t m_ruAllocation
RU Allocation.
HeRu::RuSpec GetRuAllocation() const
Get the RU specified by the RU Allocation subfield.
uint8_t GetNss() const
Get the number of spatial streams.
bool HasRaRuForAssociatedSta() const
Check if this User Info field allocates a Random Access RU for stations associated with the AP that t...
uint8_t GetMuRtsRuAllocation() const
This method can only be called on MU-RTS Trigger Frames.
uint16_t GetAid12() const
Get the value of the AID12 subfield.
Buffer::Iterator Serialize(Buffer::Iterator start) const
Serialize the User Info field to the given buffer.
uint8_t GetNRaRus() const
Get the number of contiguous RUs for Random Access.
bool m_ulDcm
whether or not to use Dual Carrier Modulation (HE variant only)
void SetUlTargetRssi(int8_t dBm)
Set the UL Target RSSI subfield to indicate the expected receive signal power in dBm.
uint8_t GetStartingSs() const
Get the starting spatial stream.
CtrlTriggerUserInfoField & operator=(const CtrlTriggerUserInfoField &userInfo)
Copy assignment operator.
uint8_t m_ulTargetRssi
Expected receive signal power.
void SetRaRuInformation(uint8_t nRaRu, bool moreRaRu)
Set the RA-RU Information subfield, which is present when the AID12 subfield is 0 or 2045.
Buffer::Iterator Deserialize(Buffer::Iterator start)
Deserialize the User Info field from the given buffer.
bool IsUlTargetRssiMaxTxPower() const
Return true if the UL Target RSSI subfield indicates to the station to transmit an HE TB PPDU respons...
void SetRuAllocation(HeRu::RuSpec ru)
Set the RU Allocation subfield according to the specified RU.
void SetBasicTriggerDepUserInfo(uint8_t spacingFactor, uint8_t tidLimit, AcIndex prefAc)
Set the Trigger Dependent User Info subfield for Basic Trigger frames.
bool moreRaRu
More RA-RU in subsequent Trigger frames.
bool m_ulFecCodingType
UL FEC Coding Type.
CtrlBAckRequestHeader m_muBarTriggerDependentUserInfo
MU-BAR variant of Trigger Dependent User Info subfield.
bool GetMoreRaRu() const
Return true if more RA-RUs are allocated in subsequent Trigger frames that are sent before the end of...
RU Specification.
Definition he-ru.h:57
std::size_t GetIndex() const
Get the RU index.
Definition he-ru.cc:454
RuType GetRuType() const
Get the RU type.
Definition he-ru.cc:447
bool GetPrimary80MHz() const
Get the primary 80 MHz flag.
Definition he-ru.cc:461
static bool DoesOverlap(MHz_u bw, RuSpec ru, const std::vector< RuSpec > &v)
Check whether the given RU overlaps with the given set of RUs.
Definition he-ru.cc:619
RuType
The different HE Resource Unit (RU) types.
Definition he-ru.h:32
@ RU_26_TONE
Definition he-ru.h:33
@ RU_484_TONE
Definition he-ru.h:37
@ RU_996_TONE
Definition he-ru.h:38
@ RU_106_TONE
Definition he-ru.h:35
@ RU_52_TONE
Definition he-ru.h:34
@ RU_242_TONE
Definition he-ru.h:36
@ RU_2x996_TONE
Definition he-ru.h:39
Protocol header serialization and deserialization.
Definition header.h:33
an EUI-48 address
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
uint16_t GetLength() const
Get the LENGTH field of the L-SIG.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
MHz_u GetChannelWidth() const
Time GetGuardInterval() const
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define FOO(x)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
TriggerFrameVariant
The different variants for Common Info field and User Info field of Trigger Frames.
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
TriggerFrameType
The different Trigger frame types.
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double MHz_u
MHz weak type.
Definition wifi-units.h:31
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition wifi-utils.h:176
void WriteTo(Buffer::Iterator &i, Ipv4Address ad)
Write an Ipv4Address to a Buffer.
void ReadFrom(Buffer::Iterator &i, Ipv4Address &ad)
Read an Ipv4Address from a Buffer.
The different BlockAckRequest variants.
Variant m_variant
Block Ack Request variant.
The different BlockAck variants.
Variant m_variant
Block Ack variant.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
The following structure can hold the BA Information field for the Basic and Compressed variants,...
uint16_t m_aidTidInfo
Reserved for Basic and Compressed Per TID Info subfield for Multi-TID AID TID Info subfield for Multi...