A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-mgt-header.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#ifndef WIFI_MGT_HEADER_H
10#define WIFI_MGT_HEADER_H
11
12#include "non-inheritance.h"
13#include "supported-rates.h"
14
15#include "ns3/eht-capabilities.h"
16#include "ns3/he-6ghz-band-capabilities.h"
17#include "ns3/header.h"
18#include "ns3/multi-link-element.h"
19#include "ns3/vht-capabilities.h"
20
21#include <algorithm>
22#include <iterator>
23#include <numeric>
24#include <optional>
25#include <utility>
26#include <vector>
27
28namespace ns3
29{
30
31namespace internal
32{
33
34/**
35 * @ingroup object
36 * @tparam T \explicit An Information Element type
37 *
38 * Provides the type used to store Information Elements in the tuple held by WifiMgtHeader:
39 * - a mandatory Information Element of type T is stored as std::optional<T>
40 * - an optional Information Element of type T is stored as std::optional<T>
41 * - an Information Element of type T that can appear 0 or more times is stored as std::vector<T>
42 */
43template <class T>
45{
46 /// typedef for the resulting optional type
47 typedef std::optional<T> type;
48};
49
50/** @copydoc GetStoredIe */
51template <class T>
52struct GetStoredIe<std::optional<T>>
53{
54 /// typedef for the resulting optional type
55 typedef std::optional<T> type;
56};
57
58/** @copydoc GetStoredIe */
59template <class T>
60struct GetStoredIe<std::vector<T>>
61{
62 /// typedef for the resulting optional type
63 typedef std::vector<T> type;
64};
65
66/** @copydoc GetStoredIe */
67template <class T>
69
70} // namespace internal
71
72/**
73 * @ingroup wifi
74 * Implement the header for management frames.
75 * @tparam Derived \explicit the type of derived management frame
76 * @tparam Tuple \explicit A tuple of the types of Information Elements included in the mgt frame
77 */
78template <typename Derived, typename Tuple>
80
81/**
82 * @ingroup wifi
83 * Base class for implementing management frame headers. This class adopts the CRTP idiom,
84 * mainly to allow subclasses to specialize the method used to initialize Information
85 * Elements before deserialization (<i>InitForDeserialization</i>).
86 *
87 * The sorted list of Information Elements that can be included in the management frame implemented
88 * as a subclass of this class is provided as the template parameter pack. Specifically:
89 * - the type of a mandatory Information Element IE is IE
90 * - the type of an optional Information Element IE is std::optional<IE>
91 * - the type of an Information Element IE that can appear zero or more times is std::vector<IE>
92 *
93 * @tparam Derived \explicit the type of derived management frame
94 * @tparam Elems \explicit sorted list of Information Elements that can be included in mgt frame
95 */
96template <typename Derived, typename... Elems>
97class WifiMgtHeader<Derived, std::tuple<Elems...>> : public Header
98{
99 public:
100 /**
101 * Access a (mandatory or optional) Information Element.
102 *
103 * @tparam T \explicit the type of the Information Element to return
104 * @return a reference to the Information Element of the given type
105 */
106 template <typename T,
107 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int> = 0>
108 std::optional<T>& Get();
109
110 /**
111 * Access a (mandatory or optional) Information Element.
112 *
113 * @tparam T \explicit the type of the Information Element to return
114 * @return a const reference to the Information Element of the given type
115 */
116 template <typename T,
117 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int> = 0>
118 const std::optional<T>& Get() const;
119
120 /**
121 * Access an Information Element that can be present zero or more times.
122 *
123 * @tparam T \explicit the type of the Information Element to return
124 * @return a reference to the Information Element of the given type
125 */
126 template <typename T,
127 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int> = 0>
128 std::vector<T>& Get();
129
130 /**
131 * Access an Information Element that can be present zero or more times.
132 *
133 * @tparam T \explicit the type of the Information Element to return
134 * @return a reference to the Information Element of the given type
135 */
136 template <typename T,
137 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int> = 0>
138 const std::vector<T>& Get() const;
139
140 void Print(std::ostream& os) const final;
141 uint32_t GetSerializedSize() const final;
142 void Serialize(Buffer::Iterator start) const final;
143 uint32_t Deserialize(Buffer::Iterator start) final;
144
145 protected:
146 /**
147 * @tparam IE \deduced the type of the Information Element to initialize for deserialization
148 * @param optElem the object to initialize for deserializing the information element into
149 *
150 * The Information Element object is constructed by calling the object's default constructor.
151 */
152 template <typename IE>
153 void InitForDeserialization(std::optional<IE>& optElem);
154
155 /**
156 * @param optElem the EhtCapabilities object to initialize for deserializing the
157 * information element into
158 */
159 void InitForDeserialization(std::optional<EhtCapabilities>& optElem);
160
161 /** @copydoc ns3::Header::Print */
162 void PrintImpl(std::ostream& os) const;
163 /** @copydoc ns3::Header::GetSerializedSize */
164 uint32_t GetSerializedSizeImpl() const;
165 /** @copydoc ns3::Header::Serialize */
166 void SerializeImpl(Buffer::Iterator start) const;
167 /** @copydoc ns3::Header::Deserialize */
168 uint32_t DeserializeImpl(Buffer::Iterator start);
169
170 /**
171 * @tparam T \deduced the type of the Information Element
172 * @param elem the optional Information Element
173 * @param start the buffer iterator pointing to where deserialization starts
174 * @return an iterator pointing to where deserialization terminated
175 */
176 template <typename T>
177 Buffer::Iterator DoDeserialize(std::optional<T>& elem, Buffer::Iterator start);
178
179 /**
180 * @tparam T \deduced the type of the Information Elements
181 * @param elems a vector of Information Elements
182 * @param start the buffer iterator pointing to where deserialization starts
183 * @return an iterator pointing to where deserialization terminated
184 */
185 template <typename T>
186 Buffer::Iterator DoDeserialize(std::vector<T>& elems, Buffer::Iterator start);
187
188 /// type of the Information Elements contained by this frame
189 using Elements = std::tuple<internal::GetStoredIeT<Elems>...>;
190
191 Elements m_elements; //!< Information Elements contained by this frame
192};
193
194/**
195 * @ingroup wifi
196 * Inspect a type to deduce whether it is an Information Element that can be included in a
197 * Per-STA Profile subelement of a Multi-Link Element.
198 * @tparam T \explicit The type to inspect.
199 */
200template <class T>
201struct CanBeInPerStaProfile : std::true_type
202{
203};
204
205/** @copydoc CanBeInPerStaProfile */
206template <class T>
208
209/**
210 * @ingroup wifi
211 * Implement the header for management frames that can be included in a Per-STA Profile
212 * subelement of a Multi-Link Element.
213 * @tparam Derived \explicit the type of derived management frame
214 * @tparam Tuple \explicit A tuple of the types of Information Elements included in the mgt frame
215 */
216template <typename Derived, typename Tuple>
218
219/**
220 * @ingroup wifi
221 *
222 * Add methods needed to serialize/deserialize a management header into a Per-STA Profile
223 * subelement of a Multi-Link Element.
224 *
225 * @tparam Derived \explicit the type of derived management frame
226 * @tparam Elems \explicit sorted list of Information Elements that can be included in mgt frame
227 */
228template <typename Derived, typename... Elems>
229class MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>
230 : public WifiMgtHeader<Derived, std::tuple<Elems...>>
231{
232 public:
233 /**
234 * @param frame the frame containing the Multi-Link Element
235 * @return the number of bytes that are needed to serialize this header into a Per-STA Profile
236 * subelement of the Multi-Link Element
237 */
238 uint32_t GetSerializedSizeInPerStaProfile(const Derived& frame) const;
239
240 /**
241 * Serialize this header into a Per-STA Profile subelement of a Multi-Link Element
242 *
243 * @param start an iterator which points to where the header should be written
244 * @param frame the frame containing the Multi-Link Element
245 */
246 void SerializeInPerStaProfile(Buffer::Iterator start, const Derived& frame) const;
247
248 /**
249 * Deserialize this header from a Per-STA Profile subelement of a Multi-Link Element.
250 *
251 * @param start an iterator which points to where the header should be read from
252 * @param length the expected number of bytes to read
253 * @param frame the frame containing the Multi-Link Element
254 * @return the number of bytes read
255 */
256 uint32_t DeserializeFromPerStaProfile(Buffer::Iterator start,
257 uint16_t length,
258 const Derived& frame);
259
260 /**
261 * Copy Information Elements inherited from the management frame containing the Multi-Link
262 * Element into this header (which is stored in a Per-STA Profile subelement). This method
263 * shall be invoked when the deserialization has been completed (i.e., the Non-Inheritance
264 * element, if present, has been deserialized).
265 *
266 * @param frame the frame containing the Multi-Link Element
267 */
268 void CopyIesFromContainingFrame(const Derived& frame);
269
270 protected:
271 using WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization;
272
273 /**
274 * @param frame the frame containing the Multi-Link Element
275 * @return the number of bytes that are needed to serialize this header into a Per-STA Profile
276 * subelement of the Multi-Link Element
277 */
278 uint32_t GetSerializedSizeInPerStaProfileImpl(const Derived& frame) const;
279
280 /**
281 * Serialize this header into a Per-STA Profile subelement of a Multi-Link Element
282 *
283 * @param start an iterator which points to where the header should be written
284 * @param frame the frame containing the Multi-Link Element
285 */
286 void SerializeInPerStaProfileImpl(Buffer::Iterator start, const Derived& frame) const;
287
288 /**
289 * Deserialize this header from a Per-STA Profile subelement of a Multi-Link Element.
290 *
291 * @param start an iterator which points to where the header should be read from
292 * @param length the expected number of bytes to read
293 * @param frame the frame containing the Multi-Link Element
294 * @return the number of bytes read
295 */
296 uint32_t DeserializeFromPerStaProfileImpl(Buffer::Iterator start,
297 uint16_t length,
298 const Derived& frame);
299
300 /**
301 * Pass a pointer to this frame to the Multi-Link Element (if any) included in this frame.
302 */
303 void SetMleContainingFrame() const;
304
305 /**
306 * @param optElem the MultiLinkElement object to initialize for deserializing the
307 * information element into
308 */
309 void InitForDeserialization(std::optional<MultiLinkElement>& optElem);
310
311 private:
312 using WifiMgtHeader<Derived, std::tuple<Elems...>>::DoDeserialize;
313 using WifiMgtHeader<Derived, std::tuple<Elems...>>::m_elements;
314
315 std::optional<NonInheritance> m_nonInheritance; /**< the Non-Inheritance IE possibly appended
316 to the Per-STA Profile subelement */
317};
318
319//
320// Implementation of the templates declared above.
321//
322
323template <typename Derived, typename... Elems>
324template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int>>
325std::optional<T>&
326WifiMgtHeader<Derived, std::tuple<Elems...>>::Get()
327{
328 return std::get<std::optional<T>>(m_elements);
329}
330
331template <typename Derived, typename... Elems>
332template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int>>
333const std::optional<T>&
334WifiMgtHeader<Derived, std::tuple<Elems...>>::Get() const
335{
336 return std::get<std::optional<T>>(m_elements);
337}
338
339template <typename Derived, typename... Elems>
340template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int>>
341std::vector<T>&
342WifiMgtHeader<Derived, std::tuple<Elems...>>::Get()
343{
344 return std::get<std::vector<T>>(m_elements);
345}
346
347template <typename Derived, typename... Elems>
348template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int>>
349const std::vector<T>&
350WifiMgtHeader<Derived, std::tuple<Elems...>>::Get() const
351{
352 return std::get<std::vector<T>>(m_elements);
353}
354
355template <typename Derived, typename... Elems>
356template <typename IE>
357void
358WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization(std::optional<IE>& optElem)
359{
360 optElem.emplace();
361}
362
363template <typename Derived, typename... Elems>
364void
365WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization(
366 std::optional<EhtCapabilities>& optElem)
367{
368 auto& vhtCapabilities = Get<VhtCapabilities>();
369 auto& he6GhzBandCapabilities = Get<He6GhzBandCapabilities>();
370 const auto is2_4Ghz = !vhtCapabilities && !he6GhzBandCapabilities;
371 auto& heCapabilities = Get<HeCapabilities>();
372 if (heCapabilities)
373 {
374 optElem.emplace(is2_4Ghz, heCapabilities.value());
375 }
376 else
377 {
378 optElem.emplace();
379 }
380}
381
382template <typename Derived, typename... Elems>
383void
384MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::InitForDeserialization(
385 std::optional<MultiLinkElement>& optElem)
386{
387 optElem.emplace(*static_cast<const Derived*>(this));
388}
389
390namespace internal
391{
392
393/**
394 * @tparam T \deduced the type of the Information Element
395 * @param elem the optional Information Element
396 * @return the serialized size of the Information Element, if present, or 0, otherwise
397 */
398template <typename T>
399uint16_t
400DoGetSerializedSize(const std::optional<T>& elem)
401{
402 return elem.has_value() ? elem->GetSerializedSize() : 0;
403}
404
405/**
406 * @tparam T \deduced the type of the Information Elements
407 * @param elems a vector of Information Elements
408 * @return the serialized size of the Information Elements
409 */
410template <typename T>
411uint16_t
412DoGetSerializedSize(const std::vector<T>& elems)
413{
414 return std::accumulate(elems.cbegin(), elems.cend(), 0, [](uint16_t a, const auto& b) {
415 return b.GetSerializedSize() + a;
416 });
417}
418
419} // namespace internal
420
421template <typename Derived, typename... Elems>
423WifiMgtHeader<Derived, std::tuple<Elems...>>::GetSerializedSize() const
424{
425 return static_cast<const Derived*>(this)->GetSerializedSizeImpl();
426}
427
428template <typename Derived, typename... Elems>
430WifiMgtHeader<Derived, std::tuple<Elems...>>::GetSerializedSizeImpl() const
431{
432 return std::apply([&](auto&... elems) { return (internal::DoGetSerializedSize(elems) + ...); },
433 m_elements);
434}
435
436namespace internal
437{
438
439/**
440 * @tparam T \deduced the type of the Information Element
441 * @param elem the optional Information Element
442 * @param start the buffer iterator pointing to where serialization starts
443 * @return an iterator pointing to where serialization terminated
444 */
445template <typename T>
447DoSerialize(const std::optional<T>& elem, Buffer::Iterator start)
448{
449 return elem.has_value() ? elem->Serialize(start) : start;
450}
451
452/**
453 * @tparam T \deduced the type of the Information Elements
454 * @param elems a vector of Information Elements
455 * @param start the buffer iterator pointing to where serialization starts
456 * @return an iterator pointing to where serialization terminated
457 */
458template <typename T>
460DoSerialize(const std::vector<T>& elems, Buffer::Iterator start)
461{
462 return std::accumulate(elems.cbegin(),
463 elems.cend(),
464 start,
465 [](Buffer::Iterator i, const auto& a) { return a.Serialize(i); });
466}
467
468} // namespace internal
469
470template <typename Derived, typename... Elems>
471void
472WifiMgtHeader<Derived, std::tuple<Elems...>>::Serialize(Buffer::Iterator start) const
473{
474 static_cast<const Derived*>(this)->SerializeImpl(start);
475}
476
477template <typename Derived, typename... Elems>
478void
479WifiMgtHeader<Derived, std::tuple<Elems...>>::SerializeImpl(Buffer::Iterator start) const
480{
481 auto i = start;
482 std::apply([&](auto&... elems) { ((i = internal::DoSerialize(elems, i)), ...); }, m_elements);
483}
484
485template <typename Derived, typename... Elems>
486template <typename T>
488WifiMgtHeader<Derived, std::tuple<Elems...>>::DoDeserialize(std::optional<T>& elem,
489 Buffer::Iterator start)
490{
491 auto i = start;
492 static_cast<Derived*>(this)->InitForDeserialization(elem);
493 i = elem->DeserializeIfPresent(i);
494 if (i.GetDistanceFrom(start) == 0)
495 {
496 elem.reset(); // the element is not present
497 }
498 return i;
499}
500
501template <typename Derived, typename... Elems>
502template <typename T>
504WifiMgtHeader<Derived, std::tuple<Elems...>>::DoDeserialize(std::vector<T>& elems,
505 Buffer::Iterator start)
506{
507 auto i = start;
508 do
509 {
510 auto tmp = i;
511 std::optional<T> item;
512 static_cast<Derived*>(this)->InitForDeserialization(item);
513 i = item->DeserializeIfPresent(i);
514 if (i.GetDistanceFrom(tmp) == 0)
515 {
516 break;
517 }
518 elems.push_back(std::move(*item));
519 } while (true);
520 return i;
521}
522
523template <typename Derived, typename... Elems>
525WifiMgtHeader<Derived, std::tuple<Elems...>>::Deserialize(Buffer::Iterator start)
526{
527 return static_cast<Derived*>(this)->DeserializeImpl(start);
528}
529
530template <typename Derived, typename... Elems>
532WifiMgtHeader<Derived, std::tuple<Elems...>>::DeserializeImpl(Buffer::Iterator start)
533{
534 auto i = start;
535
536 std::apply(
537 // auto cannot be used until gcc 10.4 due to gcc bug 97938
538 // (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97938)
539 [&](internal::GetStoredIeT<Elems>&... elems) {
540 (
541 [&] {
542 if constexpr (std::is_same_v<std::remove_reference_t<decltype(elems)>, Elems>)
543 {
544 // optional IE or IE that can be present 0 or more times
545 i = DoDeserialize(elems, i);
546 }
547 else
548 {
549 // mandatory IE
550 static_cast<Derived*>(this)->InitForDeserialization(elems);
551 i = elems->Deserialize(i);
552 }
553 }(),
554 ...);
555 },
556 m_elements);
557
558 return i.GetDistanceFrom(start);
559}
560
561namespace internal
562{
563
564/**
565 * @tparam T \deduced the type of the Information Element
566 * @param elem the optional Information Element
567 * @param os the output stream
568 */
569template <typename T>
570void
571DoPrint(const std::optional<T>& elem, std::ostream& os)
572{
573 if (elem.has_value())
574 {
575 os << *elem << ", ";
576 }
577}
578
579/**
580 * @tparam T \deduced the type of the Information Elements
581 * @param elems a vector of Information Elements
582 * @param os the output stream
583 */
584template <typename T>
585void
586DoPrint(const std::vector<T>& elems, std::ostream& os)
587{
588 std::copy(elems.cbegin(), elems.cend(), std::ostream_iterator<T>(os, " , "));
589}
590
591} // namespace internal
592
593template <typename Derived, typename... Elems>
594void
595WifiMgtHeader<Derived, std::tuple<Elems...>>::Print(std::ostream& os) const
596{
597 static_cast<const Derived*>(this)->PrintImpl(os);
598}
599
600template <typename Derived, typename... Elems>
601void
602WifiMgtHeader<Derived, std::tuple<Elems...>>::PrintImpl(std::ostream& os) const
603{
604 std::apply([&](auto&... elems) { ((internal::DoPrint(elems, os)), ...); }, m_elements);
605}
606
607namespace internal
608{
609
610/**
611 * @tparam T \deduced the type of the given Information Element
612 * @tparam Derived \deduced the type of the containing management frame
613 * @param elem the given Information Element
614 * @param frame the containing management frame
615 * @return whether the given Information Element shall be serialized in a Per-STA Profile
616 * subelement of the Multi-Link Element included in the containing management frame
617 */
618template <typename T, typename Derived>
619bool
620MustBeSerializedInPerStaProfile(const std::optional<T>& elem, const Derived& frame)
621{
623 {
624 return false;
625 }
626
627 if (auto& outsideIe = frame.template Get<T>();
628 outsideIe.has_value() && elem.has_value() && !(outsideIe.value() == elem.value()))
629 {
630 // the IE is present both outside the Multi-Link Element and in the Per-STA Profile,
631 // but they are different, hence the IE must be serialized in the Per-STA Profile
632 return true;
633 }
634
635 if (!frame.template Get<T>().has_value() && elem.has_value())
636 {
637 // the IE is not present outside the Multi-Link Element and is present in the Per-STA
638 // Profile, hence the IE must be serialized in the Per-STA Profile
639 return true;
640 }
641
642 return false;
643}
644
645/**
646 * @tparam T \deduced the type of the given vector of Information Elements
647 * @tparam Derived \deduced the type of the containing management frame
648 * @param elems the given vector of Information Elements
649 * @param frame the containing management frame
650 * @return whether the given Information Elements shall be serialized in a Per-STA Profile
651 * subelement of the Multi-Link Element included in the containing management frame
652 */
653template <typename T, typename Derived>
654bool
655MustBeSerializedInPerStaProfile(const std::vector<T>& elems, const Derived& frame)
656{
658 {
659 return false;
660 }
661
662 if (auto& outsideIe = frame.template Get<T>();
663 !outsideIe.empty() && !elems.empty() && !(outsideIe == elems))
664 {
665 // the IEs are present both outside the Multi-Link Element and in the Per-STA Profile,
666 // but they are different, hence the IEs must be serialized in the Per-STA Profile
667 return true;
668 }
669
670 if (frame.template Get<T>().empty() && !elems.empty())
671 {
672 // the IEs are not present outside the Multi-Link Element and is present in the Per-STA
673 // Profile, hence the IEs must be serialized in the Per-STA Profile
674 return true;
675 }
676
677 return false;
678}
679
680/**
681 * @tparam T \deduced the type of the given Information Element
682 * @tparam Derived \deduced the type of the containing management frame
683 * @param elem the given Information Element
684 * @param frame the containing management frame
685 * @return a pair (Element ID, Element ID Extension) if the given Information Element shall be
686 * listed in the Non-Inheritance IE of the Per-STA Profile subelement of the Multi-Link
687 * Element included in the containing management frame
688 */
689template <typename T, typename Derived>
690std::optional<std::pair<uint8_t, uint8_t>>
691MustBeListedInNonInheritance(const std::optional<T>& elem, const Derived& frame)
692{
693 if (auto& outsideIe = frame.template Get<T>();
694 CanBeInPerStaProfileV<T> && outsideIe.has_value() && !elem.has_value())
695 {
696 return {{outsideIe->ElementId(), outsideIe->ElementIdExt()}};
697 }
698 return std::nullopt;
699}
700
701/**
702 * @tparam T \deduced the type of the given vector of Information Elements
703 * @tparam Derived \deduced the type of the containing management frame
704 * @param elems the given Information Elements
705 * @param frame the containing management frame
706 * @return a pair (Element ID, Element ID Extension) if the given Information Element shall be
707 * listed in the Non-Inheritance IE of the Per-STA Profile subelement of the Multi-Link
708 * Element included in the containing management frame
709 */
710template <typename T, typename Derived>
711std::optional<std::pair<uint8_t, uint8_t>>
712MustBeListedInNonInheritance(const std::vector<T>& elems, const Derived& frame)
713{
714 if (auto& outsideIe = frame.template Get<T>();
715 CanBeInPerStaProfileV<T> && !outsideIe.empty() && elems.empty())
716 {
717 return {{outsideIe.front().ElementId(), outsideIe.front().ElementIdExt()}};
718 }
719 return std::nullopt;
720}
721
722} // namespace internal
723
724template <typename Derived, typename... Elems>
726MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::GetSerializedSizeInPerStaProfile(
727 const Derived& frame) const
728{
729 return static_cast<const Derived*>(this)->GetSerializedSizeInPerStaProfileImpl(frame);
730}
731
732template <typename Derived, typename... Elems>
734MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::GetSerializedSizeInPerStaProfileImpl(
735 const Derived& frame) const
736{
737 uint32_t size = 0;
738 std::optional<NonInheritance> nonInheritance;
739
740 std::apply(
741 [&](auto&... elems) {
742 (
743 [&] {
745 {
746 size += internal::DoGetSerializedSize(elems);
747 }
748 else if (auto idPair = internal::MustBeListedInNonInheritance(elems, frame))
749 {
750 if (!nonInheritance)
751 {
752 nonInheritance.emplace();
753 }
754 nonInheritance->Add(idPair->first, idPair->second);
755 }
756 }(),
757 ...);
758 },
759 m_elements);
760
761 if (nonInheritance)
762 {
763 size += nonInheritance->GetSerializedSize();
764 }
765 return size;
766}
767
768template <typename Derived, typename... Elems>
769void
770MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::SerializeInPerStaProfile(
771 Buffer::Iterator start,
772 const Derived& frame) const
773{
774 static_cast<const Derived*>(this)->SerializeInPerStaProfileImpl(start, frame);
775}
776
777template <typename Derived, typename... Elems>
778void
779MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::SerializeInPerStaProfileImpl(
780 Buffer::Iterator start,
781 const Derived& frame) const
782{
783 auto i = start;
784 std::optional<NonInheritance> nonInheritance;
785
786 std::apply(
787 [&](auto&... elems) {
788 (
789 [&] {
791 {
792 i = internal::DoSerialize(elems, i);
793 }
794 else if (auto idPair = internal::MustBeListedInNonInheritance(elems, frame))
795 {
796 if (!nonInheritance)
797 {
798 nonInheritance.emplace();
799 }
800 nonInheritance->Add(idPair->first, idPair->second);
801 }
802 }(),
803 ...);
804 },
805 m_elements);
806
807 if (nonInheritance)
808 {
809 nonInheritance->Serialize(i);
810 }
811}
812
813namespace internal
814{
815
816/**
817 * @tparam T \deduced the type of the given Information Element
818 * @tparam Derived \deduced the type of the containing management frame
819 * @param elem the given Information Element
820 * @param frame the containing management frame
821 *
822 * Copy the given Information Element from the containing frame to the Per-STA Profile subelement
823 * of the Multi-Link Element, if the Information Element has been inherited (i.e., it is present
824 * outside the Multi-Link Element and not present in the Per-STA Profile subelement)
825 */
826template <typename T, typename Derived>
827void
828DoCopyIeFromContainingFrame(std::optional<T>& elem, const Derived& frame)
829{
830 if (auto& outsideIe = frame.template Get<T>();
831 CanBeInPerStaProfileV<T> && outsideIe.has_value() && !elem.has_value())
832 {
833 elem = outsideIe.value();
834 }
835}
836
837/**
838 * @tparam T \deduced the type of the given vector of Information Elements
839 * @tparam Derived \deduced the type of the containing management frame
840 * @param elems the given vector of Information Elements
841 * @param frame the containing management frame
842 *
843 * Copy the given Information Element from the containing frame to the Per-STA Profile subelement
844 * of the Multi-Link Element, if the Information Element has been inherited (i.e., it is present
845 * outside the Multi-Link Element and not present in the Per-STA Profile subelement)
846 */
847template <typename T, typename Derived>
848void
849DoCopyIeFromContainingFrame(std::vector<T>& elems, const Derived& frame)
850{
851 if (auto& outsideIe = frame.template Get<T>();
852 CanBeInPerStaProfileV<T> && !outsideIe.empty() && elems.empty())
853 {
854 elems = outsideIe;
855 }
856}
857
858} // namespace internal
859
860template <typename Derived, typename... Elems>
862MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::DeserializeFromPerStaProfile(
863 Buffer::Iterator start,
864 uint16_t length,
865 const Derived& frame)
866{
867 return static_cast<Derived*>(this)->DeserializeFromPerStaProfileImpl(start, length, frame);
868}
869
870template <typename Derived, typename... Elems>
872MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::DeserializeFromPerStaProfileImpl(
873 Buffer::Iterator start,
874 uint16_t length,
875 const Derived& frame)
876{
877 auto i = start;
878
879 // deserialize the IEs in the Per-STA Profile subelement
880 std::apply(
881 [&](auto&... elems) {
882 (
883 [&] {
884 if (i.GetDistanceFrom(start) < length)
885 {
886 i = static_cast<Derived*>(this)->DoDeserialize(elems, i);
887 internal::DoCopyIeFromContainingFrame(elems, frame);
888 }
889 }(),
890 ...);
891 },
892 m_elements);
893
894 // deserialize the Non-Inheritance IE, if present
895 m_nonInheritance.reset();
896 i = DoDeserialize(m_nonInheritance, i);
897
898 auto distance = i.GetDistanceFrom(start);
899 NS_ASSERT_MSG(distance == length,
900 "Bytes read (" << distance << ") not matching expected number (" << length
901 << ")");
902 return distance;
903}
904
905namespace internal
906{
907
908/**
909 * @tparam T \deduced the type of the given Information Element
910 * @param elem the given Information Element
911 * @param nonInheritance the Non-Inheritance information element
912 *
913 * Remove the given Information Element from this header, if it is present and is listed in
914 * the given Non-Inheritance element.
915 */
916template <typename T>
917void
918RemoveIfNotInherited(std::optional<T>& elem, const NonInheritance& nonInheritance)
919{
920 if (elem.has_value() && nonInheritance.IsPresent(elem->ElementId(), elem->ElementIdExt()))
921 {
922 elem.reset();
923 }
924}
925
926/**
927 * @tparam T \deduced the type of the given vector of Information Elements
928 * @param elem the given Information Elements
929 * @param nonInheritance the Non-Inheritance information element
930 *
931 * Remove the given Information Elements from this header, if they are present and are listed in
932 * the given Non-Inheritance element.
933 */
934template <typename T>
935void
936RemoveIfNotInherited(std::vector<T>& elem, const NonInheritance& nonInheritance)
937{
938 if (!elem.empty() &&
939 nonInheritance.IsPresent(elem.front().ElementId(), elem.front().ElementIdExt()))
940 {
941 elem.clear();
942 }
943}
944
945} // namespace internal
946
947template <typename Derived, typename... Elems>
948void
949MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::CopyIesFromContainingFrame(
950 const Derived& frame)
951{
952 // copy inherited Information Elements that appear in the containing frame after the
953 // MLE (those appearing before have been copied by DeserializeFromPerStaProfileImpl)
954 std::apply(
955 [&](auto&... elems) { ((internal::DoCopyIeFromContainingFrame(elems, frame)), ...); },
956 m_elements);
957
958 // we have possibly deserialized a Non-Inheritance element; remove IEs listed therein
959 if (m_nonInheritance)
960 {
961 std::apply(
962 [&](auto&... elems) {
963 ((internal::RemoveIfNotInherited(elems, *m_nonInheritance)), ...);
964 },
965 m_elements);
966 }
967}
968
969template <typename Derived, typename... Elems>
970void
971MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>::SetMleContainingFrame() const
972{
973 if (auto& mle = WifiMgtHeader<Derived, std::tuple<Elems...>>::template Get<MultiLinkElement>())
974 {
975 mle->m_containingFrame = *static_cast<const Derived*>(this);
976 }
977}
978
979} // namespace ns3
980
981#endif /* WIFI_MGT_HEADER_H */
Simple class derived from ns3::Object, used to check attribute constructors.
iterator in a Buffer instance
Definition buffer.h:89
Protocol header serialization and deserialization.
Definition header.h:33
std::optional< NonInheritance > m_nonInheritance
the Non-Inheritance IE possibly appended to the Per-STA Profile subelement
Implement the header for management frames that can be included in a Per-STA Profile subelement of a ...
The IEEE 802.11 Non-Inheritance Information Element.
bool IsPresent(uint8_t elemId, uint8_t elemIdExt=0) const
Elements m_elements
Information Elements contained by this frame.
std::tuple< internal::GetStoredIeT< Elems >... > Elements
type of the Information Elements contained by this frame
Implement the header for management frames.
#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:75
void Print(ComponentCarrier cc)
void DoPrint(const std::optional< T > &elem, std::ostream &os)
bool MustBeSerializedInPerStaProfile(const std::optional< T > &elem, const Derived &frame)
void DoCopyIeFromContainingFrame(std::optional< T > &elem, const Derived &frame)
uint16_t DoGetSerializedSize(const std::optional< T > &elem)
std::optional< std::pair< uint8_t, uint8_t > > MustBeListedInNonInheritance(const std::optional< T > &elem, const Derived &frame)
void RemoveIfNotInherited(std::optional< T > &elem, const NonInheritance &nonInheritance)
Buffer::Iterator DoSerialize(const std::optional< T > &elem, Buffer::Iterator start)
typename GetStoredIe< T >::type GetStoredIeT
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr bool CanBeInPerStaProfileV
Inspect a type to deduce whether it is an Information Element that can be included in a Per-STA Profi...
STL namespace.
Inspect a type to deduce whether it is an Information Element that can be included in a Per-STA Profi...
std::optional< T > type
typedef for the resulting optional type
std::vector< T > type
typedef for the resulting optional type
std::optional< T > type
typedef for the resulting optional type