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
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
226 : m_containingFrame(frame),
227 m_commonInfo(std::in_place_type<std::monostate>) // initialize as UNSET
228{
229}
230
232 : MultiLinkElement(frame)
233{
234 NS_ASSERT(variant != UNSET);
235 SetVariant(variant);
236}
237
240{
241 return IE_EXTENSION;
242}
243
246{
248}
249
252{
253 return static_cast<Variant>(m_commonInfo.index());
254}
255
256void
258{
259 NS_ABORT_MSG_IF(GetVariant() != UNSET, "Multi-Link Element variant already set");
260 NS_ABORT_MSG_IF(variant == UNSET, "Invalid variant");
261
262 switch (variant)
263 {
264 case BASIC_VARIANT:
266 break;
267 default:
268 NS_ABORT_MSG("Unsupported variant: " << +variant);
269 }
270}
271
274{
275 return std::get<BASIC_VARIANT>(m_commonInfo);
276}
277
280{
281 return std::get<BASIC_VARIANT>(m_commonInfo);
282}
283
284void
286{
287 std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress = address;
288}
289
292{
293 return std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress;
294}
295
296void
298{
299 std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo = (linkIdInfo & 0x0f);
300}
301
302bool
304{
305 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.has_value();
306}
307
308uint8_t
310{
311 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.value();
312}
313
314void
316{
317 std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount = count;
318}
319
320bool
322{
323 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.has_value();
324}
325
326uint8_t
328{
329 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.value();
330}
331
332void
334{
335 int64_t delayUs = delay.GetMicroSeconds();
336 NS_ABORT_MSG_IF(delayUs % 32 != 0, "Delay must be a multiple of 32 microseconds");
337 delayUs /= 32;
338
339 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
340 if (!mediumSyncDelayInfo.has_value())
341 {
342 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
343 }
344 mediumSyncDelayInfo.value().mediumSyncDuration = (delayUs & 0xff);
345}
346
347Time
349{
350 return MicroSeconds(
351 (std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.value().mediumSyncDuration) *
352 32);
353}
354
355void
357{
358 NS_ABORT_MSG_IF(threshold < -72 || threshold > -62, "Threshold may range from -72 to -62 dBm");
359 uint8_t value = 72 + threshold;
360
361 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
362 if (!mediumSyncDelayInfo.has_value())
363 {
364 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
365 }
366 mediumSyncDelayInfo.value().mediumSyncOfdmEdThreshold = value;
367}
368
369int8_t
371{
372 return (std::get<BASIC_VARIANT>(m_commonInfo)
373 .m_mediumSyncDelayInfo.value()
374 .mediumSyncOfdmEdThreshold) -
375 72;
376}
377
378void
380{
381 NS_ASSERT(nTxops > 0);
382 nTxops--;
383
384 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
385 if (!mediumSyncDelayInfo.has_value())
386 {
387 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
388 }
389 mediumSyncDelayInfo.value().mediumSyncMaxNTxops = (nTxops & 0x0f);
390}
391
392uint8_t
394{
395 return (std::get<BASIC_VARIANT>(m_commonInfo)
396 .m_mediumSyncDelayInfo.value()
397 .mediumSyncMaxNTxops) +
398 1;
399}
400
401bool
403{
404 return std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.has_value();
405}
406
407void
409{
410 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
411 if (!emlCapabilities.has_value())
412 {
413 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
414 }
415 emlCapabilities->emlsrSupport = supported ? 1 : 0;
416}
417
418void
420{
421 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
422 if (!emlCapabilities.has_value())
423 {
424 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
425 }
427}
428
429void
431{
432 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
433 if (!emlCapabilities.has_value())
434 {
435 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
436 }
438}
439
440void
442{
443 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
444 if (!emlCapabilities.has_value())
445 {
446 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
447 }
448 auto timeoutUs = timeout.GetMicroSeconds();
449
450 if (timeoutUs == 0)
451 {
452 emlCapabilities->transitionTimeout = 0;
453 }
454 else
455 {
456 uint8_t i;
457 for (i = 1; i <= 10; i++)
458 {
459 if (1 << (i + 6) == timeoutUs)
460 {
461 emlCapabilities->transitionTimeout = i;
462 break;
463 }
464 }
465 NS_ABORT_MSG_IF(i > 10, "Value not allowed (" << timeout.As(Time::US) << ")");
466 }
467}
468
469bool
471{
472 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities.has_value();
473}
474
475bool
477{
478 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities->emlsrSupport;
479}
480
481Time
483{
484 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
485 NS_ASSERT(emlCapabilities);
486 return CommonInfoBasicMle::DecodeEmlsrPaddingDelay(emlCapabilities->emlsrPaddingDelay);
487}
488
489Time
491{
492 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
493 NS_ASSERT(emlCapabilities);
494 return CommonInfoBasicMle::DecodeEmlsrTransitionDelay(emlCapabilities->emlsrTransitionDelay);
495}
496
497Time
499{
500 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
501 NS_ASSERT(emlCapabilities);
502 if (emlCapabilities->transitionTimeout == 0)
503 {
504 return MicroSeconds(0);
505 }
506 return MicroSeconds(1 << (6 + emlCapabilities->transitionTimeout));
507}
508
510 : m_variant(variant),
511 m_staControl(0)
512{
513}
514
516 const PerStaProfileSubelement& perStaProfile)
517 : m_variant(perStaProfile.m_variant),
518 m_staControl(perStaProfile.m_staControl),
519 m_staMacAddress(perStaProfile.m_staMacAddress)
520{
521 // deep copy of the STA Profile field
522 auto staProfileCopy = [&](auto&& frame) {
523 using Ptr = std::decay_t<decltype(frame)>;
524 if constexpr (std::is_same_v<Ptr, std::monostate>)
525 {
526 return;
527 }
528 else
529 {
530 using T = std::decay_t<decltype(*frame.get())>;
531 m_staProfile = std::make_unique<T>(*frame.get());
532 }
533 };
534 std::visit(staProfileCopy, perStaProfile.m_staProfile);
535}
536
539{
540 // check for self-assignment
541 if (&perStaProfile == this)
542 {
543 return *this;
544 }
545
546 m_variant = perStaProfile.m_variant;
547 m_staControl = perStaProfile.m_staControl;
548 m_staMacAddress = perStaProfile.m_staMacAddress;
549
550 // deep copy of the STA Profile field
551 auto staProfileCopy = [&](auto&& frame) {
552 using Ptr = std::decay_t<decltype(frame)>;
553 if constexpr (std::is_same_v<Ptr, std::monostate>)
554 {
555 return;
556 }
557 else
558 {
559 using T = std::decay_t<decltype(*frame.get())>;
560 m_staProfile = std::make_unique<T>(*frame.get());
561 }
562 };
563 std::visit(staProfileCopy, perStaProfile.m_staProfile);
564
565 return *this;
566}
567
568void
570{
571 m_staControl &= 0xfff0; // reset Link ID subfield in the STA Control field
572 m_staControl |= (linkId & 0x0f);
573}
574
575uint8_t
577{
578 return static_cast<uint8_t>(m_staControl & 0x000f);
579}
580
581void
583{
584 m_staControl |= 0x0010;
585}
586
587bool
589{
590 return (m_staControl & 0x0010) != 0;
591}
592
593void
595{
596 NS_ABORT_IF(m_variant != BASIC_VARIANT);
597 m_staMacAddress = address;
598 m_staControl |= 0x0020;
599}
600
601bool
603{
604 return (m_staControl & 0x0020) != 0;
605}
606
609{
610 NS_ABORT_IF(!HasStaMacAddress());
611 return m_staMacAddress;
612}
613
614void
616 const std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>& assoc)
617{
618 std::visit(
619 [&](auto&& frame) {
620 m_staProfile = std::make_unique<std::decay_t<decltype(frame)>>(frame);
621 },
622 assoc);
623}
624
625void
627 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>&& assoc)
628{
629 std::visit(
630 [&](auto&& frame) {
631 using T = std::decay_t<decltype(frame)>;
632 m_staProfile = std::make_unique<T>(std::forward<T>(frame));
633 },
634 assoc);
635}
636
637bool
639{
640 return std::holds_alternative<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
641}
642
643bool
645{
646 return std::holds_alternative<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
647}
648
651{
652 if (HasAssocRequest())
653 {
654 return *std::get<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
655 }
656 NS_ABORT_UNLESS(HasReassocRequest());
657 return *std::get<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
658}
659
660void
662{
663 m_staProfile = std::make_unique<MgtAssocResponseHeader>(assoc);
664}
665
666void
668{
669 m_staProfile = std::make_unique<MgtAssocResponseHeader>(std::move(assoc));
670}
671
672bool
674{
675 return std::holds_alternative<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
676}
677
680{
681 NS_ABORT_IF(!HasAssocResponse());
682 return *std::get<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
683}
684
685uint8_t
687{
688 uint8_t ret = 1; // STA Info Length
689
690 if (HasStaMacAddress())
691 {
692 ret += 6;
693 }
694 // TODO add other subfields of the STA Info field
695 return ret;
696}
697
700{
702}
703
704uint16_t
706{
707 uint16_t ret = 2; // STA Control field
708
709 ret += GetStaInfoLength();
710
711 auto staProfileSize = [&](auto&& frame) {
712 using T = std::decay_t<decltype(frame)>;
713 if constexpr (std::is_same_v<T, std::monostate>)
714 {
715 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
716 "Missing management frame for Per-STA Profile subelement");
717 return static_cast<uint32_t>(0);
718 }
719 else
720 {
721 using U = std::decay_t<decltype(*frame)>;
723 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
724 "Containing frame type and frame type in Per-STA Profile do not match");
725 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
726 return frame->GetSerializedSizeInPerStaProfile(containing);
727 }
728 };
729 ret += std::visit(staProfileSize, m_staProfile);
730
731 return ret;
732}
733
734void
736{
737 start.WriteHtolsbU16(m_staControl);
738 start.WriteU8(GetStaInfoLength());
739
740 if (HasStaMacAddress())
741 {
742 WriteTo(start, m_staMacAddress);
743 }
744 // TODO add other subfields of the STA Info field
745 auto staProfileSerialize = [&](auto&& frame) {
746 using T = std::decay_t<decltype(frame)>;
747 if constexpr (std::is_same_v<T, std::monostate>)
748 {
749 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
750 "Missing management frame for Per-STA Profile subelement");
751 return;
752 }
753 else
754 {
755 using U = std::decay_t<decltype(*frame)>;
757 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
758 "Containing frame type and frame type in Per-STA Profile do not match");
759 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
760 frame->SerializeInPerStaProfile(start, containing);
761 }
762 };
763 std::visit(staProfileSerialize, m_staProfile);
764}
765
766uint16_t
768 uint16_t length)
769{
770 Buffer::Iterator i = start;
771
772 m_staControl = i.ReadLsbtohU16();
773 i.ReadU8(); // STA Info Length
774
775 if (HasStaMacAddress())
776 {
777 ReadFrom(i, m_staMacAddress);
778 }
779
780 // TODO add other subfields of the STA Info field
781 uint16_t count = i.GetDistanceFrom(start);
782
783 NS_ASSERT_MSG(count <= length,
784 "Bytes read (" << count << ") exceed expected number (" << length << ")");
785
786 if (count == length)
787 {
788 return count;
789 }
790
791 auto staProfileDeserialize = [&](auto&& frame) {
792 using T = std::decay_t<decltype(frame)>;
793 if constexpr (!std::is_same_v<T, std::monostate>)
794 {
795 using U = std::decay_t<decltype(frame.get())>;
796 U assoc;
797 count += assoc.DeserializeFromPerStaProfile(i, length - count, frame.get());
798 m_staProfile = std::make_unique<U>(std::move(assoc));
799 }
800 };
801 std::visit(staProfileDeserialize, m_containingFrame);
802
803 return count;
804}
805
806void
808{
809 auto variant = GetVariant();
810 NS_ABORT_IF(variant == UNSET);
811 m_perStaProfileSubelements.emplace_back(variant);
812}
813
814std::size_t
816{
817 return m_perStaProfileSubelements.size();
818}
819
822{
823 return m_perStaProfileSubelements.at(i);
824}
825
828{
829 return m_perStaProfileSubelements.at(i);
830}
831
832uint16_t
834{
835 uint16_t ret = 3; // ElementIdExt (1) + Multi-Link Control (2)
836
837 // add the Common Info field size (dependent on the Multi-Link Element variant)
838 ret += std::visit(
839 [](auto&& arg) -> uint8_t {
840 using T = std::decay_t<decltype(arg)>;
841 if constexpr (std::is_same_v<T, std::monostate>)
842 {
843 NS_ABORT_MSG("Multi-Link Element variant not set");
844 return 0;
845 }
846 else
847 {
848 return arg.GetSize();
849 }
850 },
852
853 for (const auto& subelement : m_perStaProfileSubelements)
854 {
855 subelement.m_containingFrame = m_containingFrame;
856 ret += subelement.GetSerializedSize();
857 }
858
859 return ret;
860}
861
862void
864{
865 // serialize the Multi-Link Control and Common Info fields
866 std::visit(
867 [this, &start](auto&& arg) {
868 using T = std::decay_t<decltype(arg)>;
869 if constexpr (std::is_same_v<T, std::monostate>)
870 {
871 NS_ABORT_MSG("Multi-Link Element variant not set");
872 }
873 else
874 {
875 uint16_t mlControl =
876 static_cast<uint8_t>(GetVariant()) + (arg.GetPresenceBitmap() << 4);
877 start.WriteHtolsbU16(mlControl);
878 arg.Serialize(start);
879 }
880 },
882
883 for (const auto& subelement : m_perStaProfileSubelements)
884 {
885 start = subelement.Serialize(start);
886 }
887}
888
889uint16_t
891{
892 Buffer::Iterator i = start;
893 uint16_t count = 0;
894
895 uint16_t mlControl = i.ReadLsbtohU16();
896 count += 2;
897
898 SetVariant(static_cast<Variant>(mlControl & 0x0007));
899 uint16_t presence = mlControl >> 4;
900
901 uint8_t nBytes = std::visit(
902 [&i, &presence](auto&& arg) -> uint8_t {
903 using T = std::decay_t<decltype(arg)>;
904 if constexpr (std::is_same_v<T, std::monostate>)
905 {
906 NS_ABORT_MSG("Multi-Link Element variant not set");
907 return 0;
908 }
909 else
910 {
911 return arg.Deserialize(i, presence);
912 }
913 },
915 i.Next(nBytes);
916 count += nBytes;
917
918 while (count < length)
919 {
920 switch (static_cast<SubElementId>(i.PeekU8()))
921 {
924 auto& perStaProfile = GetPerStaProfile(GetNPerStaProfileSubelements() - 1);
925 perStaProfile.m_containingFrame = m_containingFrame;
926 i = perStaProfile.Deserialize(i);
927 count = i.GetDistanceFrom(start);
928 }
929 break;
930 default:
931 NS_ABORT_MSG("Unsupported Subelement ID: " << +i.PeekU8());
932 }
933 }
934
935 return count;
936}
937
938} // namespace ns3
iterator in a Buffer instance
Definition: buffer.h:100
uint8_t ReadU8()
Definition: buffer.h:1027
uint16_t ReadLsbtohU16()
Definition: buffer.cc:1070
uint8_t PeekU8()
Definition: buffer.h:1006
uint32_t GetDistanceFrom(const Iterator &o) const
Definition: buffer.cc:786
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:338
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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:412
#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:1349
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.
uint8_t mediumSyncOfdmEdThreshold
Medium Synchronization OFDM ED Threshold.
uint8_t mediumSyncDuration
Medium Synchronization Duration.
uint8_t mediumSyncMaxNTxops
Medium Synchronization MAximum Number of TXOPs.
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< MldCapabilities > m_mldCapabilities
MLD Capabilities.
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.
Mac48Address m_mldMacAddress
Subfields.
std::optional< uint8_t > m_bssParamsChangeCount
BSS Parameters Change Count.
std::optional< uint8_t > m_linkIdInfo
Link ID Info.
static uint8_t EncodeEmlsrPaddingDelay(Time delay)
#define IE_EXTENSION
#define IE_EXT_MULTI_LINK_ELEMENT