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
272void
274{
275 std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress = address;
276}
277
280{
281 return std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress;
282}
283
284void
286{
287 std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo = (linkIdInfo & 0x0f);
288}
289
290bool
292{
293 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.has_value();
294}
295
296uint8_t
298{
299 return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.value();
300}
301
302void
304{
305 std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount = count;
306}
307
308bool
310{
311 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.has_value();
312}
313
314uint8_t
316{
317 return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.value();
318}
319
320void
322{
323 int64_t delayUs = delay.GetMicroSeconds();
324 NS_ABORT_MSG_IF(delayUs % 32 != 0, "Delay must be a multiple of 32 microseconds");
325 delayUs /= 32;
326
327 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
328 if (!mediumSyncDelayInfo.has_value())
329 {
330 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
331 }
332 mediumSyncDelayInfo.value().mediumSyncDuration = (delayUs & 0xff);
333}
334
335Time
337{
338 return MicroSeconds(
339 (std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.value().mediumSyncDuration) *
340 32);
341}
342
343void
345{
346 NS_ABORT_MSG_IF(threshold < -72 || threshold > -62, "Threshold may range from -72 to -62 dBm");
347 uint8_t value = 72 + threshold;
348
349 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
350 if (!mediumSyncDelayInfo.has_value())
351 {
352 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
353 }
354 mediumSyncDelayInfo.value().mediumSyncOfdmEdThreshold = value;
355}
356
357int8_t
359{
360 return (std::get<BASIC_VARIANT>(m_commonInfo)
361 .m_mediumSyncDelayInfo.value()
362 .mediumSyncOfdmEdThreshold) -
363 72;
364}
365
366void
368{
369 NS_ASSERT(nTxops > 0);
370 nTxops--;
371
372 auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
373 if (!mediumSyncDelayInfo.has_value())
374 {
375 mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
376 }
377 mediumSyncDelayInfo.value().mediumSyncMaxNTxops = (nTxops & 0x0f);
378}
379
380uint8_t
382{
383 return (std::get<BASIC_VARIANT>(m_commonInfo)
384 .m_mediumSyncDelayInfo.value()
385 .mediumSyncMaxNTxops) +
386 1;
387}
388
389bool
391{
392 return std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.has_value();
393}
394
395void
397{
398 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
399 if (!emlCapabilities.has_value())
400 {
401 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
402 }
403 emlCapabilities->emlsrSupport = supported ? 1 : 0;
404}
405
406void
408{
409 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
410 if (!emlCapabilities.has_value())
411 {
412 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
413 }
415}
416
417void
419{
420 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
421 if (!emlCapabilities.has_value())
422 {
423 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
424 }
426}
427
428void
430{
431 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
432 if (!emlCapabilities.has_value())
433 {
434 emlCapabilities = CommonInfoBasicMle::EmlCapabilities{};
435 }
436 auto timeoutUs = timeout.GetMicroSeconds();
437
438 if (timeoutUs == 0)
439 {
440 emlCapabilities->transitionTimeout = 0;
441 }
442 else
443 {
444 uint8_t i;
445 for (i = 1; i <= 10; i++)
446 {
447 if (1 << (i + 6) == timeoutUs)
448 {
449 emlCapabilities->transitionTimeout = i;
450 break;
451 }
452 }
453 NS_ABORT_MSG_IF(i > 10, "Value not allowed (" << timeout.As(Time::US) << ")");
454 }
455}
456
457bool
459{
460 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities.has_value();
461}
462
463bool
465{
466 return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities->emlsrSupport;
467}
468
469Time
471{
472 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
473 NS_ASSERT(emlCapabilities);
474 return CommonInfoBasicMle::DecodeEmlsrPaddingDelay(emlCapabilities->emlsrPaddingDelay);
475}
476
477Time
479{
480 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
481 NS_ASSERT(emlCapabilities);
482 return CommonInfoBasicMle::DecodeEmlsrTransitionDelay(emlCapabilities->emlsrTransitionDelay);
483}
484
485Time
487{
488 auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
489 NS_ASSERT(emlCapabilities);
490 if (emlCapabilities->transitionTimeout == 0)
491 {
492 return MicroSeconds(0);
493 }
494 return MicroSeconds(1 << (6 + emlCapabilities->transitionTimeout));
495}
496
498 : m_variant(variant),
499 m_staControl(0)
500{
501}
502
504 const PerStaProfileSubelement& perStaProfile)
505 : m_variant(perStaProfile.m_variant),
506 m_staControl(perStaProfile.m_staControl),
507 m_staMacAddress(perStaProfile.m_staMacAddress)
508{
509 // deep copy of the STA Profile field
510 auto staProfileCopy = [&](auto&& frame) {
511 using Ptr = std::decay_t<decltype(frame)>;
512 if constexpr (std::is_same_v<Ptr, std::monostate>)
513 {
514 return;
515 }
516 else
517 {
518 using T = std::decay_t<decltype(*frame.get())>;
519 m_staProfile = std::make_unique<T>(*frame.get());
520 }
521 };
522 std::visit(staProfileCopy, perStaProfile.m_staProfile);
523}
524
527{
528 // check for self-assignment
529 if (&perStaProfile == this)
530 {
531 return *this;
532 }
533
534 m_variant = perStaProfile.m_variant;
535 m_staControl = perStaProfile.m_staControl;
536 m_staMacAddress = perStaProfile.m_staMacAddress;
537
538 // deep copy of the STA Profile field
539 auto staProfileCopy = [&](auto&& frame) {
540 using Ptr = std::decay_t<decltype(frame)>;
541 if constexpr (std::is_same_v<Ptr, std::monostate>)
542 {
543 return;
544 }
545 else
546 {
547 using T = std::decay_t<decltype(*frame.get())>;
548 m_staProfile = std::make_unique<T>(*frame.get());
549 }
550 };
551 std::visit(staProfileCopy, perStaProfile.m_staProfile);
552
553 return *this;
554}
555
556void
558{
559 m_staControl &= 0xfff0; // reset Link ID subfield in the STA Control field
560 m_staControl |= (linkId & 0x0f);
561}
562
563uint8_t
565{
566 return static_cast<uint8_t>(m_staControl & 0x000f);
567}
568
569void
571{
572 m_staControl |= 0x0010;
573}
574
575bool
577{
578 return (m_staControl & 0x0010) != 0;
579}
580
581void
583{
584 NS_ABORT_IF(m_variant != BASIC_VARIANT);
585 m_staMacAddress = address;
586 m_staControl |= 0x0020;
587}
588
589bool
591{
592 return (m_staControl & 0x0020) != 0;
593}
594
597{
598 NS_ABORT_IF(!HasStaMacAddress());
599 return m_staMacAddress;
600}
601
602void
604 const std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>& assoc)
605{
606 std::visit(
607 [&](auto&& frame) {
608 m_staProfile = std::make_unique<std::decay_t<decltype(frame)>>(frame);
609 },
610 assoc);
611}
612
613void
615 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>&& assoc)
616{
617 std::visit(
618 [&](auto&& frame) {
619 using T = std::decay_t<decltype(frame)>;
620 m_staProfile = std::make_unique<T>(std::forward<T>(frame));
621 },
622 assoc);
623}
624
625bool
627{
628 return std::holds_alternative<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
629}
630
631bool
633{
634 return std::holds_alternative<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
635}
636
639{
640 if (HasAssocRequest())
641 {
642 return *std::get<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
643 }
644 NS_ABORT_UNLESS(HasReassocRequest());
645 return *std::get<std::unique_ptr<MgtReassocRequestHeader>>(m_staProfile);
646}
647
648void
650{
651 m_staProfile = std::make_unique<MgtAssocResponseHeader>(assoc);
652}
653
654void
656{
657 m_staProfile = std::make_unique<MgtAssocResponseHeader>(std::move(assoc));
658}
659
660bool
662{
663 return std::holds_alternative<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
664}
665
668{
669 NS_ABORT_IF(!HasAssocResponse());
670 return *std::get<std::unique_ptr<MgtAssocResponseHeader>>(m_staProfile);
671}
672
673uint8_t
675{
676 uint8_t ret = 1; // STA Info Length
677
678 if (HasStaMacAddress())
679 {
680 ret += 6;
681 }
682 // TODO add other subfields of the STA Info field
683 return ret;
684}
685
688{
690}
691
692uint16_t
694{
695 uint16_t ret = 2; // STA Control field
696
697 ret += GetStaInfoLength();
698
699 auto staProfileSize = [&](auto&& frame) {
700 using T = std::decay_t<decltype(frame)>;
701 if constexpr (std::is_same_v<T, std::monostate>)
702 {
703 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
704 "Missing management frame for Per-STA Profile subelement");
705 return static_cast<uint32_t>(0);
706 }
707 else
708 {
709 using U = std::decay_t<decltype(*frame)>;
711 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
712 "Containing frame type and frame type in Per-STA Profile do not match");
713 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
714 return frame->GetSerializedSizeInPerStaProfile(containing);
715 }
716 };
717 ret += std::visit(staProfileSize, m_staProfile);
718
719 return ret;
720}
721
722void
724{
725 start.WriteHtolsbU16(m_staControl);
726 start.WriteU8(GetStaInfoLength());
727
728 if (HasStaMacAddress())
729 {
730 WriteTo(start, m_staMacAddress);
731 }
732 // TODO add other subfields of the STA Info field
733 auto staProfileSerialize = [&](auto&& frame) {
734 using T = std::decay_t<decltype(frame)>;
735 if constexpr (std::is_same_v<T, std::monostate>)
736 {
737 NS_ASSERT_MSG(std::holds_alternative<std::monostate>(m_containingFrame),
738 "Missing management frame for Per-STA Profile subelement");
739 return;
740 }
741 else
742 {
743 using U = std::decay_t<decltype(*frame)>;
745 std::holds_alternative<std::reference_wrapper<const U>>(m_containingFrame),
746 "Containing frame type and frame type in Per-STA Profile do not match");
747 const auto& containing = std::get<std::reference_wrapper<const U>>(m_containingFrame);
748 frame->SerializeInPerStaProfile(start, containing);
749 }
750 };
751 std::visit(staProfileSerialize, m_staProfile);
752}
753
754uint16_t
756 uint16_t length)
757{
758 Buffer::Iterator i = start;
759
760 m_staControl = i.ReadLsbtohU16();
761 i.ReadU8(); // STA Info Length
762
763 if (HasStaMacAddress())
764 {
765 ReadFrom(i, m_staMacAddress);
766 }
767
768 // TODO add other subfields of the STA Info field
769 uint16_t count = i.GetDistanceFrom(start);
770
771 NS_ASSERT_MSG(count <= length,
772 "Bytes read (" << count << ") exceed expected number (" << length << ")");
773
774 if (count == length)
775 {
776 return count;
777 }
778
779 auto staProfileDeserialize = [&](auto&& frame) {
780 using T = std::decay_t<decltype(frame)>;
781 if constexpr (!std::is_same_v<T, std::monostate>)
782 {
783 using U = std::decay_t<decltype(frame.get())>;
784 U assoc;
785 count += assoc.DeserializeFromPerStaProfile(i, length - count, frame.get());
786 m_staProfile = std::make_unique<U>(std::move(assoc));
787 }
788 };
789 std::visit(staProfileDeserialize, m_containingFrame);
790
791 return count;
792}
793
794void
796{
797 auto variant = GetVariant();
798 NS_ABORT_IF(variant == UNSET);
799 m_perStaProfileSubelements.emplace_back(variant);
800}
801
802std::size_t
804{
805 return m_perStaProfileSubelements.size();
806}
807
810{
811 return m_perStaProfileSubelements.at(i);
812}
813
816{
817 return m_perStaProfileSubelements.at(i);
818}
819
820uint16_t
822{
823 uint16_t ret = 3; // ElementIdExt (1) + Multi-Link Control (2)
824
825 // add the Common Info field size (dependent on the Multi-Link Element variant)
826 ret += std::visit(
827 [](auto&& arg) -> uint8_t {
828 using T = std::decay_t<decltype(arg)>;
829 if constexpr (std::is_same_v<T, std::monostate>)
830 {
831 NS_ABORT_MSG("Multi-Link Element variant not set");
832 return 0;
833 }
834 else
835 {
836 return arg.GetSize();
837 }
838 },
840
841 for (const auto& subelement : m_perStaProfileSubelements)
842 {
843 subelement.m_containingFrame = m_containingFrame;
844 ret += subelement.GetSerializedSize();
845 }
846
847 return ret;
848}
849
850void
852{
853 // serialize the Multi-Link Control and Common Info fields
854 std::visit(
855 [this, &start](auto&& arg) {
856 using T = std::decay_t<decltype(arg)>;
857 if constexpr (std::is_same_v<T, std::monostate>)
858 {
859 NS_ABORT_MSG("Multi-Link Element variant not set");
860 }
861 else
862 {
863 uint16_t mlControl =
864 static_cast<uint8_t>(GetVariant()) + (arg.GetPresenceBitmap() << 4);
865 start.WriteHtolsbU16(mlControl);
866 arg.Serialize(start);
867 }
868 },
870
871 for (const auto& subelement : m_perStaProfileSubelements)
872 {
873 start = subelement.Serialize(start);
874 }
875}
876
877uint16_t
879{
880 Buffer::Iterator i = start;
881 uint16_t count = 0;
882
883 uint16_t mlControl = i.ReadLsbtohU16();
884 count += 2;
885
886 SetVariant(static_cast<Variant>(mlControl & 0x0007));
887 uint16_t presence = mlControl >> 4;
888
889 uint8_t nBytes = std::visit(
890 [&i, &presence](auto&& arg) -> uint8_t {
891 using T = std::decay_t<decltype(arg)>;
892 if constexpr (std::is_same_v<T, std::monostate>)
893 {
894 NS_ABORT_MSG("Multi-Link Element variant not set");
895 return 0;
896 }
897 else
898 {
899 return arg.Deserialize(i, presence);
900 }
901 },
903 i.Next(nBytes);
904 count += nBytes;
905
906 while (count < length)
907 {
908 switch (static_cast<SubElementId>(i.PeekU8()))
909 {
912 auto& perStaProfile = GetPerStaProfile(GetNPerStaProfileSubelements() - 1);
913 perStaProfile.m_containingFrame = m_containingFrame;
914 i = perStaProfile.Deserialize(i);
915 count = i.GetDistanceFrom(start);
916 }
917 break;
918 default:
919 NS_ABORT_MSG("Unsupported Subelement ID: " << +i.PeekU8());
920 }
921 }
922
923 return count;
924}
925
926} // 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:417
@ 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:1360
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