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