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/header.h"
17#include "ns3/multi-link-element.h"
18
19#include <algorithm>
20#include <iterator>
21#include <numeric>
22#include <optional>
23#include <utility>
24#include <vector>
25
26namespace ns3
27{
28
29namespace internal
30{
31
32/**
33 * \ingroup object
34 * \tparam T \explicit An Information Element type
35 *
36 * Provides the type used to store Information Elements in the tuple held by WifiMgtHeader:
37 * - a mandatory Information Element of type T is stored as std::optional<T>
38 * - an optional Information Element of type T is stored as std::optional<T>
39 * - an Information Element of type T that can appear 0 or more times is stored as std::vector<T>
40 */
41template <class T>
43{
44 /// typedef for the resulting optional type
45 typedef std::optional<T> type;
46};
47
48/** \copydoc GetStoredIe */
49template <class T>
50struct GetStoredIe<std::optional<T>>
51{
52 /// typedef for the resulting optional type
53 typedef std::optional<T> type;
54};
55
56/** \copydoc GetStoredIe */
57template <class T>
58struct GetStoredIe<std::vector<T>>
59{
60 /// typedef for the resulting optional type
61 typedef std::vector<T> type;
62};
63
64/** \copydoc GetStoredIe */
65template <class T>
67
68} // namespace internal
69
70/**
71 * \ingroup wifi
72 * Implement the header for management frames.
73 * \tparam Derived \explicit the type of derived management frame
74 * \tparam Tuple \explicit A tuple of the types of Information Elements included in the mgt frame
75 */
76template <typename Derived, typename Tuple>
78
79/**
80 * \ingroup wifi
81 * Base class for implementing management frame headers. This class adopts the CRTP idiom,
82 * mainly to allow subclasses to specialize the method used to initialize Information
83 * Elements before deserialization (<i>InitForDeserialization</i>).
84 *
85 * The sorted list of Information Elements that can be included in the management frame implemented
86 * as a subclass of this class is provided as the template parameter pack. Specifically:
87 * - the type of a mandatory Information Element IE is IE
88 * - the type of an optional Information Element IE is std::optional<IE>
89 * - the type of an Information Element IE that can appear zero or more times is std::vector<IE>
90 *
91 * \tparam Derived \explicit the type of derived management frame
92 * \tparam Elems \explicit sorted list of Information Elements that can be included in mgt frame
93 */
94template <typename Derived, typename... Elems>
95class WifiMgtHeader<Derived, std::tuple<Elems...>> : public Header
96{
97 public:
98 /**
99 * Access a (mandatory or optional) Information Element.
100 *
101 * \tparam T \explicit the type of the Information Element to return
102 * \return a reference to the Information Element of the given type
103 */
104 template <typename T,
105 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int> = 0>
106 std::optional<T>& Get();
107
108 /**
109 * Access a (mandatory or optional) Information Element.
110 *
111 * \tparam T \explicit the type of the Information Element to return
112 * \return a const reference to the Information Element of the given type
113 */
114 template <typename T,
115 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int> = 0>
116 const std::optional<T>& Get() const;
117
118 /**
119 * Access an Information Element that can be present zero or more times.
120 *
121 * \tparam T \explicit the type of the Information Element to return
122 * \return a reference to the Information Element of the given type
123 */
124 template <typename T,
125 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int> = 0>
126 std::vector<T>& Get();
127
128 /**
129 * Access an Information Element that can be present zero or more times.
130 *
131 * \tparam T \explicit the type of the Information Element to return
132 * \return a reference to the Information Element of the given type
133 */
134 template <typename T,
135 std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int> = 0>
136 const std::vector<T>& Get() const;
137
138 void Print(std::ostream& os) const final;
139 uint32_t GetSerializedSize() const final;
140 void Serialize(Buffer::Iterator start) const final;
141 uint32_t Deserialize(Buffer::Iterator start) final;
142
143 protected:
144 /**
145 * \tparam IE \deduced the type of the Information Element to initialize for deserialization
146 * \param optElem the object to initialize for deserializing the information element into
147 *
148 * The Information Element object is constructed by calling the object's default constructor.
149 */
150 template <typename IE>
151 void InitForDeserialization(std::optional<IE>& optElem);
152
153 /**
154 * \param optElem the EhtCapabilities object to initialize for deserializing the
155 * information element into
156 */
157 void InitForDeserialization(std::optional<EhtCapabilities>& optElem);
158
159 /** \copydoc ns3::Header::Print */
160 void PrintImpl(std::ostream& os) const;
161 /** \copydoc ns3::Header::GetSerializedSize */
162 uint32_t GetSerializedSizeImpl() const;
163 /** \copydoc ns3::Header::Serialize */
164 void SerializeImpl(Buffer::Iterator start) const;
165 /** \copydoc ns3::Header::Deserialize */
166 uint32_t DeserializeImpl(Buffer::Iterator start);
167
168 /**
169 * \tparam T \deduced the type of the Information Element
170 * \param elem the optional Information Element
171 * \param start the buffer iterator pointing to where deserialization starts
172 * \return an iterator pointing to where deserialization terminated
173 */
174 template <typename T>
175 Buffer::Iterator DoDeserialize(std::optional<T>& elem, Buffer::Iterator start);
176
177 /**
178 * \tparam T \deduced the type of the Information Elements
179 * \param elems a vector of Information Elements
180 * \param start the buffer iterator pointing to where deserialization starts
181 * \return an iterator pointing to where deserialization terminated
182 */
183 template <typename T>
184 Buffer::Iterator DoDeserialize(std::vector<T>& elems, Buffer::Iterator start);
185
186 /// type of the Information Elements contained by this frame
187 using Elements = std::tuple<internal::GetStoredIeT<Elems>...>;
188
189 Elements m_elements; //!< Information Elements contained by this frame
190};
191
192/**
193 * \ingroup wifi
194 * Inspect a type to deduce whether it is an Information Element that can be included in a
195 * Per-STA Profile subelement of a Multi-Link Element.
196 * \tparam T \explicit The type to inspect.
197 */
198template <class T>
199struct CanBeInPerStaProfile : std::true_type
200{
201};
202
203/** \copydoc CanBeInPerStaProfile */
204template <class T>
206
207/**
208 * \ingroup wifi
209 * Implement the header for management frames that can be included in a Per-STA Profile
210 * subelement of a Multi-Link Element.
211 * \tparam Derived \explicit the type of derived management frame
212 * \tparam Tuple \explicit A tuple of the types of Information Elements included in the mgt frame
213 */
214template <typename Derived, typename Tuple>
216
217/**
218 * \ingroup wifi
219 *
220 * Add methods needed to serialize/deserialize a management header into a Per-STA Profile
221 * subelement of a Multi-Link Element.
222 *
223 * \tparam Derived \explicit the type of derived management frame
224 * \tparam Elems \explicit sorted list of Information Elements that can be included in mgt frame
225 */
226template <typename Derived, typename... Elems>
227class MgtHeaderInPerStaProfile<Derived, std::tuple<Elems...>>
228 : public WifiMgtHeader<Derived, std::tuple<Elems...>>
229{
230 public:
231 /**
232 * \param frame the frame containing the Multi-Link Element
233 * \return the number of bytes that are needed to serialize this header into a Per-STA Profile
234 * subelement of the Multi-Link Element
235 */
236 uint32_t GetSerializedSizeInPerStaProfile(const Derived& frame) const;
237
238 /**
239 * Serialize this header into a Per-STA Profile subelement of a Multi-Link Element
240 *
241 * \param start an iterator which points to where the header should be written
242 * \param frame the frame containing the Multi-Link Element
243 */
244 void SerializeInPerStaProfile(Buffer::Iterator start, const Derived& frame) const;
245
246 /**
247 * Deserialize this header from a Per-STA Profile subelement of a Multi-Link Element.
248 *
249 * \param start an iterator which points to where the header should be read from
250 * \param length the expected number of bytes to read
251 * \param frame the frame containing the Multi-Link Element
252 * \return the number of bytes read
253 */
254 uint32_t DeserializeFromPerStaProfile(Buffer::Iterator start,
255 uint16_t length,
256 const Derived& frame);
257
258 /**
259 * Copy Information Elements inherited from the management frame containing the Multi-Link
260 * Element into this header (which is stored in a Per-STA Profile subelement). This method
261 * shall be invoked when the deserialization has been completed (i.e., the Non-Inheritance
262 * element, if present, has been deserialized).
263 *
264 * \param frame the frame containing the Multi-Link Element
265 */
266 void CopyIesFromContainingFrame(const Derived& frame);
267
268 protected:
269 using WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization;
270
271 /**
272 * \param frame the frame containing the Multi-Link Element
273 * \return the number of bytes that are needed to serialize this header into a Per-STA Profile
274 * subelement of the Multi-Link Element
275 */
276 uint32_t GetSerializedSizeInPerStaProfileImpl(const Derived& frame) const;
277
278 /**
279 * Serialize this header into a Per-STA Profile subelement of a Multi-Link Element
280 *
281 * \param start an iterator which points to where the header should be written
282 * \param frame the frame containing the Multi-Link Element
283 */
284 void SerializeInPerStaProfileImpl(Buffer::Iterator start, const Derived& frame) const;
285
286 /**
287 * Deserialize this header from a Per-STA Profile subelement of a Multi-Link Element.
288 *
289 * \param start an iterator which points to where the header should be read from
290 * \param length the expected number of bytes to read
291 * \param frame the frame containing the Multi-Link Element
292 * \return the number of bytes read
293 */
294 uint32_t DeserializeFromPerStaProfileImpl(Buffer::Iterator start,
295 uint16_t length,
296 const Derived& frame);
297
298 /**
299 * Pass a pointer to this frame to the Multi-Link Element (if any) included in this frame.
300 */
301 void SetMleContainingFrame() const;
302
303 /**
304 * \param optElem the MultiLinkElement object to initialize for deserializing the
305 * information element into
306 */
307 void InitForDeserialization(std::optional<MultiLinkElement>& optElem);
308
309 private:
310 using WifiMgtHeader<Derived, std::tuple<Elems...>>::DoDeserialize;
311 using WifiMgtHeader<Derived, std::tuple<Elems...>>::m_elements;
312
313 std::optional<NonInheritance> m_nonInheritance; /**< the Non-Inheritance IE possibly appended
314 to the Per-STA Profile subelement */
315};
316
317//
318// Implementation of the templates declared above.
319//
320
321template <typename Derived, typename... Elems>
322template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int>>
323std::optional<T>&
324WifiMgtHeader<Derived, std::tuple<Elems...>>::Get()
325{
326 return std::get<std::optional<T>>(m_elements);
327}
328
329template <typename Derived, typename... Elems>
330template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int>>
331const std::optional<T>&
332WifiMgtHeader<Derived, std::tuple<Elems...>>::Get() const
333{
334 return std::get<std::optional<T>>(m_elements);
335}
336
337template <typename Derived, typename... Elems>
338template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int>>
339std::vector<T>&
340WifiMgtHeader<Derived, std::tuple<Elems...>>::Get()
341{
342 return std::get<std::vector<T>>(m_elements);
343}
344
345template <typename Derived, typename... Elems>
346template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 1, int>>
347const std::vector<T>&
348WifiMgtHeader<Derived, std::tuple<Elems...>>::Get() const
349{
350 return std::get<std::vector<T>>(m_elements);
351}
352
353template <typename Derived, typename... Elems>
354template <typename IE>
355void
356WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization(std::optional<IE>& optElem)
357{
358 optElem.emplace();
359}
360
361template <typename Derived, typename... Elems>
362void
363WifiMgtHeader<Derived, std::tuple<Elems...>>::InitForDeserialization(
364 std::optional<EhtCapabilities>& optElem)
365{
366 NS_ASSERT(Get<SupportedRates>());
367 auto rates = AllSupportedRates{*Get<SupportedRates>(), std::nullopt};
368 const bool is2_4Ghz = rates.IsSupportedRate(
369 1000000 /* 1 Mbit/s */); // TODO: use presence of VHT capabilities IE and HE 6 GHz Band
370 // Capabilities IE once the later is implemented
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(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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.
Struct containing all supported rates.
bool IsSupportedRate(uint64_t bs) const
Check if the given rate is supported.
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