A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
multi-link-element.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 Universita' degli Studi di Napoli Federico II
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
20#include "multi-link-element.h"
21
22#include "ns3/address-utils.h"
23#include "ns3/mgt-headers.h"
24
25#include <utility>
26
27namespace ns3
28{
29
30/**
31 * CommonInfoBasicMle
32 */
33
34uint16_t
36{
37 // see Sec. 9.4.2.312.2.1 of 802.11be D1.5
38 return (m_linkIdInfo.has_value() ? 0x0001 : 0x0) |
39 (m_bssParamsChangeCount.has_value() ? 0x0002 : 0x0) |
40 (m_mediumSyncDelayInfo.has_value() ? 0x0004 : 0x0) |
41 (m_emlCapabilities.has_value() ? 0x0008 : 0x0) |
42 (m_mldCapabilities.has_value() ? 0x0010 : 0x0);
43}
44
45uint8_t
47{
48 uint8_t ret = 7; // Common Info Length (1) + MLD MAC Address (6)
49 ret += (m_linkIdInfo.has_value() ? 1 : 0);
50 ret += (m_bssParamsChangeCount.has_value() ? 1 : 0);
51 ret += (m_mediumSyncDelayInfo.has_value() ? 2 : 0);
52 ret += (m_emlCapabilities.has_value() ? 2 : 0);
53 ret += (m_mldCapabilities.has_value() ? 2 : 0);
54 return ret;
55}
56
57void
59{
60 start.WriteU8(GetSize()); // Common Info Length
62 if (m_linkIdInfo.has_value())
63 {
64 start.WriteU8(*m_linkIdInfo & 0x0f);
65 }
66 if (m_bssParamsChangeCount.has_value())
67 {
68 start.WriteU8(*m_bssParamsChangeCount);
69 }
70 if (m_mediumSyncDelayInfo.has_value())
71 {
72 start.WriteU8(m_mediumSyncDelayInfo->mediumSyncDuration);
73 uint8_t val = m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold |
74 (m_mediumSyncDelayInfo->mediumSyncMaxNTxops << 4);
75 start.WriteU8(val);
76 }
77 if (m_emlCapabilities.has_value())
78 {
79 uint16_t val =
80 m_emlCapabilities->emlsrSupport | (m_emlCapabilities->emlsrPaddingDelay << 1) |
81 (m_emlCapabilities->emlsrTransitionDelay << 4) |
82 (m_emlCapabilities->emlmrSupport << 7) | (m_emlCapabilities->emlmrDelay << 8) |
83 (m_emlCapabilities->transitionTimeout << 11);
84 start.WriteHtolsbU16(val);
85 }
86 if (m_mldCapabilities.has_value())
87 {
88 uint16_t val =
89 m_mldCapabilities->maxNSimultaneousLinks | (m_mldCapabilities->srsSupport << 4) |
90 (m_mldCapabilities->tidToLinkMappingSupport << 5) |
91 (m_mldCapabilities->freqSepForStrApMld << 7) | (m_mldCapabilities->aarSupport << 12);
92 start.WriteHtolsbU16(val);
93 }
94}
95
96uint8_t
98{
99 Buffer::Iterator i = start;
100
101 uint8_t length = i.ReadU8();
103 uint8_t count = 7;
104
105 if ((presence & 0x0001) != 0)
106 {
107 m_linkIdInfo = i.ReadU8() & 0x0f;
108 count++;
109 }
110 if ((presence & 0x0002) != 0)
111 {
113 count++;
114 }
115 if ((presence & 0x0004) != 0)
116 {
118 m_mediumSyncDelayInfo->mediumSyncDuration = i.ReadU8();
119 uint8_t val = i.ReadU8();
120 m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold = val & 0x0f;
121 m_mediumSyncDelayInfo->mediumSyncMaxNTxops = (val >> 4) & 0x0f;
122 count += 2;
123 }
124 if ((presence & 0x0008) != 0)
125 {
127 uint16_t val = i.ReadLsbtohU16();
128 m_emlCapabilities->emlsrSupport = val & 0x0001;
129 m_emlCapabilities->emlsrPaddingDelay = (val >> 1) & 0x0007;
130 m_emlCapabilities->emlsrTransitionDelay = (val >> 4) & 0x0007;
131 m_emlCapabilities->emlmrSupport = (val >> 7) & 0x0001;
132 m_emlCapabilities->emlmrDelay = (val >> 8) & 0x0007;
133 m_emlCapabilities->transitionTimeout = (val >> 11) & 0x000f;
134 count += 2;
135 }
136 if ((presence & 0x0010) != 0)
137 {
139 uint16_t val = i.ReadLsbtohU16();
140 m_mldCapabilities->maxNSimultaneousLinks = val & 0x000f;
141 m_mldCapabilities->srsSupport = (val >> 4) & 0x0001;
142 m_mldCapabilities->tidToLinkMappingSupport = (val >> 5) & 0x0003;
143 m_mldCapabilities->freqSepForStrApMld = (val >> 7) & 0x001f;
144 m_mldCapabilities->aarSupport = (val >> 12) & 0x0001;
145 count += 2;
146 }
147
148 NS_ABORT_MSG_IF(count != length,
149 "Common Info Length (" << +length
150 << ") differs "
151 "from actual number of bytes read ("
152 << +count << ")");
153 return count;
154}
155
156uint8_t
158{
159 auto delayUs = delay.GetMicroSeconds();
160
161 if (delayUs == 0)
162 {
163 return 0;
164 }
165
166 for (uint8_t i = 1; i <= 4; i++)
167 {
168 if (1 << (i + 4) == delayUs)
169 {
170 return i;
171 }
172 }
173
174 NS_ABORT_MSG("Value not allowed (" << delay.As(Time::US) << ")");
175 return 0;
176}
177
178Time
180{
181 NS_ABORT_MSG_IF(value > 4, "Value not allowed (" << +value << ")");
182 if (value == 0)
183 {
184 return MicroSeconds(0);
185 }
186 return MicroSeconds(1 << (4 + value));
187}
188
189uint8_t
191{
192 auto delayUs = delay.GetMicroSeconds();
193
194 if (delayUs == 0)
195 {
196 return 0;
197 }
198
199 for (uint8_t i = 1; i <= 5; i++)
200 {
201 if (1 << (i + 3) == delayUs)
202 {
203 return i;
204 }
205 }
206
207 NS_ABORT_MSG("Value not allowed (" << delay.As(Time::US) << ")");
208 return 0;
209}
210
211Time
213{
214 NS_ABORT_MSG_IF(value > 5, "Value not allowed (" << +value << ")");
215 if (value == 0)
216 {
217 return MicroSeconds(0);
218 }
219 return MicroSeconds(1 << (3 + value));
220}
221
222void
224{
225 int64_t delayUs = delay.GetMicroSeconds();
226 NS_ABORT_MSG_IF(delayUs % 32 != 0, "Delay must be a multiple of 32 microseconds");
227 delayUs /= 32;
228
229 if (!m_mediumSyncDelayInfo.has_value())
230 {
232 }
233 m_mediumSyncDelayInfo->mediumSyncDuration = (delayUs & 0xff);
234}
235
236Time
238{
240 return MicroSeconds(m_mediumSyncDelayInfo->mediumSyncDuration * 32);
241}
242
243void
245{
246 NS_ABORT_MSG_IF(threshold < -72 || threshold > -62, "Threshold may range from -72 to -62 dBm");
247 uint8_t value = 72 + threshold;
248
249 if (!m_mediumSyncDelayInfo.has_value())
250 {
252 }
253 m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold = value;
254}
255
256int8_t
258{
260 return (m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold) - 72;
261}
262
263void
265{
266 NS_ASSERT_MSG(nTxops < 16, "Value " << +nTxops << "cannot be encoded in 4 bits");
267
268 if (!m_mediumSyncDelayInfo.has_value())
269 {
271 }
272
273 if (nTxops == 0)
274 {
275 // no limit on max number of TXOPs
276 m_mediumSyncDelayInfo->mediumSyncMaxNTxops = 15;
277 return;
278 }
279
280 m_mediumSyncDelayInfo->mediumSyncMaxNTxops = --nTxops;
281}
282
283std::optional<uint8_t>
285{
287 uint8_t nTxops = m_mediumSyncDelayInfo->mediumSyncMaxNTxops;
288 if (nTxops == 15)
289 {
290 return std::nullopt;
291 }
292 return nTxops + 1;
293}
294
295/**
296 * MultiLinkElement
297 */
299 : m_containingFrame(frame),
300 m_commonInfo(std::in_place_type<std::monostate>) // initialize as UNSET
301{
302}
303
305 : MultiLinkElement(frame)
306{
307 NS_ASSERT(variant != UNSET);
308 SetVariant(variant);
309}
310
313{
314 return IE_EXTENSION;
315}
316
319{
321}
322
325{
326 return static_cast<Variant>(m_commonInfo.index());
327}
328
329void
331{
332 NS_ABORT_MSG_IF(GetVariant() != UNSET, "Multi-Link Element variant already set");
333 NS_ABORT_MSG_IF(variant == UNSET, "Invalid variant");
334
335 switch (variant)
336 {
337 case BASIC_VARIANT:
339 break;
340 default:
341 NS_ABORT_MSG("Unsupported variant: " << +variant);
342 }
343}
344
347{
348 return std::get<BASIC_VARIANT>(m_commonInfo);
349}
350
353{
354 return std::get<BASIC_VARIANT>(m_commonInfo);
355}
356
357void
359{
360 std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress = address;
361}
362
365{
366 return std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress;
367}
368
369void
371{
372 std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo = (linkIdInfo & 0x0f);
373}
374
375bool
377{
378 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.has_value();
379}
380
381uint8_t
383{
384 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.value();
385}
386
387void
389{
390 std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount = count;
391}
392
393bool
395{
396 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.has_value();
397}
398
399uint8_t
401{
402 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.value();
403}
404
405void
407{
408 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
409 if (!emlCapabilities.has_value())
410 {
411 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
412 }
413 emlCapabilities->emlsrSupport = supported ? 1 : 0;
414}
415
416void
418{
419 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
420 if (!emlCapabilities.has_value())
421 {
422 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
423 }
425}
426
427void
429{
430 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
431 if (!emlCapabilities.has_value())
432 {
433 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
434 }
436}
437
438void
440{
441 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
442 if (!emlCapabilities.has_value())
443 {
444 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
445 }
446 auto timeoutUs = timeout.GetMicroSeconds();
447
448 if (timeoutUs == 0)
449 {
450 emlCapabilities->transitionTimeout = 0;
451 }
452 else
453 {
454 uint8_t i;
455 for (i = 1; i <= 10; i++)
456 {
457 if (1 << (i + 6) == timeoutUs)
458 {
459 emlCapabilities->transitionTimeout = i;
460 break;
461 }
462 }
463 NS_ABORT_MSG_IF(i > 10, "Value not allowed (" << timeout.As(Time::US) << ")");
464 }
465}
466
467bool
469{
470 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities.has_value();
471}
472
473bool
475{
476 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities->emlsrSupport;
477}
478
479Time
481{
482 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
483 NS_ASSERT(emlCapabilities);
484 return CommonInfoBasicMle::DecodeEmlsrPaddingDelay(emlCapabilities->emlsrPaddingDelay);
485}
486
487Time
489{
490 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
491 NS_ASSERT(emlCapabilities);
492 return CommonInfoBasicMle::DecodeEmlsrTransitionDelay(emlCapabilities->emlsrTransitionDelay);
493}
494
495Time
497{
498 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
499 NS_ASSERT(emlCapabilities);
500 if (emlCapabilities->transitionTimeout == 0)
501 {
502 return MicroSeconds(0);
503 }
504 return MicroSeconds(1 << (6 + emlCapabilities->transitionTimeout));
505}
506
508 : m_variant(variant),
509 m_staControl(0)
510{
511}
512
514 const PerStaProfileSubelement& perStaProfile)
515 : m_variant(perStaProfile.m_variant),
516 m_staControl(perStaProfile.m_staControl),
517 m_staMacAddress(perStaProfile.m_staMacAddress)
518{
519 // deep copy of the STA Profile field
520 auto staProfileCopy = [&](auto&& frame) {
521 using Ptr = std::decay_t<decltype(frame)>;
522 if constexpr (std::is_same_v<Ptr, std::monostate>)
523 {
524 return;
525 }
526 else
527 {
528 using T = std::decay_t<decltype(*frame.get())>;
529 m_staProfile = std::make_unique<T>(*frame.get());
530 }
531 };
532 std::visit(staProfileCopy, perStaProfile.m_staProfile);
533}
534
537{
538 // check for self-assignment
539 if (&perStaProfile == this)
540 {
541 return *this;
542 }
543
544 m_variant = perStaProfile.m_variant;
545 m_staControl = perStaProfile.m_staControl;
546 m_staMacAddress = perStaProfile.m_staMacAddress;
547
548 // deep copy of the STA Profile field
549 auto staProfileCopy = [&](auto&& frame) {
550 using Ptr = std::decay_t<decltype(frame)>;
551 if constexpr (std::is_same_v<Ptr, std::monostate>)
552 {
553 return;
554 }
555 else
556 {
557 using T = std::decay_t<decltype(*frame.get())>;
558 m_staProfile = std::make_unique<T>(*frame.get());
559 }
560 };
561 std::visit(staProfileCopy, perStaProfile.m_staProfile);
562
563 return *this;
564}
565
566void
568{
569 m_staControl &= 0xfff0; // reset Link ID subfield in the STA Control field
570 m_staControl |= (linkId & 0x0f);
571}
572
573uint8_t
575{
576 return static_cast<uint8_t>(m_staControl & 0x000f);
577}
578
579void
581{
582 m_staControl |= 0x0010;
583}
584
585bool
587{
588 return (m_staControl & 0x0010) != 0;
589}
590
591void
593{
594 NS_ABORT_IF(m_variant != BASIC_VARIANT);
595 m_staMacAddress = address;
596 m_staControl |= 0x0020;
597}
598
599bool
601{
602 return (m_staControl & 0x0020) != 0;
603}
604
607{
608 NS_ABORT_IF(!HasStaMacAddress());
609 return m_staMacAddress;
610}
611
612void
614 const std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>& assoc)
615{
616 std::visit(
617 [&](auto&& frame) {
618 m_staProfile = std::make_unique<std::decay_t<decltype(frame)>>(frame);
619 },
620 assoc);
621}
622
623void
625 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>&& assoc)
626{
627 std::visit(
628 [&](auto&& frame) {
629 using T = std::decay_t<decltype(frame)>;
630 m_staProfile = std::make_unique<T>(std::forward<T>(frame));
631 },
632 assoc);
633}
634
635bool
637{
638 return std::holds_alternative<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
639}
640
641bool
643{
644 return std::holds_alternative<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
645}
646
649{
650 if (HasAssocRequest())
651 {
652 return *std::get<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
653 }
654 NS_ABORT_UNLESS(HasReassocRequest());
655 return *std::get<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
656}
657
658void
660{
661 m_staProfile = std::make_unique<MgtAssocResponseHeader>(assoc);
662}
663
664void
666{
667 m_staProfile = std::make_unique<MgtAssocResponseHeader>(std::move(assoc));
668}
669
670bool
672{
673 return std::holds_alternative<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
674}
675
678{
679 NS_ABORT_IF(!HasAssocResponse());
680 return *std::get<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
681}
682
683uint8_t
685{
686 uint8_t ret = 1; // STA Info Length
687
688 if (HasStaMacAddress())
689 {
690 ret += 6;
691 }
692 // TODO add other subfields of the STA Info field
693 return ret;
694}
695
698{
700}
701
702uint16_t
704{
705 uint16_t ret = 2; // STA Control field
706
707 ret += GetStaInfoLength();
708
709 auto staProfileSize = [&](auto&& frame) {
710 using T = std::decay_t<decltype(frame)>;
711 if constexpr (std::is_same_v<T, std::monostate>)
712 {
713 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
714 "Missing management frame for Per-STA Profile subelement");
715 return static_cast<uint32_t>(0);
716 }
717 else
718 {
719 using U = std::decay_t<decltype(*frame)>;
721 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
722 "Containing frame type and frame type in Per-STA Profile do not match");
723 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
724 return frame->GetSerializedSizeInPerStaProfile(containing);
725 }
726 };
727 ret += std::visit(staProfileSize, m_staProfile);
728
729 return ret;
730}
731
732void
734{
735 start.WriteHtolsbU16(m_staControl);
736 start.WriteU8(GetStaInfoLength());
737
738 if (HasStaMacAddress())
739 {
740 WriteTo(start, m_staMacAddress);
741 }
742 // TODO add other subfields of the STA Info field
743 auto staProfileSerialize = [&](auto&& frame) {
744 using T = std::decay_t<decltype(frame)>;
745 if constexpr (std::is_same_v<T, std::monostate>)
746 {
747 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
748 "Missing management frame for Per-STA Profile subelement");
749 return;
750 }
751 else
752 {
753 using U = std::decay_t<decltype(*frame)>;
755 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
756 "Containing frame type and frame type in Per-STA Profile do not match");
757 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
758 frame->SerializeInPerStaProfile(start, containing);
759 }
760 };
761 std::visit(staProfileSerialize, m_staProfile);
762}
763
764uint16_t
766 uint16_t length)
767{
768 Buffer::Iterator i = start;
769
770 m_staControl = i.ReadLsbtohU16();
771 i.ReadU8(); // STA Info Length
772
773 if (HasStaMacAddress())
774 {
775 ReadFrom(i, m_staMacAddress);
776 }
777
778 // TODO add other subfields of the STA Info field
779 uint16_t count = i.GetDistanceFrom(start);
780
781 NS_ASSERT_MSG(count <= length,
782 "Bytes read (" << count << ") exceed expected number (" << length << ")");
783
784 if (count == length)
785 {
786 return count;
787 }
788
789 auto staProfileDeserialize = [&](auto&& frame) {
790 using T = std::decay_t<decltype(frame)>;
791 if constexpr (!std::is_same_v<T, std::monostate>)
792 {
793 using U = std::decay_t<decltype(frame.get())>;
794 U assoc;
795 count += assoc.DeserializeFromPerStaProfile(i, length - count, frame.get());
796 m_staProfile = std::make_unique<U>(std::move(assoc));
797 }
798 };
799 std::visit(staProfileDeserialize, m_containingFrame);
800
801 return count;
802}
803
804void
806{
807 auto variant = GetVariant();
808 NS_ABORT_IF(variant == UNSET);
809 m_perStaProfileSubelements.emplace_back(variant);
810}
811
812std::size_t
814{
815 return m_perStaProfileSubelements.size();
816}
817
820{
821 return m_perStaProfileSubelements.at(i);
822}
823
826{
827 return m_perStaProfileSubelements.at(i);
828}
829
830uint16_t
832{
833 uint16_t ret = 3; // ElementIdExt (1) + Multi-Link Control (2)
834
835 // add the Common Info field size (dependent on the Multi-Link Element variant)
836 ret += std::visit(
837 [](auto&& arg) -> uint8_t {
838 using T = std::decay_t<decltype(arg)>;
839 if constexpr (std::is_same_v<T, std::monostate>)
840 {
841 NS_ABORT_MSG("Multi-Link Element variant not set");
842 return 0;
843 }
844 else
845 {
846 return arg.GetSize();
847 }
848 },
850
851 for (const auto& subelement : m_perStaProfileSubelements)
852 {
853 subelement.m_containingFrame = m_containingFrame;
854 ret += subelement.GetSerializedSize();
855 }
856
857 return ret;
858}
859
860void
862{
863 // serialize the Multi-Link Control and Common Info fields
864 std::visit(
865 [this, &start](auto&& arg) {
866 using T = std::decay_t<decltype(arg)>;
867 if constexpr (std::is_same_v<T, std::monostate>)
868 {
869 NS_ABORT_MSG("Multi-Link Element variant not set");
870 }
871 else
872 {
873 uint16_t mlControl =
874 static_cast<uint8_t>(GetVariant()) + (arg.GetPresenceBitmap() << 4);
875 start.WriteHtolsbU16(mlControl);
876 arg.Serialize(start);
877 }
878 },
880
881 for (const auto& subelement : m_perStaProfileSubelements)
882 {
883 start = subelement.Serialize(start);
884 }
885}
886
887uint16_t
889{
890 Buffer::Iterator i = start;
891 uint16_t count = 0;
892
893 uint16_t mlControl = i.ReadLsbtohU16();
894 count += 2;
895
896 SetVariant(static_cast<Variant>(mlControl & 0x0007));
897 uint16_t presence = mlControl >> 4;
898
899 uint8_t nBytes = std::visit(
900 [&i, &presence](auto&& arg) -> uint8_t {
901 using T = std::decay_t<decltype(arg)>;
902 if constexpr (std::is_same_v<T, std::monostate>)
903 {
904 NS_ABORT_MSG("Multi-Link Element variant not set");
905 return 0;
906 }
907 else
908 {
909 return arg.Deserialize(i, presence);
910 }
911 },
913 i.Next(nBytes);
914 count += nBytes;
915
916 while (count < length)
917 {
918 switch (static_cast<SubElementId>(i.PeekU8()))
919 {
922 auto& perStaProfile = GetPerStaProfile(GetNPerStaProfileSubelements() - 1);
923 perStaProfile.m_containingFrame = m_containingFrame;
924 i = perStaProfile.Deserialize(i);
925 count = i.GetDistanceFrom(start);
926 }
927 break;
928 default:
929 NS_ABORT_MSG("Unsupported Subelement ID: " << +i.PeekU8());
930 }
931 }
932
933 return count;
934}
935
936} // namespace ns3
iterator in a Buffer instance
Definition: buffer.h:100
uint8_t ReadU8()
Definition: buffer.h:1027
uint16_t ReadLsbtohU16()
Definition: buffer.cc:1064
uint8_t PeekU8()
Definition: buffer.h:1006
uint32_t GetDistanceFrom(const Iterator &o) const
Definition: buffer.cc:780
void Next()
go forward by one byte
Definition: buffer.h:853
an EUI-48 address
Definition: mac48-address.h:46
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:334
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
@ US
microsecond
Definition: nstime.h:118
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:413
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_UNLESS(cond)
Abnormal program termination if a condition is false.
Definition: abort.h:129
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Variant
Multi-Link element variants.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::variant< std::reference_wrapper< MgtAssocRequestHeader >, std::reference_wrapper< MgtReassocRequestHeader > > AssocReqRefVariant
variant holding a reference to a (Re)Association Request
Definition: ap-wifi-mac.h:55
void WriteTo(Buffer::Iterator &i, Ipv4Address ad)
Write an Ipv4Address to a Buffer.
uint8_t WifiInformationElementId
This type is used to represent an Information Element ID.
void ReadFrom(Buffer::Iterator &i, Ipv4Address &ad)
Read an Ipv4Address from a Buffer.
STL namespace.
ns3::Time timeout
uint8_t emlsrPaddingDelay
EMLSR Padding Delay.
uint8_t emlsrTransitionDelay
EMLSR Transition Delay.
Medium Synchronization Delay Information subfield.
Common Info field of the Basic Multi-Link element.
uint16_t GetPresenceBitmap() const
Get the Presence Bitmap subfield of the Common Info field.
uint8_t GetSize() const
Get the size of the serialized Common Info field.
static uint8_t EncodeEmlsrTransitionDelay(Time delay)
static Time DecodeEmlsrTransitionDelay(uint8_t value)
std::optional< EmlCapabilities > m_emlCapabilities
EML Capabilities.
uint8_t Deserialize(Buffer::Iterator start, uint16_t presence)
Deserialize the Common Info field.
std::optional< uint8_t > GetMediumSyncMaxNTxops() const
Get the maximum number of TXOPs a non-AP STA is allowed to attempt to initiate while the MediumSyncDe...
int8_t GetMediumSyncOfdmEdThreshold() const
Get the Medium Synchronization OFDM ED Threshold in dBm.
std::optional< MldCapabilities > m_mldCapabilities
MLD Capabilities.
void SetMediumSyncOfdmEdThreshold(int8_t threshold)
Set the Medium Synchronization OFDM ED Threshold subfield of the Medium Synchronization Delay Informa...
static Time DecodeEmlsrPaddingDelay(uint8_t value)
void Serialize(Buffer::Iterator &start) const
Serialize the Common Info field.
std::optional< MediumSyncDelayInfo > m_mediumSyncDelayInfo
Medium Synchronization Delay Information.
void SetMediumSyncDelayTimer(Time delay)
Set the Medium Synchronization Duration subfield of the Medium Synchronization Delay Information in t...
Time GetMediumSyncDelayTimer() const
Get the Medium Synchronization Duration subfield of the Medium Synchronization Delay Information in t...
Mac48Address m_mldMacAddress
Subfields.
std::optional< uint8_t > m_bssParamsChangeCount
BSS Parameters Change Count.
void SetMediumSyncMaxNTxops(uint8_t nTxops)
Set the Medium Synchronization Maximum Number of TXOPs subfield of the Medium Synchronization Delay I...
std::optional< uint8_t > m_linkIdInfo
Link ID Info.
static uint8_t EncodeEmlsrPaddingDelay(Time delay)
#define IE_EXTENSION
#define IE_EXT_MULTI_LINK_ELEMENT