A Discrete-Event Network Simulator
API
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  // NOTE Fig. 9-1002h of 802.11be D1.5 reports that the size of the EML Capabilities
53  // subfield is 3 octets, but this is likely a typo (the correct size is 2 octets)
54  ret += (m_emlCapabilities.has_value() ? 2 : 0);
55  ret += (m_mldCapabilities.has_value() ? 2 : 0);
56  return ret;
57 }
58 
59 void
61 {
62  start.WriteU8(GetSize()); // Common Info Length
64  if (m_linkIdInfo.has_value())
65  {
66  start.WriteU8(*m_linkIdInfo & 0x0f);
67  }
68  if (m_bssParamsChangeCount.has_value())
69  {
70  start.WriteU8(*m_bssParamsChangeCount);
71  }
72  if (m_mediumSyncDelayInfo.has_value())
73  {
74  start.WriteU8(m_mediumSyncDelayInfo->mediumSyncDuration);
75  uint8_t val = m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold |
76  (m_mediumSyncDelayInfo->mediumSyncMaxNTxops << 4);
77  start.WriteU8(val);
78  }
79  if (m_emlCapabilities.has_value())
80  {
81  uint16_t val =
82  m_emlCapabilities->emlsrSupport | (m_emlCapabilities->emlsrPaddingDelay << 1) |
83  (m_emlCapabilities->emlsrTransitionDelay << 4) |
84  (m_emlCapabilities->emlmrSupport << 7) | (m_emlCapabilities->emlmrDelay << 8) |
85  (m_emlCapabilities->transitionTimeout << 11);
86  start.WriteHtolsbU16(val);
87  }
88  if (m_mldCapabilities.has_value())
89  {
90  uint16_t val =
91  m_mldCapabilities->maxNSimultaneousLinks | (m_mldCapabilities->srsSupport << 4) |
92  (m_mldCapabilities->tidToLinkMappingSupport << 5) |
93  (m_mldCapabilities->freqSepForStrApMld << 7) | (m_mldCapabilities->aarSupport << 12);
94  start.WriteHtolsbU16(val);
95  }
96 }
97 
98 uint8_t
100 {
102 
103  uint8_t length = i.ReadU8();
105  uint8_t count = 7;
106 
107  if ((presence & 0x0001) != 0)
108  {
109  m_linkIdInfo = i.ReadU8() & 0x0f;
110  count++;
111  }
112  if ((presence & 0x0002) != 0)
113  {
115  count++;
116  }
117  if ((presence & 0x0004) != 0)
118  {
120  m_mediumSyncDelayInfo->mediumSyncDuration = i.ReadU8();
121  uint8_t val = i.ReadU8();
122  m_mediumSyncDelayInfo->mediumSyncOfdmEdThreshold = val & 0x0f;
123  m_mediumSyncDelayInfo->mediumSyncMaxNTxops = (val >> 4) & 0x0f;
124  count += 2;
125  }
126  if ((presence & 0x0008) != 0)
127  {
129  uint16_t val = i.ReadLsbtohU16();
130  m_emlCapabilities->emlsrSupport = val & 0x0001;
131  m_emlCapabilities->emlsrPaddingDelay = (val >> 1) & 0x0007;
132  m_emlCapabilities->emlsrTransitionDelay = (val >> 4) & 0x0007;
133  m_emlCapabilities->emlmrSupport = (val >> 7) & 0x0001;
134  m_emlCapabilities->emlmrDelay = (val >> 8) & 0x0007;
135  m_emlCapabilities->transitionTimeout = (val >> 11) & 0x000f;
136  count += 2;
137  }
138  if ((presence & 0x0010) != 0)
139  {
141  uint16_t val = i.ReadLsbtohU16();
142  m_mldCapabilities->maxNSimultaneousLinks = val & 0x000f;
143  m_mldCapabilities->srsSupport = (val >> 4) & 0x0001;
144  m_mldCapabilities->tidToLinkMappingSupport = (val >> 5) & 0x0003;
145  m_mldCapabilities->freqSepForStrApMld = (val >> 7) & 0x001f;
146  m_mldCapabilities->aarSupport = (val >> 12) & 0x0001;
147  count += 2;
148  }
149 
150  NS_ABORT_MSG_IF(count != length,
151  "Common Info Length (" << +length
152  << ") differs "
153  "from actual number of bytes read ("
154  << +count << ")");
155  return count;
156 }
157 
162  : m_frameType(frameType),
163  m_commonInfo(std::in_place_type<std::monostate>) // initialize as UNSET
164 {
165 }
166 
168  : MultiLinkElement(frameType)
169 {
170  NS_ASSERT(variant != UNSET);
171  SetVariant(variant);
172 }
173 
176 {
177  return IE_EXTENSION;
178 }
179 
182 {
184 }
185 
188 {
189  return static_cast<Variant>(m_commonInfo.index());
190 }
191 
192 void
194 {
195  NS_ABORT_MSG_IF(GetVariant() != UNSET, "Multi-Link Element variant already set");
196  NS_ABORT_MSG_IF(variant == UNSET, "Invalid variant");
197 
198  switch (variant)
199  {
200  case BASIC_VARIANT:
202  break;
203  default:
204  NS_ABORT_MSG("Unsupported variant: " << +variant);
205  }
206 }
207 
208 void
210 {
211  std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress = address;
212 }
213 
216 {
217  return std::get<BASIC_VARIANT>(m_commonInfo).m_mldMacAddress;
218 }
219 
220 void
222 {
223  std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo = (linkIdInfo & 0x0f);
224 }
225 
226 bool
228 {
229  return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.has_value();
230 }
231 
232 uint8_t
234 {
235  return std::get<BASIC_VARIANT>(m_commonInfo).m_linkIdInfo.value();
236 }
237 
238 void
240 {
241  std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount = count;
242 }
243 
244 bool
246 {
247  return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.has_value();
248 }
249 
250 uint8_t
252 {
253  return std::get<BASIC_VARIANT>(m_commonInfo).m_bssParamsChangeCount.value();
254 }
255 
256 void
258 {
259  int64_t delayUs = delay.GetMicroSeconds();
260  NS_ABORT_MSG_IF(delayUs % 32 != 0, "Delay must be a multiple of 32 microseconds");
261  delayUs /= 32;
262 
263  auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
264  if (!mediumSyncDelayInfo.has_value())
265  {
266  mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
267  }
268  mediumSyncDelayInfo.value().mediumSyncDuration = (delayUs & 0xff);
269 }
270 
271 Time
273 {
274  return MicroSeconds(
275  (std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.value().mediumSyncDuration) *
276  32);
277 }
278 
279 void
281 {
282  NS_ABORT_MSG_IF(threshold < -72 || threshold > -62, "Threshold may range from -72 to -62 dBm");
283  uint8_t value = 72 + threshold;
284 
285  auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
286  if (!mediumSyncDelayInfo.has_value())
287  {
288  mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
289  }
290  mediumSyncDelayInfo.value().mediumSyncOfdmEdThreshold = value;
291 }
292 
293 int8_t
295 {
296  return (std::get<BASIC_VARIANT>(m_commonInfo)
297  .m_mediumSyncDelayInfo.value()
298  .mediumSyncOfdmEdThreshold) -
299  72;
300 }
301 
302 void
304 {
305  NS_ASSERT(nTxops > 0);
306  nTxops--;
307 
308  auto& mediumSyncDelayInfo = std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo;
309  if (!mediumSyncDelayInfo.has_value())
310  {
311  mediumSyncDelayInfo = CommonInfoBasicMle::MediumSyncDelayInfo{};
312  }
313  mediumSyncDelayInfo.value().mediumSyncMaxNTxops = (nTxops & 0x0f);
314 }
315 
316 uint8_t
318 {
319  return (std::get<BASIC_VARIANT>(m_commonInfo)
320  .m_mediumSyncDelayInfo.value()
321  .mediumSyncMaxNTxops) +
322  1;
323 }
324 
325 bool
327 {
328  return std::get<BASIC_VARIANT>(m_commonInfo).m_mediumSyncDelayInfo.has_value();
329 }
330 
332  WifiMacType frameType)
333  : m_variant(variant),
334  m_frameType(frameType),
335  m_staControl(0)
336 {
337 }
338 
340  const PerStaProfileSubelement& perStaProfile)
341  : m_variant(perStaProfile.m_variant),
342  m_frameType(perStaProfile.m_frameType),
343  m_staControl(perStaProfile.m_staControl),
344  m_staMacAddress(perStaProfile.m_staMacAddress)
345 {
346  // deep copy of the STA Profile field
347  if (perStaProfile.HasAssocRequest())
348  {
349  m_staProfile = std::make_unique<MgtAssocRequestHeader>(
350  *static_cast<MgtAssocRequestHeader*>(perStaProfile.m_staProfile.get()));
351  }
352  else if (perStaProfile.HasReassocRequest())
353  {
354  m_staProfile = std::make_unique<MgtReassocRequestHeader>(
355  *static_cast<MgtReassocRequestHeader*>(perStaProfile.m_staProfile.get()));
356  }
357  else if (perStaProfile.HasAssocResponse())
358  {
359  m_staProfile = std::make_unique<MgtAssocResponseHeader>(
360  *static_cast<MgtAssocResponseHeader*>(perStaProfile.m_staProfile.get()));
361  }
362 }
363 
366 {
367  // check for self-assignment
368  if (&perStaProfile == this)
369  {
370  return *this;
371  }
372 
373  m_variant = perStaProfile.m_variant;
374  m_frameType = perStaProfile.m_frameType;
375  m_staControl = perStaProfile.m_staControl;
376  m_staMacAddress = perStaProfile.m_staMacAddress;
377 
378  // deep copy of the STA Profile field
379  if (perStaProfile.HasAssocRequest())
380  {
381  m_staProfile = std::make_unique<MgtAssocRequestHeader>(
382  *static_cast<MgtAssocRequestHeader*>(perStaProfile.m_staProfile.get()));
383  }
384  else if (perStaProfile.HasReassocRequest())
385  {
386  m_staProfile = std::make_unique<MgtReassocRequestHeader>(
387  *static_cast<MgtReassocRequestHeader*>(perStaProfile.m_staProfile.get()));
388  }
389  else if (perStaProfile.HasAssocResponse())
390  {
391  m_staProfile = std::make_unique<MgtAssocResponseHeader>(
392  *static_cast<MgtAssocResponseHeader*>(perStaProfile.m_staProfile.get()));
393  }
394 
395  return *this;
396 }
397 
398 void
400 {
401  m_staControl &= 0xfff0; // reset Link ID subfield in the STA Control field
402  m_staControl |= (linkId & 0x0f);
403 }
404 
405 uint8_t
407 {
408  return static_cast<uint8_t>(m_staControl & 0x000f);
409 }
410 
411 void
413 {
414  m_staControl |= 0x0010;
415 }
416 
417 bool
419 {
420  return (m_staControl & 0x0010) != 0;
421 }
422 
423 void
425 {
426  NS_ABORT_IF(m_variant != BASIC_VARIANT);
427  m_staMacAddress = address;
428  m_staControl |= 0x0020;
429 }
430 
431 bool
433 {
434  return (m_staControl & 0x0020) != 0;
435 }
436 
439 {
440  NS_ABORT_IF(!HasStaMacAddress());
441  return m_staMacAddress;
442 }
443 
444 void
446  const std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>& assoc)
447 {
448  switch (m_frameType)
449  {
451  m_staProfile =
452  std::make_unique<MgtAssocRequestHeader>(std::get<MgtAssocRequestHeader>(assoc));
453  break;
455  m_staProfile =
456  std::make_unique<MgtReassocRequestHeader>(std::get<MgtReassocRequestHeader>(assoc));
457  break;
458  default:
459  NS_ABORT_MSG("Invalid frame type: " << m_frameType);
460  }
461 }
462 
463 void
465  std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>&& assoc)
466 {
467  switch (m_frameType)
468  {
470  m_staProfile = std::make_unique<MgtAssocRequestHeader>(
471  std::move(std::get<MgtAssocRequestHeader>(assoc)));
472  break;
474  m_staProfile = std::make_unique<MgtReassocRequestHeader>(
475  std::move(std::get<MgtReassocRequestHeader>(assoc)));
476  break;
477  default:
478  NS_ABORT_MSG("Invalid frame type: " << m_frameType);
479  }
480 }
481 
482 bool
484 {
485  return m_staProfile && m_frameType == WIFI_MAC_MGT_ASSOCIATION_REQUEST;
486 }
487 
488 bool
490 {
491  return m_staProfile && m_frameType == WIFI_MAC_MGT_REASSOCIATION_REQUEST;
492 }
493 
496 {
497  if (HasAssocRequest())
498  {
499  return *static_cast<MgtAssocRequestHeader*>(m_staProfile.get());
500  }
501  NS_ABORT_UNLESS(HasReassocRequest());
502  return *static_cast<MgtReassocRequestHeader*>(m_staProfile.get());
503 }
504 
505 void
507 {
510  m_staProfile = std::make_unique<MgtAssocResponseHeader>(assoc);
511 }
512 
513 void
515 {
518  m_staProfile = std::make_unique<MgtAssocResponseHeader>(std::move(assoc));
519 }
520 
521 bool
523 {
524  return m_staProfile && (m_frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
526 }
527 
530 {
531  NS_ABORT_IF(!HasAssocResponse());
532  return *static_cast<MgtAssocResponseHeader*>(m_staProfile.get());
533 }
534 
535 uint8_t
537 {
538  uint8_t ret = 1; // STA Info Length
539 
540  if (HasStaMacAddress())
541  {
542  ret += 6;
543  }
544  // TODO add other subfields of the STA Info field
545  return ret;
546 }
547 
550 {
552 }
553 
554 uint16_t
556 {
557  uint16_t ret = 2; // STA Control field
558 
559  ret += GetStaInfoLength();
560 
561  if (HasAssocRequest() || HasReassocRequest() || HasAssocResponse())
562  {
563  ret += m_staProfile->GetSerializedSize();
564  }
565 
566  return ret;
567 }
568 
569 void
571 {
572  start.WriteHtolsbU16(m_staControl);
573  start.WriteU8(GetStaInfoLength());
574 
575  if (HasStaMacAddress())
576  {
577  WriteTo(start, m_staMacAddress);
578  }
579  // TODO add other subfields of the STA Info field
580  if (HasAssocRequest() || HasReassocRequest() || HasAssocResponse())
581  {
582  m_staProfile->Serialize(start);
583  }
584 }
585 
586 uint16_t
588  uint16_t length)
589 {
591  uint16_t count = 0;
592 
593  m_staControl = i.ReadLsbtohU16();
594  count += 2;
595 
596  i.ReadU8(); // STA Info Length
597  count++;
598 
599  if (HasStaMacAddress())
600  {
601  ReadFrom(i, m_staMacAddress);
602  count += 6;
603  }
604 
605  // TODO add other subfields of the STA Info field
606 
607  if (count >= length)
608  {
609  return count;
610  }
611 
613  {
614  MgtAssocRequestHeader assoc;
615  count += assoc.Deserialize(i);
616  SetAssocRequest(std::move(assoc));
617  }
619  {
620  MgtReassocRequestHeader reassoc;
621  count += reassoc.Deserialize(i);
622  SetAssocRequest(std::move(reassoc));
623  }
626  {
628  count += assoc.Deserialize(i);
629  SetAssocResponse(assoc);
630  }
631 
632  return count;
633 }
634 
635 void
637 {
638  auto variant = GetVariant();
639  NS_ABORT_IF(variant == UNSET);
641  m_perStaProfileSubelements.emplace_back(variant, m_frameType);
642 }
643 
644 std::size_t
646 {
647  return m_perStaProfileSubelements.size();
648 }
649 
652 {
653  return m_perStaProfileSubelements.at(i);
654 }
655 
658 {
659  return m_perStaProfileSubelements.at(i);
660 }
661 
662 uint16_t
664 {
665  uint16_t ret = 3; // ElementIdExt (1) + Multi-Link Control (2)
666 
667  // add the Common Info field size (dependent on the Multi-Link Element variant)
668  ret += std::visit(
669  [](auto&& arg) -> uint8_t {
670  using T = std::decay_t<decltype(arg)>;
671  if constexpr (std::is_same_v<T, std::monostate>)
672  {
673  NS_ABORT_MSG("Multi-Link Element variant not set");
674  return 0;
675  }
676  else
677  {
678  return arg.GetSize();
679  }
680  },
681  m_commonInfo);
682 
683  for (const auto& subelement : m_perStaProfileSubelements)
684  {
685  ret += subelement.GetSerializedSize();
686  }
687 
688  return ret;
689 }
690 
691 void
693 {
694  // serialize the Multi-Link Control and Common Info fields
695  std::visit(
696  [this, &start](auto&& arg) {
697  using T = std::decay_t<decltype(arg)>;
698  if constexpr (std::is_same_v<T, std::monostate>)
699  {
700  NS_ABORT_MSG("Multi-Link Element variant not set");
701  }
702  else
703  {
704  uint16_t mlControl =
705  static_cast<uint8_t>(GetVariant()) + (arg.GetPresenceBitmap() << 4);
706  start.WriteHtolsbU16(mlControl);
707  arg.Serialize(start);
708  }
709  },
710  m_commonInfo);
711 
712  for (const auto& subelement : m_perStaProfileSubelements)
713  {
714  start = subelement.Serialize(start);
715  }
716 }
717 
718 uint16_t
720 {
722  uint16_t count = 0;
723 
724  uint16_t mlControl = i.ReadLsbtohU16();
725  count += 2;
726 
727  SetVariant(static_cast<Variant>(mlControl & 0x0007));
728  uint16_t presence = mlControl >> 4;
729 
730  uint8_t nBytes = std::visit(
731  [&i, &presence](auto&& arg) -> uint8_t {
732  using T = std::decay_t<decltype(arg)>;
733  if constexpr (std::is_same_v<T, std::monostate>)
734  {
735  NS_ABORT_MSG("Multi-Link Element variant not set");
736  return 0;
737  }
738  else
739  {
740  return arg.Deserialize(i, presence);
741  }
742  },
743  m_commonInfo);
744  i.Next(nBytes);
745  count += nBytes;
746 
747  while (count < length)
748  {
749  switch (static_cast<SubElementId>(i.PeekU8()))
750  {
754  count = i.GetDistanceFrom(start);
755  break;
756  default:
757  NS_ABORT_MSG("Unsupported Subelement ID: " << +i.PeekU8());
758  }
759  }
760 
761  return count;
762 }
763 
764 } // namespace ns3
iterator in a Buffer instance
Definition: buffer.h:100
uint8_t ReadU8()
Definition: buffer.h:1027
uint16_t ReadLsbtohU16()
Definition: buffer.cc:1067
uint8_t PeekU8()
Definition: buffer.h:1006
uint32_t GetDistanceFrom(const Iterator &o) const
Definition: buffer.cc:783
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 request.
Definition: mgt-headers.h:55
uint32_t Deserialize(Buffer::Iterator start) override
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:447
uint32_t Deserialize(Buffer::Iterator start) override
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:248
uint32_t Deserialize(Buffer::Iterator start) override
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
Buffer::Iterator Deserialize(Buffer::Iterator i)
Deserialize entire IE (which may possibly be fragmented into multiple elements), which must be presen...
#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_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.
address
Definition: first.py:40
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:54
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
@ WIFI_MAC_MGT_REASSOCIATION_REQUEST
@ WIFI_MAC_DATA
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
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.
value
Definition: second.py:41
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.
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.
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.
#define IE_EXTENSION
#define IE_EXT_MULTI_LINK_ELEMENT