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_ABORT_MSG_IF(ru.GetIndex() == 0, "Valid indices start at 1");
1420 "SetMuRtsRuAllocation() must be used for MU-RTS");
1421
1422 switch (ru.GetRuType())
1423 {
1424 case HeRu::RU_26_TONE:
1425 m_ruAllocation = ru.GetIndex() - 1;
1426 break;
1427 case HeRu::RU_52_TONE:
1428 m_ruAllocation = ru.GetIndex() + 36;
1429 break;
1430 case HeRu::RU_106_TONE:
1431 m_ruAllocation = ru.GetIndex() + 52;
1432 break;
1433 case HeRu::RU_242_TONE:
1434 m_ruAllocation = ru.GetIndex() + 60;
1435 break;
1436 case HeRu::RU_484_TONE:
1437 m_ruAllocation = ru.GetIndex() + 64;
1438 break;
1439 case HeRu::RU_996_TONE:
1440 m_ruAllocation = 67;
1441 break;
1443 m_ruAllocation = 68;
1444 break;
1445 default:
1446 NS_FATAL_ERROR("RU type unknown.");
1447 break;
1448 }
1449
1450 NS_ABORT_MSG_IF(m_ruAllocation > 68, "Reserved value.");
1451
1452 m_ruAllocation <<= 1;
1453 if (!ru.GetPrimary80MHz())
1454 {
1456 }
1457}
1458
1461{
1463 "GetMuRtsRuAllocation() must be used for MU-RTS");
1464
1465 HeRu::RuType ruType;
1466 std::size_t index;
1467
1468 bool primary80MHz = ((m_ruAllocation & 0x01) == 0);
1469
1470 uint8_t val = m_ruAllocation >> 1;
1471
1472 if (val < 37)
1473 {
1474 ruType = HeRu::RU_26_TONE;
1475 index = val + 1;
1476 }
1477 else if (val < 53)
1478 {
1479 ruType = HeRu::RU_52_TONE;
1480 index = val - 36;
1481 }
1482 else if (val < 61)
1483 {
1484 ruType = HeRu::RU_106_TONE;
1485 index = val - 52;
1486 }
1487 else if (val < 65)
1488 {
1489 ruType = HeRu::RU_242_TONE;
1490 index = val - 60;
1491 }
1492 else if (val < 67)
1493 {
1494 ruType = HeRu::RU_484_TONE;
1495 index = val - 64;
1496 }
1497 else if (val == 67)
1498 {
1499 ruType = HeRu::RU_996_TONE;
1500 index = 1;
1501 }
1502 else if (val == 68)
1503 {
1504 ruType = HeRu::RU_2x996_TONE;
1505 index = 1;
1506 }
1507 else
1508 {
1509 NS_FATAL_ERROR("Reserved value.");
1510 }
1511
1512 return HeRu::RuSpec(ruType, index, primary80MHz);
1513}
1514
1515void
1517{
1519 "SetMuRtsRuAllocation() can only be used for MU-RTS");
1521 value < 61 || value > 68,
1522 "Value "
1523 << +value
1524 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1525
1526 m_ruAllocation = (value << 1);
1527 if (value == 68)
1528 {
1529 // set B0 for 160 MHz and 80+80 MHz indication
1531 }
1532}
1533
1534uint8_t
1536{
1538 "GetMuRtsRuAllocation() can only be used for MU-RTS");
1539 uint8_t value = (m_ruAllocation >> 1);
1541 value < 61 || value > 68,
1542 "Value "
1543 << +value
1544 << " is not admitted for B7-B1 of the RU Allocation subfield of MU-RTS Trigger Frames");
1545 return value;
1546}
1547
1548void
1553
1554bool
1559
1560void
1562{
1563 uint8_t maxMcs = m_variant == TriggerFrameVariant::EHT ? 13 : 11;
1564 NS_ABORT_MSG_IF(mcs > maxMcs, "Invalid MCS index");
1565 m_ulMcs = mcs;
1566}
1567
1568uint8_t
1570{
1571 return m_ulMcs;
1572}
1573
1574void
1576{
1577 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1578 m_ulDcm = dcm;
1579}
1580
1581bool
1583{
1584 NS_ASSERT_MSG(m_variant == TriggerFrameVariant::HE, "UL DCM flag only present in HE variant");
1585 return m_ulDcm;
1586}
1587
1588void
1589CtrlTriggerUserInfoField::SetSsAllocation(uint8_t startingSs, uint8_t nSs)
1590{
1591 NS_ABORT_MSG_IF(m_aid12 == 0 || m_aid12 == 2045, "SS Allocation subfield not present");
1592 NS_ABORT_MSG_IF(!startingSs || startingSs > 8, "Starting SS must be from 1 to 8");
1593 NS_ABORT_MSG_IF(!nSs || nSs > 8, "Number of SS must be from 1 to 8");
1594
1595 m_bits26To31.ssAllocation.startingSs = startingSs - 1;
1596 m_bits26To31.ssAllocation.nSs = nSs - 1;
1597}
1598
1599uint8_t
1601{
1602 if (m_aid12 == 0 || m_aid12 == 2045)
1603 {
1604 return 1;
1605 }
1606 return m_bits26To31.ssAllocation.startingSs + 1;
1607}
1608
1609uint8_t
1611{
1612 if (m_aid12 == 0 || m_aid12 == 2045)
1613 {
1614 return 1;
1615 }
1616 return m_bits26To31.ssAllocation.nSs + 1;
1617}
1618
1619void
1621{
1622 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1623 NS_ABORT_MSG_IF(!nRaRu || nRaRu > 32, "Number of contiguous RA-RUs must be from 1 to 32");
1624
1625 m_bits26To31.raRuInformation.nRaRu = nRaRu - 1;
1626 m_bits26To31.raRuInformation.moreRaRu = moreRaRu;
1627}
1628
1629uint8_t
1631{
1632 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1633
1634 return m_bits26To31.raRuInformation.nRaRu + 1;
1635}
1636
1637bool
1639{
1640 NS_ABORT_MSG_IF(m_aid12 != 0 && m_aid12 != 2045, "RA-RU Information subfield not present");
1641
1642 return m_bits26To31.raRuInformation.moreRaRu;
1643}
1644
1645void
1647{
1648 m_ulTargetRssi = 127; // see Table 9-25i of 802.11ax amendment D3.0
1649}
1650
1651void
1653{
1654 NS_ABORT_MSG_IF(dBm < -110 || dBm > -20, "Invalid values for signal power");
1655
1656 m_ulTargetRssi = static_cast<uint8_t>(110 + dBm);
1657}
1658
1659bool
1664
1665int8_t
1667{
1668 NS_ABORT_MSG_IF(m_ulTargetRssi == 127, "STA must use its max TX power");
1669
1670 return static_cast<int8_t>(m_ulTargetRssi) - 110;
1671}
1672
1673void
1675 uint8_t tidLimit,
1676 AcIndex prefAc)
1677{
1678 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1679
1680 m_basicTriggerDependentUserInfo = (spacingFactor & 0x03) |
1681 (tidLimit & 0x07) << 2
1682 // B5 is reserved
1683 | (prefAc & 0x03) << 6;
1684}
1685
1686uint8_t
1693
1694uint8_t
1696{
1697 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1698
1699 return (m_basicTriggerDependentUserInfo & 0x1c) >> 2;
1700}
1701
1702AcIndex
1704{
1705 NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::BASIC_TRIGGER, "Not a Basic Trigger Frame");
1706
1707 return AcIndex((m_basicTriggerDependentUserInfo & 0xc0) >> 6);
1708}
1709
1710void
1712{
1714 "Not a MU-BAR Trigger frame");
1717 "BAR Control indicates it is neither the Compressed nor the Multi-TID variant");
1719}
1720
1729
1730/***********************************
1731 * Trigger frame
1732 ***********************************/
1733
1735
1737 : m_variant(TriggerFrameVariant::HE),
1738 m_triggerType(TriggerFrameType::BASIC_TRIGGER),
1739 m_ulLength(0),
1740 m_moreTF(false),
1741 m_csRequired(false),
1742 m_ulBandwidth(0),
1743 m_giAndLtfType(0),
1744 m_apTxPower(0),
1745 m_ulSpatialReuse(0),
1746 m_padding(0)
1747{
1748}
1749
1752{
1754 "This constructor cannot be used for MU-RTS");
1755
1756 switch (txVector.GetPreambleType())
1757 {
1760 break;
1763 break;
1764 default:
1765 NS_ABORT_MSG("Cannot create a TF out of a TXVECTOR with preamble type: "
1766 << txVector.GetPreambleType());
1767 }
1768
1769 m_triggerType = type;
1770 SetUlBandwidth(txVector.GetChannelWidth());
1771 SetUlLength(txVector.GetLength());
1772 const auto gi = txVector.GetGuardInterval().GetNanoSeconds();
1773 if ((gi == 800) || (gi == 1600))
1774 {
1775 m_giAndLtfType = 1;
1776 }
1777 else
1778 {
1779 m_giAndLtfType = 2;
1780 }
1781 for (auto& userInfo : txVector.GetHeMuUserInfoMap())
1782 {
1784 ui.SetAid12(userInfo.first);
1785 ui.SetRuAllocation(userInfo.second.ru);
1786 ui.SetUlMcs(userInfo.second.mcs);
1787 ui.SetSsAllocation(1, userInfo.second.nss); // MU-MIMO is not supported
1788 }
1789}
1790
1794
1797{
1798 // check for self-assignment
1799 if (&trigger == this)
1800 {
1801 return *this;
1802 }
1803
1804 m_variant = trigger.m_variant;
1805 m_triggerType = trigger.m_triggerType;
1806 m_ulLength = trigger.m_ulLength;
1807 m_moreTF = trigger.m_moreTF;
1808 m_csRequired = trigger.m_csRequired;
1809 m_ulBandwidth = trigger.m_ulBandwidth;
1811 m_apTxPower = trigger.m_apTxPower;
1813 m_padding = trigger.m_padding;
1814 m_userInfoFields.clear();
1816 return *this;
1817}
1818
1819TypeId
1821{
1822 static TypeId tid = TypeId("ns3::CtrlTriggerHeader")
1823 .SetParent<Header>()
1824 .SetGroupName("Wifi")
1825 .AddConstructor<CtrlTriggerHeader>();
1826 return tid;
1827}
1828
1829TypeId
1831{
1832 return GetTypeId();
1833}
1834
1835void
1836CtrlTriggerHeader::Print(std::ostream& os) const
1837{
1838 os << "TriggerType=" << GetTypeString() << ", Bandwidth=" << +GetUlBandwidth()
1839 << ", UL Length=" << m_ulLength;
1840
1841 for (auto& ui : m_userInfoFields)
1842 {
1843 ui.Print(os);
1844 }
1845}
1846
1847void
1849{
1851 "Cannot change Common Info field variant if User Info fields are present");
1852 m_variant = variant;
1853}
1854
1857{
1858 return m_variant;
1859}
1860
1863{
1864 uint32_t size = 0;
1865 size += 8; // Common Info (excluding Trigger Dependent Common Info)
1866
1867 // Add the size of the Trigger Dependent Common Info subfield
1869 {
1870 size += 4;
1871 }
1872
1873 for (auto& ui : m_userInfoFields)
1874 {
1875 size += ui.GetSerializedSize();
1876 }
1877
1878 size += m_padding;
1879
1880 return size;
1881}
1882
1883void
1885{
1887 "BFRP Trigger frame is not supported");
1889 "GCR-MU-BAR Trigger frame is not supported");
1891 "NFRP Trigger frame is not supported");
1892
1893 Buffer::Iterator i = start;
1894
1895 uint64_t commonInfo = 0;
1896 commonInfo |= (static_cast<uint8_t>(m_triggerType) & 0x0f);
1897 commonInfo |= (m_ulLength & 0x0fff) << 4;
1898 commonInfo |= (m_moreTF ? 1 << 16 : 0);
1899 commonInfo |= (m_csRequired ? 1 << 17 : 0);
1900 commonInfo |= (m_ulBandwidth & 0x03) << 18;
1901 commonInfo |= (m_giAndLtfType & 0x03) << 20;
1902 commonInfo |= static_cast<uint64_t>(m_apTxPower & 0x3f) << 28;
1903 commonInfo |= static_cast<uint64_t>(m_ulSpatialReuse) << 37;
1905 {
1906 uint64_t ulHeSigA2 = 0x01ff; // nine bits equal to 1
1907 commonInfo |= ulHeSigA2 << 54;
1908 }
1909
1910 i.WriteHtolsbU64(commonInfo);
1911
1912 for (auto& ui : m_userInfoFields)
1913 {
1914 i = ui.Serialize(i);
1915 }
1916
1917 for (std::size_t count = 0; count < m_padding; count++)
1918 {
1919 i.WriteU8(0xff); // Padding field
1920 }
1921}
1922
1925{
1926 Buffer::Iterator i = start;
1927
1928 uint64_t commonInfo = i.ReadLsbtohU64();
1929
1930 m_triggerType = static_cast<TriggerFrameType>(commonInfo & 0x0f);
1931 m_ulLength = (commonInfo >> 4) & 0x0fff;
1932 m_moreTF = (commonInfo >> 16) & 0x01;
1933 m_csRequired = (commonInfo >> 17) & 0x01;
1934 m_ulBandwidth = (commonInfo >> 18) & 0x03;
1935 m_giAndLtfType = (commonInfo >> 20) & 0x03;
1936 m_apTxPower = (commonInfo >> 28) & 0x3f;
1937 m_ulSpatialReuse = (commonInfo >> 37) & 0xffff;
1938 uint8_t bit54and55 = (commonInfo >> 54) & 0x03;
1940 m_userInfoFields.clear();
1941 m_padding = 0;
1942
1944 "BFRP Trigger frame is not supported");
1946 "GCR-MU-BAR Trigger frame is not supported");
1948 "NFRP Trigger frame is not supported");
1949
1950 while (i.GetRemainingSize() >= 2)
1951 {
1952 // read the first 2 bytes to check if we encountered the Padding field
1953 if (i.ReadU16() == 0xffff)
1954 {
1955 m_padding = i.GetRemainingSize() + 2;
1956 }
1957 else
1958 {
1959 // go back 2 bytes to deserialize the User Info field from the beginning
1960 i.Prev(2);
1962 i = ui.Deserialize(i);
1963 }
1964 }
1965
1966 return i.GetDistanceFrom(start);
1967}
1968
1969void
1974
1977{
1978 return m_triggerType;
1979}
1980
1981const char*
1983{
1984 return GetTypeString(GetType());
1985}
1986
1987const char*
1989{
1990#define FOO(x) \
1991 case TriggerFrameType::x: \
1992 return #x;
1993
1994 switch (type)
1995 {
2004 default:
2005 return "ERROR";
2006 }
2007#undef FOO
2008}
2009
2010bool
2015
2016bool
2021
2022bool
2027
2028bool
2033
2034bool
2039
2040bool
2045
2046bool
2051
2052bool
2057
2058void
2060{
2061 m_ulLength = (len & 0x0fff);
2062}
2063
2064uint16_t
2066{
2067 return m_ulLength;
2068}
2069
2072{
2074 "GetHeTbTxVector() cannot be used for MU-RTS");
2075 auto userInfoIt = FindUserInfoWithAid(staId);
2076 NS_ASSERT(userInfoIt != end());
2077
2078 WifiTxVector v;
2079 v.SetPreambleType(userInfoIt->GetPreambleType());
2084 staId,
2085 {userInfoIt->GetRuAllocation(), userInfoIt->GetUlMcs(), userInfoIt->GetNss()});
2086 return v;
2087}
2088
2089void
2091{
2092 m_moreTF = more;
2093}
2094
2095bool
2097{
2098 return m_moreTF;
2099}
2100
2101void
2103{
2104 m_csRequired = cs;
2105}
2106
2107bool
2109{
2110 return m_csRequired;
2111}
2112
2113void
2115{
2116 switch (static_cast<uint16_t>(bw))
2117 {
2118 case 20:
2119 m_ulBandwidth = 0;
2120 break;
2121 case 40:
2122 m_ulBandwidth = 1;
2123 break;
2124 case 80:
2125 m_ulBandwidth = 2;
2126 break;
2127 case 160:
2128 m_ulBandwidth = 3;
2129 break;
2130 default:
2131 NS_FATAL_ERROR("Bandwidth value not allowed.");
2132 break;
2133 }
2134}
2135
2136MHz_u
2138{
2139 return (1 << m_ulBandwidth) * 20;
2140}
2141
2142void
2143CtrlTriggerHeader::SetGiAndLtfType(Time guardInterval, uint8_t ltfType)
2144{
2145 const auto gi = guardInterval.GetNanoSeconds();
2146 if ((ltfType == 1) && (gi == 1600))
2147 {
2148 m_giAndLtfType = 0;
2149 }
2150 else if ((ltfType == 2) && (gi == 1600))
2151 {
2152 m_giAndLtfType = 1;
2153 }
2154 else if ((ltfType == 4) && (gi == 3200))
2155 {
2156 m_giAndLtfType = 2;
2157 }
2158 else
2159 {
2160 NS_FATAL_ERROR("Invalid combination of GI and LTF type");
2161 }
2162}
2163
2164Time
2166{
2167 if (m_giAndLtfType == 0 || m_giAndLtfType == 1)
2168 {
2169 return NanoSeconds(1600);
2170 }
2171 else if (m_giAndLtfType == 2)
2172 {
2173 return NanoSeconds(3200);
2174 }
2175 else
2176 {
2177 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2178 }
2179}
2180
2181uint8_t
2183{
2184 if (m_giAndLtfType == 0)
2185 {
2186 return 1;
2187 }
2188 else if (m_giAndLtfType == 1)
2189 {
2190 return 2;
2191 }
2192 else if (m_giAndLtfType == 2)
2193 {
2194 return 4;
2195 }
2196 else
2197 {
2198 NS_FATAL_ERROR("Invalid value for GI And LTF Type subfield");
2199 }
2200}
2201
2202void
2204{
2205 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2206 NS_ABORT_MSG_IF(power < -20 || power > 40, "Out of range power values");
2207
2208 m_apTxPower = static_cast<uint8_t>(power + 20);
2209}
2210
2211int8_t
2213{
2214 // see Table 9-25f "AP Tx Power subfield encoding" of 802.11ax amendment D3.0
2215 return static_cast<int8_t>(m_apTxPower) - 20;
2216}
2217
2218void
2220{
2221 m_ulSpatialReuse = sr;
2222}
2223
2224uint16_t
2229
2230void
2232{
2233 NS_ABORT_MSG_IF(size == 1, "The Padding field, if present, shall be at least two octets");
2234 m_padding = size;
2235}
2236
2237std::size_t
2239{
2240 return m_padding;
2241}
2242
2245{
2246 // make a copy of this Trigger Frame and remove the User Info fields from the copy
2247 CtrlTriggerHeader trigger(*this);
2248 trigger.m_userInfoFields.clear();
2249 return trigger;
2250}
2251
2258
2261{
2263 userInfo.GetType() != m_triggerType,
2264 "Trying to add a User Info field of a type other than the type of the Trigger Frame");
2265 m_userInfoFields.push_back(userInfo);
2266 return m_userInfoFields.back();
2267}
2268
2271{
2272 return m_userInfoFields.erase(userInfoIt);
2273}
2274
2277{
2278 return m_userInfoFields.begin();
2279}
2280
2283{
2284 return m_userInfoFields.end();
2285}
2286
2289{
2290 return m_userInfoFields.begin();
2291}
2292
2295{
2296 return m_userInfoFields.end();
2297}
2298
2299std::size_t
2301{
2302 return m_userInfoFields.size();
2303}
2304
2307{
2308 // the lambda function returns true if a User Info field has the AID12 subfield
2309 // equal to the given aid12 value
2310 return std::find_if(start, end(), [aid12](const CtrlTriggerUserInfoField& ui) -> bool {
2311 return (ui.GetAid12() == aid12);
2312 });
2313}
2314
2317{
2318 return FindUserInfoWithAid(m_userInfoFields.begin(), aid12);
2319}
2320
2326
2332
2338
2344
2345bool
2347{
2349 {
2350 return true;
2351 }
2352
2353 // check that allocated RUs do not overlap
2354 // TODO This is not a problem in case of UL MU-MIMO
2355 std::vector<HeRu::RuSpec> prevRus;
2356
2357 for (auto& ui : m_userInfoFields)
2358 {
2359 if (HeRu::DoesOverlap(GetUlBandwidth(), ui.GetRuAllocation(), prevRus))
2360 {
2361 return false;
2362 }
2363 prevRus.push_back(ui.GetRuAllocation());
2364 }
2365 return true;
2366}
2367
2368} // 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,...
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:1380
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:185
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...