A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-ie-fragment-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 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#include "ns3/header-serialization-test.h"
10#include "ns3/log.h"
11#include "ns3/supported-rates.h"
12#include "ns3/wifi-information-element.h"
13#include "ns3/wifi-mgt-header.h"
14
15#include <list>
16#include <numeric>
17#include <optional>
18
19using namespace ns3;
20
21NS_LOG_COMPONENT_DEFINE("WifiIeFragmentTest");
22
23/// whether the test Information Element includes an Element ID Extension field
24static bool g_extendedIe = false;
25
26/**
27 * \ingroup wifi-test
28 * \ingroup tests
29 *
30 * Subelement to test fragmentation. Its content is a sequence of bytes
31 * of configurable size.
32 */
34{
35 public:
36 TestWifiSubElement() = default;
37
38 /**
39 * Construct a test subelement containing a sequence of bytes of the given
40 * size and with the given initial value.
41 *
42 * \param count the number of bytes to append
43 * \param start the initial value for the sequence of bytes to add
44 */
45 TestWifiSubElement(uint16_t count, uint8_t start);
46
47 WifiInformationElementId ElementId() const override;
48
49 private:
50 uint16_t GetInformationFieldSize() const override;
51 void SerializeInformationField(Buffer::Iterator start) const override;
52 uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
53
54 std::list<uint8_t> m_content; ///< content of the IE
55};
56
57TestWifiSubElement::TestWifiSubElement(uint16_t count, uint8_t start)
58{
59 NS_LOG_FUNCTION(this << count << +start);
60 m_content.resize(count);
61 std::iota(m_content.begin(), m_content.end(), start);
62}
63
66{
67 return 0;
68}
69
70uint16_t
75
76void
78{
79 NS_LOG_FUNCTION(this);
80 for (const auto& byte : m_content)
81 {
82 start.WriteU8(byte);
83 }
84}
85
86uint16_t
88{
89 NS_LOG_FUNCTION(this << length);
90 m_content.clear();
91 for (uint16_t i = 0; i < length; i++)
92 {
93 m_content.push_back(start.ReadU8());
94 }
95 return length;
96}
97
98/**
99 * \ingroup wifi-test
100 * \ingroup tests
101 *
102 * Information Element to test IE fragmentation. Its content is one or more
103 * test subelements.
104 */
106{
107 public:
108 /**
109 * Constructor
110 * \param extended whether this IE includes an Element ID Extension field
111 */
113
114 WifiInformationElementId ElementId() const override;
115 WifiInformationElementId ElementIdExt() const override;
116 /**
117 * Append the given subelement.
118 *
119 * \param subelement the subelement to append
120 */
121 void AddSubelement(TestWifiSubElement&& subelement);
122
123 private:
124 uint16_t GetInformationFieldSize() const override;
125 void SerializeInformationField(Buffer::Iterator start) const override;
126 uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
127
128 bool m_extended; ///< whether this IE has an Element ID Extension field
129 std::list<TestWifiSubElement> m_content; ///< content of the IE
130};
131
137
140{
141 return m_extended ? 255 : 2; // reserved in 802.11-2020
142}
143
146{
148 return 32; // reserved in 802.11-2020
149}
150
151void
153{
154 NS_LOG_FUNCTION(this);
155 m_content.push_back(std::move(subelement));
156}
157
158uint16_t
160{
161 uint16_t size = (m_extended ? 1 : 0);
162 for (const auto& subelement : m_content)
163 {
164 size += subelement.GetSerializedSize();
165 }
166 return size;
167}
168
169void
171{
172 NS_LOG_FUNCTION(this);
173 for (const auto& subelement : m_content)
174 {
175 start = subelement.Serialize(start);
176 }
177}
178
179uint16_t
181{
182 NS_LOG_FUNCTION(this << length);
183
184 Buffer::Iterator i = start;
185 uint16_t count = 0;
186
187 while (count < length)
188 {
189 TestWifiSubElement subelement;
190 i = subelement.Deserialize(i);
191 m_content.push_back(std::move(subelement));
192 count = i.GetDistanceFrom(start);
193 }
194 return count;
195}
196
197/**
198 * \ingroup wifi-test
199 * \ingroup tests
200 *
201 * Test header that can contain multiple test information elements.
202 */
204 : public WifiMgtHeader<TestHeader, std::tuple<std::vector<TestWifiInformationElement>>>
205{
206 friend class WifiMgtHeader<TestHeader, std::tuple<std::vector<TestWifiInformationElement>>>;
207
208 public:
209 ~TestHeader() override = default;
210
211 /**
212 * \brief Get the type ID.
213 * \return the object TypeId
214 */
215 static TypeId GetTypeId();
216
217 /**
218 * \return the TypeId for this object.
219 */
220 TypeId GetInstanceTypeId() const override;
221
222 private:
223 /**
224 * \param optElem the MultiLinkElement object to initialize for deserializing the
225 * information element into
226 */
227 void InitForDeserialization(std::optional<TestWifiInformationElement>& optElem);
228};
229
231
234{
235 static TypeId tid = TypeId("ns3::TestHeader")
236 .SetParent<Header>()
237 .SetGroupName("Wifi")
238 .AddConstructor<TestHeader>();
239 return tid;
240}
241
242TypeId
244{
245 return GetTypeId();
246}
247
248void
249TestHeader::InitForDeserialization(std::optional<TestWifiInformationElement>& optElem)
250{
251 optElem.emplace(g_extendedIe);
252}
253
254/**
255 * \ingroup wifi-test
256 * \ingroup tests
257 *
258 * \brief Test fragmentation of Information Elements
259 */
261{
262 public:
263 /**
264 * Constructor
265 * \param extended whether this IE includes an Element ID Extension field
266 */
268 ~WifiIeFragmentationTest() override = default;
269
270 /**
271 * Serialize the given element in a buffer.
272 *
273 * \param element the given element
274 * \return the buffer in which the given element has been serialized
275 */
276 Buffer SerializeIntoBuffer(const WifiInformationElement& element);
277
278 /**
279 * Check that the given buffer contains the given value at the given position.
280 *
281 * \param buffer the given buffer
282 * \param position the given position (starting at 0)
283 * \param value the given value
284 */
285 void CheckSerializedByte(const Buffer& buffer, uint32_t position, uint8_t value);
286
287 private:
288 void DoRun() override;
289
290 bool m_extended; //!< whether the IE includes an Element ID Extension field
291};
292
293WifiIeFragmentationTest ::WifiIeFragmentationTest(bool extended)
294 : HeaderSerializationTestCase("Check fragmentation of Information Elements"),
295 m_extended(extended)
296{
297}
298
299Buffer
301{
302 Buffer buffer;
303 buffer.AddAtStart(element.GetSerializedSize());
304 element.Serialize(buffer.Begin());
305 return buffer;
306}
307
308void
309WifiIeFragmentationTest::CheckSerializedByte(const Buffer& buffer, uint32_t position, uint8_t value)
310{
311 Buffer::Iterator it = buffer.Begin();
312 it.Next(position);
313 uint8_t byte = it.ReadU8();
314 NS_TEST_EXPECT_MSG_EQ(+byte, +value, "Unexpected byte at pos=" << position);
315}
316
317void
319{
320 // maximum IE size to avoid incurring IE fragmentation
321 uint16_t limit = m_extended ? 254 : 255;
322
323 TestHeader header;
325
326 /*
327 * Add an IE (containing 2 subelements). No fragmentation occurs
328 */
329
330 uint16_t sub01Size = 50;
331 uint16_t sub02Size = limit - sub01Size;
332
333 auto sub01 =
334 TestWifiSubElement(sub01Size - 2, 53); // minus 2 to account for Subelement ID and Length
335 auto sub02 = TestWifiSubElement(sub02Size - 2, 26);
336
338 testIe.AddSubelement(std::move(sub01));
339 testIe.AddSubelement(std::move(sub02));
340
341 {
342 Buffer buffer = SerializeIntoBuffer(testIe);
343 CheckSerializedByte(buffer, 1, 255); // element length is the maximum length
344 if (m_extended)
345 {
346 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
347 }
349 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
350 CheckSerializedByte(buffer,
351 (m_extended ? 3 : 2) + sub01Size,
353 CheckSerializedByte(buffer,
354 (m_extended ? 3 : 2) + sub01Size + 1,
355 sub02Size - 2); // subelement 2 Length
356 }
357
358 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
359 uint32_t expectedHdrSize = 2 + 255;
360 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
362
363 /*
364 * Add an IE (containing 2 subelements) that is fragmented into 2 fragments.
365 * Subelements are not fragmented
366 */
367 sub01Size = 65;
368 sub02Size = limit + 1 - sub01Size;
369
370 sub01 =
371 TestWifiSubElement(sub01Size - 2, 47); // minus 2 to account for Subelement ID and Length
372 sub02 = TestWifiSubElement(sub02Size - 2, 71);
373
375 testIe.AddSubelement(std::move(sub01));
376 testIe.AddSubelement(std::move(sub02));
377
378 {
379 Buffer buffer = SerializeIntoBuffer(testIe);
380 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
381 if (m_extended)
382 {
383 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
384 }
386 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
387 CheckSerializedByte(buffer,
388 (m_extended ? 3 : 2) + sub01Size,
390 CheckSerializedByte(buffer,
391 (m_extended ? 3 : 2) + sub01Size + 1,
392 sub02Size - 2); // subelement 2 Length
393 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
394 CheckSerializedByte(buffer,
395 2 + 255 + 1,
396 1); // the length of the second element fragment is 1
397 }
398
399 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
400 expectedHdrSize += 2 + 255 // first fragment
401 + 2 + 1; // second fragment
402 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
404
405 /*
406 * Add an IE (containing 3 subelements) that is fragmented into 2 fragments.
407 * Subelements are not fragmented
408 */
409 sub01Size = 200;
410 sub02Size = 200;
411 uint16_t sub03Size = limit + 255 - sub01Size - sub02Size;
412
413 sub01 =
414 TestWifiSubElement(sub01Size - 2, 16); // minus 2 to account for Subelement ID and Length
415 sub02 = TestWifiSubElement(sub02Size - 2, 83);
416 auto sub03 = TestWifiSubElement(sub03Size - 2, 98);
417
419 testIe.AddSubelement(std::move(sub01));
420 testIe.AddSubelement(std::move(sub02));
421 testIe.AddSubelement(std::move(sub03));
422
423 {
424 Buffer buffer = SerializeIntoBuffer(testIe);
425 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
426 if (m_extended)
427 {
428 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
429 }
431 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
432 CheckSerializedByte(buffer,
433 (m_extended ? 3 : 2) + sub01Size,
435 CheckSerializedByte(buffer,
436 (m_extended ? 3 : 2) + sub01Size + 1,
437 sub02Size - 2); // subelement 2 Length
438 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
439 CheckSerializedByte(buffer, 2 + 255 + 1, 255); // maximum length for second element fragment
440 }
441
442 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
443 expectedHdrSize += 2 + 255 // first fragment
444 + 2 + 255; // second fragment
445 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
447
448 /*
449 * Add an IE (containing 3 subelements) that is fragmented into 3 fragments.
450 * Subelements are not fragmented
451 */
452 sub01Size = 200;
453 sub02Size = 200;
454 sub03Size = limit + 255 + 1 - sub01Size - sub02Size;
455
456 sub01 =
457 TestWifiSubElement(sub01Size - 2, 20); // minus 2 to account for Subelement ID and Length
458 sub02 = TestWifiSubElement(sub02Size - 2, 77);
459 sub03 = TestWifiSubElement(sub03Size - 2, 14);
460
462 testIe.AddSubelement(std::move(sub01));
463 testIe.AddSubelement(std::move(sub02));
464 testIe.AddSubelement(std::move(sub03));
465
466 {
467 Buffer buffer = SerializeIntoBuffer(testIe);
468 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
469 if (m_extended)
470 {
471 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
472 }
474 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
475 CheckSerializedByte(buffer,
476 (m_extended ? 3 : 2) + sub01Size,
478 CheckSerializedByte(buffer,
479 (m_extended ? 3 : 2) + sub01Size + 1,
480 sub02Size - 2); // subelement 2 Length
481 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
482 CheckSerializedByte(buffer, 2 + 255 + 1, 255); // maximum length for second fragment
483 CheckSerializedByte(buffer,
484 (m_extended ? 3 : 2) + sub01Size + 2 + sub02Size,
486 CheckSerializedByte(buffer,
487 (m_extended ? 3 : 2) + sub01Size + 2 + sub02Size + 1,
488 sub03Size - 2); // subelement 3 Length
489 CheckSerializedByte(buffer, 2 * (2 + 255), IE_FRAGMENT); // Fragment ID
490 CheckSerializedByte(buffer, 2 * (2 + 255) + 1, 1); // the length of the third fragment is 1
491 }
492
493 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
494 expectedHdrSize += 2 + 255 // first fragment
495 + 2 + 255 // second fragment
496 + 2 + 1; // third fragment
497 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
499
500 /*
501 * Add an IE containing one subelement of the maximum size.
502 * The IE is fragmented into 2 fragments.
503 */
504 sub01Size = 2 + 255;
505
506 sub01 =
507 TestWifiSubElement(sub01Size - 2, 47); // minus 2 to account for Subelement ID and Length
508
510 testIe.AddSubelement(std::move(sub01));
511
512 {
513 Buffer buffer = SerializeIntoBuffer(testIe);
514 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
515 if (m_extended)
516 {
517 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
518 }
520 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
521 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
522 CheckSerializedByte(buffer,
523 2 + 255 + 1,
524 (m_extended ? 3 : 2)); // length of the second element fragment
525 }
526
527 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
528 expectedHdrSize += 2 + 255 // first fragment
529 + 2 + (m_extended ? 3 : 2); // second fragment
530 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
532
533 /*
534 * Add an IE containing one subelement that gets fragmented.
535 * The IE is fragmented into 2 fragments as well.
536 */
537 sub01Size = 2 + 256;
538
539 sub01 =
540 TestWifiSubElement(sub01Size - 2, 84); // minus 2 to account for Subelement ID and Length
541
543 testIe.AddSubelement(std::move(sub01));
544
545 {
546 Buffer buffer = SerializeIntoBuffer(testIe);
547 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
548 if (m_extended)
549 {
550 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
551 }
553 CheckSerializedByte(buffer,
554 (m_extended ? 3 : 2) + 1,
555 255); // first subelement fragment Length
556 CheckSerializedByte(buffer,
557 2 + 255,
558 IE_FRAGMENT); // Fragment ID for second element fragment
559 // Subelement bytes in first element fragment: X = 255 - 1 (Ext ID, if any) - 1 (Sub ID) - 1
560 // (Sub Length) Subelement bytes in second element fragment: Y = 256 - X = (m_extended ? 4 :
561 // 3) Length of the second element fragment: Y + 2 (Fragment ID and Length for second
562 // subelement fragment)
563 CheckSerializedByte(buffer, 2 + 255 + 1, (m_extended ? 6 : 5));
564 CheckSerializedByte(buffer,
565 2 + 255 + 2 + (m_extended ? 3 : 2),
566 IE_FRAGMENT); // Fragment ID for second subelement fragment
567 CheckSerializedByte(buffer,
568 2 + 255 + 2 + (m_extended ? 3 : 2) + 1,
569 1); // Length for second subelement fragment
570 }
571
572 header.Get<TestWifiInformationElement>().push_back(std::move(testIe));
573 expectedHdrSize += 2 + 255 // first fragment
574 + 2 + (m_extended ? 6 : 5); // second fragment
575 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
577}
578
579/**
580 * \ingroup wifi-test
581 * \ingroup tests
582 *
583 * \brief wifi Information Element fragmentation Test Suite
584 */
586{
587 public:
589};
590
592 : TestSuite("wifi-ie-fragment", Type::UNIT)
593{
594 AddTestCase(new WifiIeFragmentationTest(false), TestCase::Duration::QUICK);
595 AddTestCase(new WifiIeFragmentationTest(true), TestCase::Duration::QUICK);
596}
597
Test header that can contain multiple test information elements.
TypeId GetInstanceTypeId() const override
void InitForDeserialization(std::optional< TestWifiInformationElement > &optElem)
static TypeId GetTypeId()
Get the type ID.
Information Element to test IE fragmentation.
uint16_t GetInformationFieldSize() const override
Length of serialized information (i.e., the length of the body of the IE, not including the Element I...
uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override
Deserialize information (i.e., the body of the IE, not including the Element ID and length octets)
TestWifiInformationElement(bool extended)
Constructor.
void AddSubelement(TestWifiSubElement &&subelement)
Append the given subelement.
WifiInformationElementId ElementId() const override
Get the wifi information element ID.
WifiInformationElementId ElementIdExt() const override
Get the wifi information element ID extension.
bool m_extended
whether this IE has an Element ID Extension field
std::list< TestWifiSubElement > m_content
content of the IE
void SerializeInformationField(Buffer::Iterator start) const override
Serialize information (i.e., the body of the IE, not including the Element ID and length octets)
Subelement to test fragmentation.
WifiInformationElementId ElementId() const override
Get the wifi information element ID.
TestWifiSubElement()=default
std::list< uint8_t > m_content
content of the IE
void SerializeInformationField(Buffer::Iterator start) const override
Serialize information (i.e., the body of the IE, not including the Element ID and length octets)
uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override
Deserialize information (i.e., the body of the IE, not including the Element ID and length octets)
uint16_t GetInformationFieldSize() const override
Length of serialized information (i.e., the length of the body of the IE, not including the Element I...
Test fragmentation of Information Elements.
Buffer SerializeIntoBuffer(const WifiInformationElement &element)
Serialize the given element in a buffer.
bool m_extended
whether the IE includes an Element ID Extension field
void CheckSerializedByte(const Buffer &buffer, uint32_t position, uint8_t value)
Check that the given buffer contains the given value at the given position.
void DoRun() override
Implementation to actually run this TestCase.
~WifiIeFragmentationTest() override=default
wifi Information Element fragmentation Test Suite
iterator in a Buffer instance
Definition buffer.h:89
uint32_t GetDistanceFrom(const Iterator &o) const
Definition buffer.cc:769
void Next()
go forward by one byte
Definition buffer.h:842
automatically resized byte buffer
Definition buffer.h:83
void AddAtStart(uint32_t start)
Definition buffer.cc:303
Buffer::Iterator Begin() const
Definition buffer.h:1063
Protocol header serialization and deserialization.
Definition header.h:33
Subclass of TestCase class adding the ability to test the serialization and deserialization of a Head...
void TestHeaderSerialization(const T &hdr, Args &&... args)
Serialize the given header in a buffer, then create a new header by deserializing from the buffer and...
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Information element, as defined in 802.11-2007 standard.
uint16_t GetSerializedSize() const
Get the size of the serialized IE including Element ID and length fields (for every element this IE i...
Buffer::Iterator Deserialize(Buffer::Iterator i)
Deserialize entire IE (which may possibly be fragmented into multiple elements), which must be presen...
Buffer::Iterator Serialize(Buffer::Iterator i) const
Serialize entire IE including Element ID and length fields.
Implement the header for management frames.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Every class exported by the ns3 library is enclosed in the ns3 namespace.
@ extended
uint8_t WifiInformationElementId
This type is used to represent an Information Element ID.
STL namespace.
static bool g_extendedIe
whether the test Information Element includes an Element ID Extension field
static WifiIeFragmentationTestSuite g_wifiIeFragmentationTestSuite
the test suite
#define IE_FRAGMENT