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;
76 size += (2 + 6); // SSC plus GCR Group Address
77 break;
78 default:
79 NS_FATAL_ERROR("Invalid BA type");
80 break;
81 }
82 return size;
83}
84
85void
87{
88 Buffer::Iterator i = start;
90 switch (m_barType.m_variant)
91 {
96 break;
98 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
99 break;
103 break;
104 default:
105 NS_FATAL_ERROR("Invalid BA type");
106 break;
107 }
108}
109
112{
113 Buffer::Iterator i = start;
115 switch (m_barType.m_variant)
116 {
121 break;
123 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
124 break;
128 break;
129 default:
130 NS_FATAL_ERROR("Invalid BA type");
131 break;
132 }
133 return i.GetDistanceFrom(start);
134}
135
136uint16_t
138{
139 uint16_t res = 0;
140 switch (m_barType.m_variant)
141 {
143 break;
145 res |= (0x02 << 1);
146 break;
148 res |= (0x01 << 1);
149 break;
151 res |= (0x03 << 1);
152 break;
154 res |= (0x06 << 1);
155 break;
156 default:
157 NS_FATAL_ERROR("Invalid BA type");
158 break;
159 }
160 res |= (m_tidInfo << 12) & (0xf << 12);
161 return res;
162}
163
164void
166{
167 m_barAckPolicy = ((bar & 0x01) == 1);
168 if (((bar >> 1) & 0x0f) == 0x06)
169 {
171 }
172 else if (((bar >> 1) & 0x0f) == 0x03)
173 {
175 }
176 else if (((bar >> 1) & 0x0f) == 0x01)
177 {
179 }
180 else if (((bar >> 1) & 0x0f) == 0x02)
181 {
183 }
184 else
185 {
187 }
188 m_tidInfo = (bar >> 12) & 0x0f;
189}
190
191uint16_t
193{
194 return (m_startingSeq << 4) & 0xfff0;
195}
196
197void
199{
200 m_startingSeq = (seqControl >> 4) & 0x0fff;
201}
202
203void
205{
206 m_barAckPolicy = immediateAck;
207}
208
209void
214
217{
218 return m_barType;
219}
220
221void
223{
224 m_tidInfo = static_cast<uint16_t>(tid);
225}
226
227void
232
233bool
238
239uint8_t
241{
242 auto tid = static_cast<uint8_t>(m_tidInfo);
243 return tid;
244}
245
246uint16_t
251
252void
258
265
266bool
271
272bool
277
278bool
283
284bool
289
290bool
295
296/***********************************
297 * Block ack response
298 ***********************************/
299
301
303 : m_baAckPolicy(false),
304 m_tidInfo(0)
305{
307}
308
312
313TypeId
315{
316 static TypeId tid = TypeId("ns3::CtrlBAckResponseHeader")
317 .SetParent<Header>()
318 .SetGroupName("Wifi")
319 .AddConstructor<CtrlBAckResponseHeader>();
320 return tid;
321}
322
323TypeId
328
329void
330CtrlBAckResponseHeader::Print(std::ostream& os) const
331{
333 {
334 os << "TID_INFO=" << m_tidInfo << ", StartingSeq=0x" << std::hex
335 << m_baInfo[0].m_startingSeq << std::dec;
336 }
337 else
338 {
339 for (std::size_t i = 0; i < m_baInfo.size(); i++)
340 {
341 os << "{AID=" << GetAid11(i) << ", TID=" << GetTidInfo(i) << ", StartingSeq=0x"
342 << std::hex << m_baInfo[i].m_startingSeq << std::dec << "}";
343 }
344 }
345}
346
349{
350 // This method only makes use of the configured BA type, so that functions like
351 // GetBlockAckSize () can easily return the size of a Block Ack of a given type
352 uint32_t size = 0;
353 size += 2; // BA control
354 switch (m_baType.m_variant)
355 {
359 size += (2 + m_baType.m_bitmapLen[0]);
360 break;
362 size += (2 + 2 + 8) * (m_tidInfo + 1); // Multi-TID block ack
363 break;
365 size += (2 + 6 + m_baType.m_bitmapLen[0]);
366 break;
368 for (auto& bitmapLen : m_baType.m_bitmapLen)
369 {
370 size += 2 /* AID TID Info */ + (bitmapLen > 0 ? 2 : 0) /* BA SSC */ + bitmapLen;
371 }
372 break;
373 default:
374 NS_FATAL_ERROR("Invalid BA type");
375 break;
376 }
377 return size;
378}
379
380void
382{
383 Buffer::Iterator i = start;
385 switch (m_baType.m_variant)
386 {
391 i = SerializeBitmap(i);
392 break;
395 WriteTo(i, m_baInfo[0].m_address);
396 i = SerializeBitmap(i);
397 break;
399 for (std::size_t index = 0; index < m_baInfo.size(); index++)
400 {
401 i.WriteHtolsbU16(m_baInfo[index].m_aidTidInfo);
402 if (GetAid11(index) != 2045)
403 {
404 if (!m_baInfo[index].m_bitmap.empty())
405 {
407 i = SerializeBitmap(i, index);
408 }
409 }
410 else
411 {
412 uint32_t reserved = 0;
413 i.WriteHtolsbU32(reserved);
414 WriteTo(i, m_baInfo[index].m_address);
415 }
416 }
417 break;
419 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
420 break;
421 default:
422 NS_FATAL_ERROR("Invalid BA type");
423 break;
424 }
425}
426
429{
430 Buffer::Iterator i = start;
432 switch (m_baType.m_variant)
433 {
438 i = DeserializeBitmap(i);
439 break;
442 ReadFrom(i, m_baInfo[0].m_address);
443 i = DeserializeBitmap(i);
444 break;
446 std::size_t index = 0;
447 while (i.GetRemainingSize() > 0)
448 {
449 m_baInfo.emplace_back();
450 m_baType.m_bitmapLen.push_back(0); // updated by next call to SetStartingSequenceControl
451
452 m_baInfo.back().m_aidTidInfo = i.ReadLsbtohU16();
453
454 if (GetAid11(index) != 2045)
455 {
456 // the Block Ack Starting Sequence Control and Block Ack Bitmap subfields
457 // are only present in Block acknowledgement context, i.e., if the Ack Type
458 // subfield is set to 0 and the TID subfield is set to a value from 0 to 7.
459 if (!GetAckType(index) && GetTidInfo(index) < 8)
460 {
462 i = DeserializeBitmap(i, index);
463 }
464 }
465 else
466 {
467 i.ReadLsbtohU32(); // next 4 bytes are reserved
468 ReadFrom(i, m_baInfo.back().m_address);
469 // the length of this Per AID TID Info subfield is 12, so set
470 // the bitmap length to 8 to simulate the correct size
471 m_baType.m_bitmapLen.back() = 8;
472 }
473 index++;
474 }
475 }
476 break;
478 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
479 break;
480 default:
481 NS_FATAL_ERROR("Invalid BA type");
482 break;
483 }
484 return i.GetDistanceFrom(start);
485}
486
487void
489{
490 m_baAckPolicy = immediateAck;
491}
492
493void
495{
496 m_baType = type;
497 m_baInfo.clear();
498
499 for (auto& bitmapLen : m_baType.m_bitmapLen)
500 {
501 BaInfoInstance baInfoInstance{.m_aidTidInfo = 0,
502 .m_startingSeq = 0,
503 .m_bitmap = std::vector<uint8_t>(bitmapLen, 0),
504 .m_address = Mac48Address()};
505
506 m_baInfo.emplace_back(baInfoInstance);
507 }
508}
509
512{
513 return m_baType;
514}
515
516void
517CtrlBAckResponseHeader::SetTidInfo(uint8_t tid, std::size_t index)
518{
520 "index can only be non null for Multi-STA Block Ack");
521 NS_ASSERT(index < m_baInfo.size());
522
524 {
525 m_tidInfo = static_cast<uint16_t>(tid);
526 }
527 else
528 {
529 m_baInfo[index].m_aidTidInfo |= ((static_cast<uint16_t>(tid) & 0x000f) << 12);
530 }
531}
532
533void
534CtrlBAckResponseHeader::SetStartingSequence(uint16_t seq, std::size_t index)
535{
537 "index can only be non null for Multi-STA Block Ack");
538 NS_ASSERT(index < m_baInfo.size());
539
540 m_baInfo[index].m_startingSeq = seq;
541}
542
543bool
548
549uint8_t
551{
553 "index can only be non null for Multi-STA Block Ack");
554 NS_ASSERT(index < m_baInfo.size());
555
556 uint8_t tid = 0;
557
559 {
560 tid = static_cast<uint8_t>(m_tidInfo);
561 }
562 else
563 {
564 tid = static_cast<uint8_t>((m_baInfo[index].m_aidTidInfo >> 12) & 0x000f);
565 }
566 return tid;
567}
568
569uint16_t
571{
573 "index can only be non null for Multi-STA Block Ack");
574 NS_ASSERT(index < m_baInfo.size());
575
576 return m_baInfo[index].m_startingSeq;
577}
578
579bool
584
585bool
590
591bool
596
597bool
602
603bool
608
609bool
614
615void
616CtrlBAckResponseHeader::SetAid11(uint16_t aid, std::size_t index)
617{
619
620 m_baInfo[index].m_aidTidInfo |= (aid & 0x07ff);
621}
622
623uint16_t
624CtrlBAckResponseHeader::GetAid11(std::size_t index) const
625{
627
628 return m_baInfo[index].m_aidTidInfo & 0x07ff;
629}
630
631void
632CtrlBAckResponseHeader::SetAckType(bool type, std::size_t index)
633{
635
636 if (type)
637 {
638 m_baInfo[index].m_aidTidInfo |= (1 << 11);
639 }
640}
641
642bool
644{
646
647 return ((m_baInfo[index].m_aidTidInfo >> 11) & 0x0001) != 0;
648}
649
650void
652{
653 NS_ASSERT(GetAid11(index) == 2045);
654
655 m_baInfo[index].m_address = ra;
656}
657
660{
661 NS_ASSERT(GetAid11(index) == 2045);
662
663 return m_baInfo[index].m_address;
664}
665
666std::size_t
672
673std::vector<uint32_t>
675{
677
678 std::vector<uint32_t> ret;
679 ret.reserve(m_baInfo.size());
680 for (uint32_t i = 0; i < m_baInfo.size(); i++)
681 {
682 if (GetAid11(i) == aid)
683 {
684 ret.push_back(i);
685 }
686 }
687 return ret;
688}
689
690void
692{
693 NS_ASSERT(IsGcr());
694 m_baInfo[0].m_address = address;
695}
696
699{
700 NS_ASSERT(IsGcr());
701 return m_baInfo[0].m_address;
702}
703
704uint16_t
706{
707 uint16_t res = 0;
708 if (m_baAckPolicy)
709 {
710 res |= 0x1;
711 }
712 switch (m_baType.m_variant)
713 {
715 break;
717 res |= (0x02 << 1);
718 break;
720 res |= (0x01 << 1);
721 break;
723 res |= (0x03 << 1);
724 break;
726 res |= (0x06 << 1);
727 break;
729 res |= (0x0b << 1);
730 break;
731 default:
732 NS_FATAL_ERROR("Invalid BA type");
733 break;
734 }
736 {
737 res |= (m_tidInfo << 12) & (0xf << 12);
738 }
739 return res;
740}
741
742void
744{
745 m_baAckPolicy = ((ba & 0x01) == 1);
746 if (((ba >> 1) & 0x0f) == 0x06)
747 {
749 }
750 else if (((ba >> 1) & 0x0f) == 0x03)
751 {
753 }
754 else if (((ba >> 1) & 0x0f) == 0x01)
755 {
757 }
758 else if (((ba >> 1) & 0x0f) == 0x02)
759 {
761 }
762 else if (((ba >> 1) & 0x0f) == 0)
763 {
765 }
766 else if (((ba >> 1) & 0x0f) == 0x0b)
767 {
769 }
770 else
771 {
772 NS_FATAL_ERROR("Invalid BA type");
773 }
775 {
776 m_tidInfo = (ba >> 12) & 0x0f;
777 }
778}
779
780uint16_t
782{
784 "index can only be non null for Multi-STA Block Ack");
785 NS_ASSERT(index < m_baInfo.size());
786
787 uint16_t ret = (m_baInfo[index].m_startingSeq << 4) & 0xfff0;
788
789 // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA
790 // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0).
791 // Note that Fragmentation Level 3 is not supported.
793 {
794 switch (m_baType.m_bitmapLen[0])
795 {
796 case 8:
797 // do nothing
798 break;
799 case 32:
800 ret |= 0x0004;
801 break;
802 case 64:
803 ret |= 0x0008;
804 break;
805 case 128:
806 ret |= 0x000a;
807 break;
808 default:
809 NS_ABORT_MSG("Unsupported bitmap length: " << +m_baType.m_bitmapLen[0] << " bytes");
810 }
811 }
813 {
814 NS_ASSERT(m_baInfo.size() == m_baType.m_bitmapLen.size());
815 NS_ASSERT_MSG(!m_baInfo[index].m_bitmap.empty(),
816 "This Per AID TID Info subfield has no Starting Sequence Control subfield");
817
818 switch (m_baType.m_bitmapLen[index])
819 {
820 case 8:
821 // do nothing
822 break;
823 case 16:
824 ret |= 0x0002;
825 break;
826 case 32:
827 ret |= 0x0004;
828 break;
829 case 4:
830 ret |= 0x0006;
831 break;
832 case 64:
833 ret |= 0x0008;
834 break;
835 case 128:
836 ret |= 0x000a;
837 break;
838 default:
839 NS_ABORT_MSG("Unsupported bitmap length: " << +m_baType.m_bitmapLen[index] << " bytes");
840 }
841 }
842 return ret;
843}
844
845void
846CtrlBAckResponseHeader::SetStartingSequenceControl(uint16_t seqControl, std::size_t index)
847{
849 "index can only be non null for Multi-STA Block Ack");
850 NS_ASSERT(index < m_baInfo.size());
851
852 // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA
853 // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0).
854 // Note that Fragmentation Level 3 is not supported.
856 {
857 uint16_t fragNumber = seqControl & 0x000f;
858
859 if ((fragNumber & 0x0001) == 1)
860 {
861 NS_FATAL_ERROR("Fragmentation Level 3 unsupported");
862 }
863 switch (fragNumber)
864 {
865 case 0:
866 SetType({m_baType.m_variant, {8}});
867 break;
868 case 4:
869 SetType({m_baType.m_variant, {32}});
870 break;
871 case 8:
872 SetType({m_baType.m_variant, {64}});
873 break;
874 case 10:
875 SetType({m_baType.m_variant, {128}});
876 break;
877 default:
878 NS_ABORT_MSG("Unsupported fragment number: " << fragNumber);
879 }
880 }
882 {
883 uint16_t fragNumber = seqControl & 0x000f;
884
885 if ((fragNumber & 0x0001) == 1)
886 {
887 NS_FATAL_ERROR("Fragmentation Level 3 unsupported");
888 }
889 uint8_t bitmapLen = 0;
890 switch (fragNumber)
891 {
892 case 0:
893 bitmapLen = 8;
894 break;
895 case 2:
896 bitmapLen = 16;
897 break;
898 case 4:
899 bitmapLen = 32;
900 break;
901 case 6:
902 bitmapLen = 4;
903 break;
904 case 8:
905 bitmapLen = 64;
906 break;
907 case 10:
908 bitmapLen = 128;
909 break;
910 default:
911 NS_ABORT_MSG("Unsupported fragment number: " << fragNumber);
912 }
913 m_baType.m_bitmapLen[index] = bitmapLen;
914 m_baInfo[index].m_bitmap.assign(bitmapLen, 0);
915 }
916
917 m_baInfo[index].m_startingSeq = (seqControl >> 4) & 0x0fff;
918}
919
922{
924 "index can only be non null for Multi-STA Block Ack");
925 NS_ASSERT(index < m_baInfo.size());
926
927 Buffer::Iterator i = start;
928 switch (m_baType.m_variant)
929 {
935 for (const auto& byte : m_baInfo[index].m_bitmap)
936 {
937 i.WriteU8(byte);
938 }
939 break;
941 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
942 break;
943 default:
944 NS_FATAL_ERROR("Invalid BA type");
945 break;
946 }
947 return i;
948}
949
952{
954 "index can only be non null for Multi-STA Block Ack");
955 NS_ASSERT(index < m_baInfo.size());
956
957 Buffer::Iterator i = start;
958 switch (m_baType.m_variant)
959 {
965 for (uint8_t j = 0; j < m_baType.m_bitmapLen[index]; j++)
966 {
967 m_baInfo[index].m_bitmap[j] = i.ReadU8();
968 }
969 break;
971 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
972 break;
973 default:
974 NS_FATAL_ERROR("Invalid BA type");
975 break;
976 }
977 return i;
978}
979
980void
981CtrlBAckResponseHeader::SetReceivedPacket(uint16_t seq, std::size_t index)
982{
984 "index can only be non null for Multi-STA Block Ack");
985 NS_ASSERT(index < m_baInfo.size());
986
987 if (!IsInBitmap(seq, index))
988 {
989 return;
990 }
991 switch (m_baType.m_variant)
992 {
994 /* To set correctly basic block ack bitmap we need fragment number too.
995 So if it's not specified, we consider packet not fragmented. */
996 m_baInfo[index].m_bitmap[IndexInBitmap(seq) * 2] |= 0x01;
997 break;
1000 case BlockAckType::GCR:
1002 uint16_t i = IndexInBitmap(seq, index);
1003 m_baInfo[index].m_bitmap[i / 8] |= (uint8_t(0x01) << (i % 8));
1004 break;
1005 }
1007 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
1008 break;
1009 default:
1010 NS_FATAL_ERROR("Invalid BA type");
1011 break;
1012 }
1013}
1014
1015void
1017{
1018 NS_ASSERT(frag < 16);
1019 if (!IsInBitmap(seq))
1020 {
1021 return;
1022 }
1023 switch (m_baType.m_variant)
1024 {
1026 m_baInfo[0].m_bitmap[IndexInBitmap(seq) * 2 + frag / 8] |= (0x01 << (frag % 8));
1027 break;
1030 case BlockAckType::GCR:
1032 /* We can ignore this...compressed block ack doesn't support
1033 acknowledgment of single fragments */
1034 break;
1036 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
1037 break;
1038 default:
1039 NS_FATAL_ERROR("Invalid BA type");
1040 break;
1041 }
1042}
1043
1044bool
1045CtrlBAckResponseHeader::IsPacketReceived(uint16_t seq, std::size_t index) const
1046{
1048 "index can only be non null for Multi-STA Block Ack");
1049 NS_ASSERT(index < m_baInfo.size());
1050
1052 GetTidInfo(index) == 14)
1053 {
1054 // All-ack context
1055 return true;
1056 }
1057 if (!IsInBitmap(seq, index))
1058 {
1059 return false;
1060 }
1061 switch (m_baType.m_variant)
1062 {
1064 /*It's impossible to say if an entire packet was correctly received. */
1065 return false;
1068 case BlockAckType::GCR:
1070 uint16_t i = IndexInBitmap(seq, index);
1071 uint8_t mask = uint8_t(0x01) << (i % 8);
1072 return (m_baInfo[index].m_bitmap[i / 8] & mask) != 0;
1073 }
1075 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
1076 break;
1077 default:
1078 NS_FATAL_ERROR("Invalid BA type");
1079 break;
1080 }
1081 return false;
1082}
1083
1084bool
1085CtrlBAckResponseHeader::IsFragmentReceived(uint16_t seq, uint8_t frag) const
1086{
1087 NS_ASSERT(frag < 16);
1088 if (!IsInBitmap(seq))
1089 {
1090 return false;
1091 }
1092 switch (m_baType.m_variant)
1093 {
1095 return (m_baInfo[0].m_bitmap[IndexInBitmap(seq) * 2 + frag / 8] & (0x01 << (frag % 8))) !=
1096 0;
1099 case BlockAckType::GCR:
1101 /* We can ignore this...compressed block ack doesn't support
1102 acknowledgement of single fragments */
1103 return false;
1105 NS_FATAL_ERROR("Multi-tid block ack is not supported.");
1106 break;
1107 }
1108 default: {
1109 NS_FATAL_ERROR("Invalid BA type");
1110 break;
1111 }
1112 }
1113 return false;
1114}
1115
1116uint16_t
1117CtrlBAckResponseHeader::IndexInBitmap(uint16_t seq, std::size_t index) const
1118{
1119 uint16_t i;
1120 if (seq >= m_baInfo[index].m_startingSeq)
1121 {
1122 i = seq - m_baInfo[index].m_startingSeq;
1123 }
1124 else
1125 {
1126 i = SEQNO_SPACE_SIZE - m_baInfo[index].m_startingSeq + seq;
1127 }
1128
1129 uint16_t nAckedMpdus = m_baType.m_bitmapLen[index] * 8;
1130
1132 {
1133 nAckedMpdus = nAckedMpdus / 16;
1134 }
1135
1136 NS_ASSERT(i < nAckedMpdus);
1137 return i;
1138}
1139
1140bool
1141CtrlBAckResponseHeader::IsInBitmap(uint16_t seq, std::size_t index) const
1142{
1144 "index can only be non null for Multi-STA Block Ack");
1145 NS_ASSERT(index < m_baType.m_bitmapLen.size());
1146
1147 uint16_t nAckedMpdus = m_baType.m_bitmapLen[index] * 8;
1148
1150 {
1151 nAckedMpdus = nAckedMpdus / 16;
1152 }
1153
1154 return (seq - m_baInfo[index].m_startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE <
1155 nAckedMpdus;
1156}
1157
1158const std::vector<uint8_t>&
1160{
1162 "index can only be non null for Multi-STA Block Ack");
1163 NS_ASSERT(index < m_baInfo.size());
1164
1165 return m_baInfo[index].m_bitmap;
1166}
1167
1168void
1170{
1172 "index can only be non null for Multi-STA Block Ack");
1173 NS_ASSERT(index < m_baInfo.size());
1174
1175 m_baInfo[index].m_bitmap.assign(m_baType.m_bitmapLen[index], 0);
1176}
1177
1178/***********************************
1179 * Trigger frame - User Info field
1180 ***********************************/
1181
1183 TriggerFrameVariant variant)
1184 : m_variant(variant),
1185 m_aid12(0),
1186 m_ruAllocation(0),
1187 m_ulFecCodingType(false),
1188 m_ulMcs(0),
1189 m_ulDcm(false),
1190 m_ps160(true),
1191 m_ulTargetRssi(0),
1192 m_triggerType(triggerType),
1193 m_basicTriggerDependentUserInfo(0)
1194{
1195 memset(&m_bits26To31, 0, sizeof(m_bits26To31));
1196}
1197
1201
1204{
1205 NS_ABORT_MSG_IF(m_triggerType != userInfo.m_triggerType, "Trigger Frame type mismatch");
1206
1207 // check for self-assignment
1208 if (&userInfo == this)
1209 {
1210 return *this;
1211 }
1212
1213 m_variant = userInfo.m_variant;
1214 m_aid12 = userInfo.m_aid12;
1215 m_ruAllocation = userInfo.m_ruAllocation;
1217 m_ulMcs = userInfo.m_ulMcs;
1218 m_ulDcm = userInfo.m_ulDcm;
1219 m_ps160 = userInfo.m_ps160;
1220 m_bits26To31 = userInfo.m_bits26To31;
1221 m_ulTargetRssi = userInfo.m_ulTargetRssi;
1224 return *this;
1225}
1226
1227void
1228CtrlTriggerUserInfoField::Print(std::ostream& os) const
1229{
1230 os << ", USER_INFO " << (m_variant == TriggerFrameVariant::HE ? "HE" : "EHT")
1231 << " variant AID=" << m_aid12 << ", RU_Allocation=" << +m_ruAllocation
1232 << ", MCS=" << +m_ulMcs;
1233}
1234
1237{
1238 uint32_t size = 0;
1239 size += 5; // User Info (excluding Trigger Dependent User Info)
1240
1241 switch (m_triggerType)
1242 {
1245 size += 1;
1246 break;
1248 size +=
1249 m_muBarTriggerDependentUserInfo.GetSerializedSize(); // BAR Control and BAR Information
1250 break;
1251 default:;
1252 // The Trigger Dependent User Info subfield is not present in the other variants
1253 }
1254
1255 return size;
1256}
1257
1260{
1262 "BFRP Trigger frame is not supported");
1264 "GCR-MU-BAR Trigger frame is not supported");
1266 "NFRP Trigger frame is not supported");
1267
1268 Buffer::Iterator i = start;
1269
1270 uint32_t userInfo = 0; // User Info except the MSB
1271 userInfo |= (m_aid12 & 0x0fff);
1272 userInfo |= (m_ruAllocation << 12);
1273 userInfo |= (m_ulFecCodingType ? 1 << 20 : 0);
1274 userInfo |= (m_ulMcs & 0x0f) << 21;
1276 {
1277 userInfo |= (m_ulDcm ? 1 << 25 : 0);
1278 }
1279
1280 if (m_aid12 != 0 && m_aid12 != 2045)
1281 {
1282 userInfo |= (m_bits26To31.ssAllocation.startingSs & 0x07) << 26;
1283 userInfo |= (m_bits26To31.ssAllocation.nSs & 0x07) << 29;
1284 }
1285 else
1286 {
1287 userInfo |= (m_bits26To31.raRuInformation.nRaRu & 0x1f) << 26;
1288 userInfo |= (m_bits26To31.raRuInformation.moreRaRu ? 1 << 31 : 0);
1289 }
1290
1291 i.WriteHtolsbU32(userInfo);
1292 // Here we need to write 8 bits covering the UL Target RSSI (7 bits) and B39, which is
1293 // reserved in the HE variant and the PS160 subfield in the EHT variant.
1294 uint8_t bit32To39 = m_ulTargetRssi;
1296 {
1297 bit32To39 |= (m_ps160 ? 1 << 7 : 0);
1298 }
1299
1300 i.WriteU8(bit32To39);
1301
1303 {
1305 }
1307 {
1310 }
1311
1312 return i;
1313}
1314
1317{
1319 "BFRP Trigger frame is not supported");
1321 "GCR-MU-BAR Trigger frame is not supported");
1323 "NFRP Trigger frame is not supported");
1324
1325 Buffer::Iterator i = start;
1326
1327 uint32_t userInfo = i.ReadLsbtohU32();
1328
1329 m_aid12 = userInfo & 0x0fff;
1330 NS_ABORT_MSG_IF(m_aid12 == 4095, "Cannot deserialize a Padding field");
1331 m_ruAllocation = (userInfo >> 12) & 0xff;
1332 m_ulFecCodingType = (userInfo >> 20) & 0x01;
1333 m_ulMcs = (userInfo >> 21) & 0x0f;
1335 {
1336 m_ulDcm = (userInfo >> 25) & 0x01;
1337 }
1338
1339 if (m_aid12 != 0 && m_aid12 != 2045)
1340 {
1341 m_bits26To31.ssAllocation.startingSs = (userInfo >> 26) & 0x07;
1342 m_bits26To31.ssAllocation.nSs = (userInfo >> 29) & 0x07;
1343 }
1344 else
1345 {
1346 m_bits26To31.raRuInformation.nRaRu = (userInfo >> 26) & 0x1f;
1347 m_bits26To31.raRuInformation.moreRaRu = (userInfo >> 31) & 0x01;
1348 }
1349
1350 uint8_t bit32To39 = i.ReadU8();
1351 m_ulTargetRssi = bit32To39 & 0x7f; // B39 is reserved in HE variant
1353 {
1354 m_ps160 = (bit32To39 >> 7) == 1;
1355 }
1356
1358 {
1360 }
1362 {
1364 i.Next(len);
1365 }
1366
1367 return i;
1368}
1369
1372{
1373 return m_triggerType;
1374}
1375
1378{
1379 switch (m_variant)
1380 {
1382 return WIFI_PREAMBLE_HE_TB;
1384 return WIFI_PREAMBLE_EHT_TB;
1385 default:
1386 NS_ABORT_MSG("Unexpected variant: " << +static_cast<uint8_t>(m_variant));
1387 }
1388 return WIFI_PREAMBLE_LONG; // to silence warning
1389}
1390
1391void
1393{
1394 m_aid12 = aid & 0x0fff;
1395}
1396
1397uint16_t
1399{
1400 return m_aid12;
1401}
1402
1403bool
1405{
1406 return (m_aid12 == 0);
1407}
1408
1409bool
1411{
1412 return (m_aid12 == 2045);
1413}
1414
1415void
1417{
1418 NS_ASSERT_MSG(WifiRu::IsHe(ru), "EHT RUs not supported yet");
1419 const auto ruIndex = WifiRu::GetIndex(ru);
1420 const auto ruType = WifiRu::GetRuType(ru);
1421 NS_ABORT_MSG_IF(ruIndex == 0, "Valid indices start at 1");
1423 "SetMuRtsRuAllocation() must be used for MU-RTS");
1424
1425 switch (ruType)
1426 {
1427 case RuType::RU_26_TONE:
1428 m_ruAllocation = ruIndex - 1;
1429 break;
1430 case RuType::RU_52_TONE:
1431 m_ruAllocation = ruIndex + 36;
1432 break;
1434 m_ruAllocation = ruIndex + 52;
1435 break;
1437 m_ruAllocation = ruIndex + 60;
1438 break;
1440 m_ruAllocation = ruIndex + 64;
1441 break;
1443 m_ruAllocation = 67;
1444 break;
1446 m_ruAllocation = 68;
1447 break;
1448 default:
1449 NS_FATAL_ERROR("RU type unknown.");
1450 break;
1451 }
1452
1453 NS_ABORT_MSG_IF(m_ruAllocation > 68, "Reserved value.");
1454
1455 m_ruAllocation <<= 1;
1456 if (WifiRu::IsHe(ru) && !std::get<HeRu::RuSpec>(ru).GetPrimary80MHz())
1457 {
1459 }
1460}
1461
1464{
1466 "GetMuRtsRuAllocation() must be used for MU-RTS");
1467
1468 RuType ruType;
1469 std::size_t index;
1470
1471 bool primary80MHz = ((m_ruAllocation & 0x01) == 0);
1472
1473 uint8_t val = m_ruAllocation >> 1;
1474
1475 if (val < 37)
1476 {
1477 ruType = RuType::RU_26_TONE;
1478 index = val + 1;
1479 }
1480 else if (val < 53)
1481 {
1482 ruType = RuType::RU_52_TONE;
1483 index = val - 36;
1484 }
1485 else if (val < 61)
1486 {
1487 ruType = RuType::RU_106_TONE;
1488 index = val - 52;
1489 }
1490 else if (val < 65)
1491 {
1492 ruType = RuType::RU_242_TONE;
1493 index = val - 60;
1494 }
1495 else if (val < 67)
1496 {
1497 ruType = RuType::RU_484_TONE;
1498 index = val - 64;
1499 }
1500 else if (val == 67)
1501 {
1502 ruType = RuType::RU_996_TONE;
1503 index = 1;
1504 }
1505 else if (val == 68)
1506 {
1507 ruType = RuType::RU_2x996_TONE;
1508 index = 1;
1509 }
1510 else
1511 {
1512 NS_FATAL_ERROR("Reserved value.");
1513 }
1514
1515 return HeRu::RuSpec{ruType, index, primary80MHz};
1516}
1517
1518void
1520{
1522 "SetMuRtsRuAllocation() can only be used for MU-RTS");
1524 value < 61 || value > 68,
1525 "Value "
1526 << +value
1527 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1528
1529 m_ruAllocation = (value << 1);
1530 if (value == 68)
1531 {
1532 // set B0 for 160 MHz and 80+80 MHz indication
1534 }
1535}
1536
1537uint8_t
1539{
1541 "GetMuRtsRuAllocation() can only be used for MU-RTS");
1542 uint8_t value = (m_ruAllocation >> 1);
1544 value < 61 || value > 68,
1545 "Value "
1546 << +value
1547 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1548 return value;
1549}
1550
1551void
1556
1557bool
1562
1563void
1565{
1566 uint8_t maxMcs = m_variant == TriggerFrameVariant::EHT ? 13 : 11;
1567 NS_ABORT_MSG_IF(mcs > maxMcs, "Invalid MCS index");
1568 m_ulMcs = mcs;
1569}
1570
1571uint8_t
1573{
1574 return m_ulMcs;
1575}
1576
1577void
1579{
1580 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1581 m_ulDcm = dcm;
1582}
1583
1584bool
1586{
1587 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1588 return m_ulDcm;
1589}
1590
1591void
1592CtrlTriggerUserInfoField::SetSsAllocation(uint8_t startingSs, uint8_t nSs)
1593{
1594 NS_ABORT_MSG_IF(m_aid12 == 0 || m_aid12 == 2045, "SS Allocation subfield not present");
1595 NS_ABORT_MSG_IF(!startingSs || startingSs > 8, "Starting SS must be from 1 to 8");
1596 NS_ABORT_MSG_IF(!nSs || nSs > 8, "Number of SS must be from 1 to 8");
1597
1598 m_bits26To31.ssAllocation.startingSs = startingSs - 1;
1599 m_bits26To31.ssAllocation.nSs = nSs - 1;
1600}
1601
1602uint8_t
1604{
1605 if (m_aid12 == 0 || m_aid12 == 2045)
1606 {
1607 return 1;
1608 }
1609 return m_bits26To31.ssAllocation.startingSs + 1;
1610}
1611
1612uint8_t
1614{
1615 if (m_aid12 == 0 || m_aid12 == 2045)
1616 {
1617 return 1;
1618 }
1619 return m_bits26To31.ssAllocation.nSs + 1;
1620}
1621
1622void
1624{
1625 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1626 NS_ABORT_MSG_IF(!nRaRu || nRaRu > 32, "Number of contiguous RA-RUs must be from 1 to 32");
1627
1628 m_bits26To31.raRuInformation.nRaRu = nRaRu - 1;
1629 m_bits26To31.raRuInformation.moreRaRu = moreRaRu;
1630}
1631
1632uint8_t
1634{
1635 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1636
1637 return m_bits26To31.raRuInformation.nRaRu + 1;
1638}
1639
1640bool
1642{
1643 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1644
1645 return m_bits26To31.raRuInformation.moreRaRu;
1646}
1647
1648void
1650{
1651 m_ulTargetRssi = 127; // see Table 9-25i of 802.11ax amendment D3.0
1652}
1653
1654void
1656{
1657 NS_ABORT_MSG_IF(dBm < -110 || dBm > -20, "Invalid values for signal power");
1658
1659 m_ulTargetRssi = static_cast<uint8_t>(110 + dBm);
1660}
1661
1662bool
1667
1668int8_t
1670{
1671 NS_ABORT_MSG_IF(m_ulTargetRssi == 127, "STA must use its max TX power");
1672
1673 return static_cast<int8_t>(m_ulTargetRssi) - 110;
1674}
1675
1676void
1678 uint8_t tidLimit,
1679 AcIndex prefAc)
1680{
1681 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1682
1683 m_basicTriggerDependentUserInfo = (spacingFactor & 0x03) |
1684 (tidLimit & 0x07) << 2
1685 // B5 is reserved
1686 | (prefAc & 0x03) << 6;
1687}
1688
1689uint8_t
1696
1697uint8_t
1699{
1700 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1701
1702 return (m_basicTriggerDependentUserInfo & 0x1c) >> 2;
1703}
1704
1705AcIndex
1707{
1708 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1709
1710 return AcIndex((m_basicTriggerDependentUserInfo & 0xc0) >> 6);
1711}
1712
1713void
1715{
1717 "Not a MU-BAR Trigger frame");
1720 "BAR Control indicates it is neither the Compressed nor the Multi-TID variant");
1722}
1723
1732
1733/***********************************
1734 * Trigger frame
1735 ***********************************/
1736
1738
1740 : m_variant(TriggerFrameVariant::HE),
1741 m_triggerType(TriggerFrameType::BASIC_TRIGGER),
1742 m_ulLength(0),
1743 m_moreTF(false),
1744 m_csRequired(false),
1745 m_ulBandwidth(0),
1746 m_giAndLtfType(0),
1747 m_apTxPower(0),
1748 m_ulSpatialReuse(0),
1749 m_padding(0)
1750{
1751}
1752
1755{
1757 "This constructor cannot be used for MU-RTS");
1758
1759 switch (txVector.GetPreambleType())
1760 {
1763 break;
1766 break;
1767 default:
1768 NS_ABORT_MSG("Cannot create a TF out of a TXVECTOR with preamble type: "
1769 << txVector.GetPreambleType());
1770 }
1771
1772 m_triggerType = type;
1773 SetUlBandwidth(txVector.GetChannelWidth());
1774 SetUlLength(txVector.GetLength());
1775 const auto gi = txVector.GetGuardInterval().GetNanoSeconds();
1776 if ((gi == 800) || (gi == 1600))
1777 {
1778 m_giAndLtfType = 1;
1779 }
1780 else
1781 {
1782 m_giAndLtfType = 2;
1783 }
1784 for (auto& userInfo : txVector.GetHeMuUserInfoMap())
1785 {
1787 ui.SetAid12(userInfo.first);
1788 ui.SetRuAllocation(userInfo.second.ru);
1789 ui.SetUlMcs(userInfo.second.mcs);
1790 ui.SetSsAllocation(1, userInfo.second.nss); // MU-MIMO is not supported
1791 }
1792}
1793
1797
1800{
1801 // check for self-assignment
1802 if (&trigger == this)
1803 {
1804 return *this;
1805 }
1806
1807 m_variant = trigger.m_variant;
1808 m_triggerType = trigger.m_triggerType;
1809 m_ulLength = trigger.m_ulLength;
1810 m_moreTF = trigger.m_moreTF;
1811 m_csRequired = trigger.m_csRequired;
1812 m_ulBandwidth = trigger.m_ulBandwidth;
1814 m_apTxPower = trigger.m_apTxPower;
1816 m_padding = trigger.m_padding;
1817 m_userInfoFields.clear();
1819 return *this;
1820}
1821
1822TypeId
1824{
1825 static TypeId tid = TypeId("ns3::CtrlTriggerHeader")
1826 .SetParent<Header>()
1827 .SetGroupName("Wifi")
1828 .AddConstructor<CtrlTriggerHeader>();
1829 return tid;
1830}
1831
1832TypeId
1834{
1835 return GetTypeId();
1836}
1837
1838void
1839CtrlTriggerHeader::Print(std::ostream& os) const
1840{
1841 os << "TriggerType=" << GetTypeString() << ", Bandwidth=" << +GetUlBandwidth()
1842 << ", UL Length=" << m_ulLength;
1843
1844 for (auto& ui : m_userInfoFields)
1845 {
1846 ui.Print(os);
1847 }
1848}
1849
1850void
1852{
1854 "Cannot change Common Info field variant if User Info fields are present");
1855 m_variant = variant;
1856}
1857
1860{
1861 return m_variant;
1862}
1863
1866{
1867 uint32_t size = 0;
1868 size += 8; // Common Info (excluding Trigger Dependent Common Info)
1869
1870 // Add the size of the Trigger Dependent Common Info subfield
1872 {
1873 size += 4;
1874 }
1875
1876 for (auto& ui : m_userInfoFields)
1877 {
1878 size += ui.GetSerializedSize();
1879 }
1880
1881 size += m_padding;
1882
1883 return size;
1884}
1885
1886void
1888{
1890 "BFRP Trigger frame is not supported");
1892 "GCR-MU-BAR Trigger frame is not supported");
1894 "NFRP Trigger frame is not supported");
1895
1896 Buffer::Iterator i = start;
1897
1898 uint64_t commonInfo = 0;
1899 commonInfo |= (static_cast<uint8_t>(m_triggerType) & 0x0f);
1900 commonInfo |= (m_ulLength & 0x0fff) << 4;
1901 commonInfo |= (m_moreTF ? 1 << 16 : 0);
1902 commonInfo |= (m_csRequired ? 1 << 17 : 0);
1903 commonInfo |= (m_ulBandwidth & 0x03) << 18;
1904 commonInfo |= (m_giAndLtfType & 0x03) << 20;
1905 commonInfo |= static_cast<uint64_t>(m_apTxPower & 0x3f) << 28;
1906 commonInfo |= static_cast<uint64_t>(m_ulSpatialReuse) << 37;
1908 {
1909 uint64_t ulHeSigA2 = 0x01ff; // nine bits equal to 1
1910 commonInfo |= ulHeSigA2 << 54;
1911 }
1912
1913 i.WriteHtolsbU64(commonInfo);
1914
1915 for (auto& ui : m_userInfoFields)
1916 {
1917 i = ui.Serialize(i);
1918 }
1919
1920 for (std::size_t count = 0; count < m_padding; count++)
1921 {
1922 i.WriteU8(0xff); // Padding field
1923 }
1924}
1925
1928{
1929 Buffer::Iterator i = start;
1930
1931 uint64_t commonInfo = i.ReadLsbtohU64();
1932
1933 m_triggerType = static_cast<TriggerFrameType>(commonInfo & 0x0f);
1934 m_ulLength = (commonInfo >> 4) & 0x0fff;
1935 m_moreTF = (commonInfo >> 16) & 0x01;
1936 m_csRequired = (commonInfo >> 17) & 0x01;
1937 m_ulBandwidth = (commonInfo >> 18) & 0x03;
1938 m_giAndLtfType = (commonInfo >> 20) & 0x03;
1939 m_apTxPower = (commonInfo >> 28) & 0x3f;
1940 m_ulSpatialReuse = (commonInfo >> 37) & 0xffff;
1941 uint8_t bit54and55 = (commonInfo >> 54) & 0x03;
1943 m_userInfoFields.clear();
1944 m_padding = 0;
1945
1947 "BFRP Trigger frame is not supported");
1949 "GCR-MU-BAR Trigger frame is not supported");
1951 "NFRP Trigger frame is not supported");
1952
1953 while (i.GetRemainingSize() >= 2)
1954 {
1955 // read the first 2 bytes to check if we encountered the Padding field
1956 if (i.ReadU16() == 0xffff)
1957 {
1958 m_padding = i.GetRemainingSize() + 2;
1959 }
1960 else
1961 {
1962 // go back 2 bytes to deserialize the User Info field from the beginning
1963 i.Prev(2);
1965 i = ui.Deserialize(i);
1966 }
1967 }
1968
1969 return i.GetDistanceFrom(start);
1970}
1971
1972void
1977
1980{
1981 return m_triggerType;
1982}
1983
1984const char*
1986{
1987 return GetTypeString(GetType());
1988}
1989
1990const char*
1992{
1993#define FOO(x) \
1994 case TriggerFrameType::x: \
1995 return #x;
1996
1997 switch (type)
1998 {
2007 default:
2008 return "ERROR";
2009 }
2010#undef FOO
2011}
2012
2013bool
2018
2019bool
2024
2025bool
2030
2031bool
2036
2037bool
2042
2043bool
2048
2049bool
2054
2055bool
2060
2061void
2063{
2064 m_ulLength = (len & 0x0fff);
2065}
2066
2067uint16_t
2069{
2070 return m_ulLength;
2071}
2072
2075{
2077 "GetHeTbTxVector() cannot be used for MU-RTS");
2078 auto userInfoIt = FindUserInfoWithAid(staId);
2079 NS_ASSERT(userInfoIt != end());
2080
2081 WifiTxVector v;
2082 v.SetPreambleType(userInfoIt->GetPreambleType());
2087 staId,
2088 {userInfoIt->GetRuAllocation(), userInfoIt->GetUlMcs(), userInfoIt->GetNss()});
2089 return v;
2090}
2091
2092void
2094{
2095 m_moreTF = more;
2096}
2097
2098bool
2100{
2101 return m_moreTF;
2102}
2103
2104void
2106{
2107 m_csRequired = cs;
2108}
2109
2110bool
2112{
2113 return m_csRequired;
2114}
2115
2116void
2118{
2119 switch (static_cast<uint16_t>(bw))
2120 {
2121 case 20:
2122 m_ulBandwidth = 0;
2123 break;
2124 case 40:
2125 m_ulBandwidth = 1;
2126 break;
2127 case 80:
2128 m_ulBandwidth = 2;
2129 break;
2130 case 160:
2131 m_ulBandwidth = 3;
2132 break;
2133 default:
2134 NS_FATAL_ERROR("Bandwidth value not allowed.");
2135 break;
2136 }
2137}
2138
2139MHz_u
2141{
2142 return (1 << m_ulBandwidth) * MHz_u{20};
2143}
2144
2145void
2146CtrlTriggerHeader::SetGiAndLtfType(Time guardInterval, uint8_t ltfType)
2147{
2148 const auto gi = guardInterval.GetNanoSeconds();
2149 if ((ltfType == 1) && (gi == 1600))
2150 {
2151 m_giAndLtfType = 0;
2152 }
2153 else if ((ltfType == 2) && (gi == 1600))
2154 {
2155 m_giAndLtfType = 1;
2156 }
2157 else if ((ltfType == 4) && (gi == 3200))
2158 {
2159 m_giAndLtfType = 2;
2160 }
2161 else
2162 {
2163 NS_FATAL_ERROR("Invalid combination of GI and LTF type");
2164 }
2165}
2166
2167Time
2169{
2170 if (m_giAndLtfType == 0 || m_giAndLtfType == 1)
2171 {
2172 return NanoSeconds(1600);
2173 }
2174 else if (m_giAndLtfType == 2)
2175 {
2176 return NanoSeconds(3200);
2177 }
2178 else
2179 {
2180 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2181 }
2182}
2183
2184uint8_t
2186{
2187 if (m_giAndLtfType == 0)
2188 {
2189 return 1;
2190 }
2191 else if (m_giAndLtfType == 1)
2192 {
2193 return 2;
2194 }
2195 else if (m_giAndLtfType == 2)
2196 {
2197 return 4;
2198 }
2199 else
2200 {
2201 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2202 }
2203}
2204
2205void
2207{
2208 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2209 NS_ABORT_MSG_IF(power < -20 || power > 40, "Out of range power values");
2210
2211 m_apTxPower = static_cast<uint8_t>(power + 20);
2212}
2213
2214int8_t
2216{
2217 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2218 return static_cast<int8_t>(m_apTxPower) - 20;
2219}
2220
2221void
2223{
2224 m_ulSpatialReuse = sr;
2225}
2226
2227uint16_t
2232
2233void
2235{
2236 NS_ABORT_MSG_IF(size == 1, "The Padding field, if present, shall be at least two octets");
2237 m_padding = size;
2238}
2239
2240std::size_t
2242{
2243 return m_padding;
2244}
2245
2248{
2249 // make a copy of this Trigger Frame and remove the User Info fields from the copy
2250 CtrlTriggerHeader trigger(*this);
2251 trigger.m_userInfoFields.clear();
2252 return trigger;
2253}
2254
2261
2264{
2266 userInfo.GetType() != m_triggerType,
2267 "Trying to add a User Info field of a type other than the type of the Trigger Frame");
2268 m_userInfoFields.push_back(userInfo);
2269 return m_userInfoFields.back();
2270}
2271
2274{
2275 return m_userInfoFields.erase(userInfoIt);
2276}
2277
2280{
2281 return m_userInfoFields.begin();
2282}
2283
2286{
2287 return m_userInfoFields.end();
2288}
2289
2292{
2293 return m_userInfoFields.begin();
2294}
2295
2298{
2299 return m_userInfoFields.end();
2300}
2301
2302std::size_t
2304{
2305 return m_userInfoFields.size();
2306}
2307
2310{
2311 // the lambda function returns true if a User Info field has the AID12 subfield
2312 // equal to the given aid12 value
2313 return std::find_if(start, end(), [aid12](const CtrlTriggerUserInfoField& ui) -> bool {
2314 return (ui.GetAid12() == aid12);
2315 });
2316}
2317
2320{
2321 return FindUserInfoWithAid(m_userInfoFields.begin(), aid12);
2322}
2323
2329
2335
2341
2347
2348bool
2350{
2352 {
2353 return true;
2354 }
2355
2356 // check that allocated RUs do not overlap
2357 // TODO This is not a problem in case of UL MU-MIMO
2358 std::vector<WifiRu::RuSpec> prevRus;
2359 for (auto& ui : m_userInfoFields)
2360 {
2361 if (WifiRu::DoesOverlap(GetUlBandwidth(), ui.GetRuAllocation(), prevRus))
2362 {
2363 return false;
2364 }
2365 prevRus.push_back(ui.GetRuAllocation());
2366 }
2367 return true;
2368}
2369
2370} // 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).
void Print(std::ostream &os) const override
Mac48Address GetGcrGroupAddress() const
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
BlockAckReqType m_barType
BAR type.
Mac48Address m_gcrAddress
GCR Group Address (GCR variant only)
void SetStartingSequenceControl(uint16_t seqControl)
Set the starting sequence control with the given sequence control value.
BlockAckReqType GetType() const
Return the BlockAckRequest type.
void SetHtImmediateAck(bool immediateAck)
Enable or disable HT immediate Ack.
uint32_t Deserialize(Buffer::Iterator start) override
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.
void SetGcrGroupAddress(const Mac48Address &address)
Set the GCR Group address (GCR variant only).
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.
Headers for BlockAck response.
void SetBaControl(uint16_t ba)
Set the Block Ack control.
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
void SetGcrGroupAddress(const Mac48Address &address)
Set the GCR Group address (GCR variant only).
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...
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...
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...
Mac48Address GetGcrGroupAddress() const
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.
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 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.
Iterator RemoveUserInfoField(ConstIterator userInfoIt)
Remove a User Info field from the Trigger Frame.
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,...
WifiRu::RuSpec GetRuAllocation() const
Get the RU specified by the RU Allocation subfield.
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.
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.
void SetRuAllocation(WifiRu::RuSpec ru)
Set the RU Allocation subfield according to the specified RU.
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 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:37
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:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
static bool IsHe(RuSpec ru)
Get whether a given RU variant is a HE RU.
Definition wifi-ru.cc:248
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
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 wifi-ru.cc:207
static std::size_t GetIndex(RuSpec ru)
Get the index of a given RU.
Definition wifi-ru.cc:51
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:1381
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.
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:98
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:265
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...