A Discrete-Event Network Simulator
QKDNetSim v2.0 (NS-3 v3.41) @ (+)
API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
27 namespace ns3
28 {
29 
34 uint16_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 
45 uint8_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 
57 void
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 
96 uint8_t
98 {
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 
156 uint8_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 
178 Time
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 
189 uint8_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 
211 Time
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 
222 void
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 
236 Time
238 {
240  return MicroSeconds(m_mediumSyncDelayInfo->mediumSyncDuration * 32);
241 }
242 
243 void
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 
256 int8_t
258 {
260  return (m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold) - 72;
261 }
262 
263 void
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 
283 std::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 
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 
329 void
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 
351 const CommonInfoBasicMle&
353 {
354  return std::get<BASIC_VARIANT>(m_commonInfo);
355 }
356 
357 void
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 
369 void
371 {
372  std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo = (linkIdInfo & 0x0f);
373 }
374 
375 bool
377 {
378  return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.has_value();
379 }
380 
381 uint8_t
383 {
384  return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.value();
385 }
386 
387 void
389 {
390  std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount = count;
391 }
392 
393 bool
395 {
396  return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.has_value();
397 }
398 
399 uint8_t
401 {
402  return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.value();
403 }
404 
405 void
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 
416 void
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 
427 void
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 
438 void
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 
467 bool
469 {
470  return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities.has_value();
471 }
472 
473 bool
475 {
476  return std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities->emlsrSupport;
477 }
478 
479 Time
481 {
482  auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
483  NS_ASSERT(emlCapabilities);
484  return CommonInfoBasicMle::DecodeEmlsrPaddingDelay(emlCapabilities->emlsrPaddingDelay);
485 }
486 
487 Time
489 {
490  auto& emlCapabilities = std::get<BASIC_VARIANT>(m_commonInfo).m_emlCapabilities;
491  NS_ASSERT(emlCapabilities);
492  return CommonInfoBasicMle::DecodeEmlsrTransitionDelay(emlCapabilities->emlsrTransitionDelay);
493 }
494 
495 Time
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 
566 void
568 {
569  m_staControl &= 0xfff0; // reset Link ID subfield in the STA Control field
570  m_staControl |= (linkId & 0x0f);
571 }
572 
573 uint8_t
575 {
576  return static_cast<uint8_t>(m_staControl & 0x000f);
577 }
578 
579 void
581 {
582  m_staControl |= 0x0010;
583 }
584 
585 bool
587 {
588  return (m_staControl & 0x0010) != 0;
589 }
590 
591 void
593 {
594  NS_ABORT_IF(m_variant != BASIC_VARIANT);
595  m_staMacAddress = address;
596  m_staControl |= 0x0020;
597 }
598 
599 bool
601 {
602  return (m_staControl & 0x0020) != 0;
603 }
604 
607 {
608  NS_ABORT_IF(!HasStaMacAddress());
609  return m_staMacAddress;
610 }
611 
612 void
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 
623 void
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 
635 bool
637 {
638  return std::holds_alternative<std::unique_ptr<MgtAssocRequestHeader>>(m_staProfile);
639 }
640 
641 bool
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 
658 void
660 {
661  m_staProfile = std::make_unique<MgtAssocResponseHeader>(assoc);
662 }
663 
664 void
666 {
667  m_staProfile = std::make_unique<MgtAssocResponseHeader>(std::move(assoc));
668 }
669 
670 bool
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 
683 uint8_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 
702 uint16_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 
732 void
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 
764 uint16_t
766  uint16_t length)
767 {
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 
804 void
806 {
807  auto variant = GetVariant();
808  NS_ABORT_IF(variant == UNSET);
809  m_perStaProfileSubelements.emplace_back(variant);
810 }
811 
812 std::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 
830 uint16_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  },
849  m_commonInfo);
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 
860 void
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  },
879  m_commonInfo);
880 
881  for (const auto& subelement : m_perStaProfileSubelements)
882  {
883  start = subelement.Serialize(start);
884  }
885 }
886 
887 uint16_t
889 {
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  },
912  m_commonInfo);
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:1350
Variant
Multi-Link element variants.
address
Definition: first.py:47
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.
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