A Discrete-Event Network Simulator
API
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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
20#include "ns3/header-serialization-test.h"
21#include "ns3/log.h"
22#include "ns3/wifi-information-element.h"
23
24#include <list>
25#include <numeric>
26
27using namespace ns3;
28
29NS_LOG_COMPONENT_DEFINE("WifiIeFragmentTest");
30
39{
40 public:
41 TestWifiSubElement() = default;
42
50 TestWifiSubElement(uint16_t count, uint8_t start);
51
52 WifiInformationElementId ElementId() const override;
53
54 private:
55 uint16_t GetInformationFieldSize() const override;
57 uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
58
59 std::list<uint8_t> m_content;
60};
61
63{
64 NS_LOG_FUNCTION(this << count << +start);
65 m_content.resize(count);
66 std::iota(m_content.begin(), m_content.end(), start);
67}
68
71{
72 return 0;
73}
74
75uint16_t
77{
78 return m_content.size();
79}
80
81void
83{
84 NS_LOG_FUNCTION(this);
85 for (const auto& byte : m_content)
86 {
87 start.WriteU8(byte);
88 }
89}
90
91uint16_t
93{
94 NS_LOG_FUNCTION(this << length);
95 m_content.clear();
96 for (uint16_t i = 0; i < length; i++)
97 {
98 m_content.push_back(start.ReadU8());
99 }
100 return length;
101}
102
111{
112 public:
118
119 WifiInformationElementId ElementId() const override;
120 WifiInformationElementId ElementIdExt() const override;
126 void AddSubelement(TestWifiSubElement&& subelement);
127
128 private:
129 uint16_t GetInformationFieldSize() const override;
131 uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
132
134 std::list<TestWifiSubElement> m_content;
135};
136
138 : m_extended(extended)
139{
140 NS_LOG_FUNCTION(this << extended);
141}
142
145{
146 return m_extended ? 255 : 2; // reserved in 802.11-2020
147}
148
151{
153 return 32; // reserved in 802.11-2020
154}
155
156void
158{
159 NS_LOG_FUNCTION(this);
160 m_content.push_back(std::move(subelement));
161}
162
163uint16_t
165{
166 uint16_t size = (m_extended ? 1 : 0);
167 for (const auto& subelement : m_content)
168 {
169 size += subelement.GetSerializedSize();
170 }
171 return size;
172}
173
174void
176{
177 NS_LOG_FUNCTION(this);
178 for (const auto& subelement : m_content)
179 {
180 start = subelement.Serialize(start);
181 }
182}
183
184uint16_t
186{
187 NS_LOG_FUNCTION(this << length);
188
190 uint16_t count = 0;
191
192 while (count < length)
193 {
194 TestWifiSubElement subelement;
195 i = subelement.Deserialize(i);
196 m_content.push_back(std::move(subelement));
197 count = i.GetDistanceFrom(start);
198 }
199 return count;
200}
201
208class TestHeader : public Header
209{
210 public:
215 static TypeId GetTypeId();
216
217 TypeId GetInstanceTypeId() const override;
218 uint32_t GetSerializedSize() const override;
219 void Serialize(Buffer::Iterator start) const override;
221 void Print(std::ostream& os) const override;
222
229
230 private:
231 std::list<TestWifiInformationElement> m_elements;
232};
233
235
238{
239 static TypeId tid = TypeId("ns3::TestHeader")
240 .SetParent<Header>()
241 .SetGroupName("Wifi")
242 .AddConstructor<TestHeader>();
243 return tid;
244}
245
246TypeId
248{
249 return GetTypeId();
250}
251
252void
253TestHeader::Print(std::ostream& os) const
254{
255}
256
259{
260 uint32_t size = 0;
261 for (const auto& elem : m_elements)
262 {
263 size += elem.GetSerializedSize();
264 }
265 return size;
266}
267
268void
270{
271 NS_LOG_FUNCTION(this);
272 for (const auto& elem : m_elements)
273 {
274 start = elem.Serialize(start);
275 }
276}
277
280{
281 NS_LOG_FUNCTION(this);
283 m_elements.clear();
284
285 while (!i.IsEnd())
286 {
287 std::optional<TestWifiInformationElement> elem;
288 i = WifiInformationElement::DeserializeIfPresent(elem, i, true);
289 if (!elem.has_value())
290 {
291 // try deserializing the test IE without Element ID Extension field
292 i = WifiInformationElement::DeserializeIfPresent(elem, i, false);
293 }
294 if (elem.has_value())
295 {
296 m_elements.push_back(std::move(*elem));
297 }
298 }
299 return i.GetDistanceFrom(start);
300}
301
302void
304{
305 NS_LOG_FUNCTION(this);
306 m_elements.push_back(std::move(element));
307}
308
316{
317 public:
323 ~WifiIeFragmentationTest() override = default;
324
332
340 void CheckSerializedByte(const Buffer& buffer, uint32_t position, uint8_t value);
341
342 private:
343 void DoRun() override;
344
346};
347
349 : HeaderSerializationTestCase("Check fragmentation of Information Elements"),
350 m_extended(extended)
351{
352}
353
354Buffer
356{
357 Buffer buffer;
358 buffer.AddAtStart(element.GetSerializedSize());
359 element.Serialize(buffer.Begin());
360 return buffer;
361}
362
363void
365{
366 Buffer::Iterator it = buffer.Begin();
367 it.Next(position);
368 uint8_t byte = it.ReadU8();
369 NS_TEST_EXPECT_MSG_EQ(+byte, +value, "Unexpected byte at pos=" << position);
370}
371
372void
374{
375 // maximum IE size to avoid incurring IE fragmentation
376 uint16_t limit = m_extended ? 254 : 255;
377
378 TestHeader header;
379
380 /*
381 * Add an IE (containing 2 subelements). No fragmentation occurs
382 */
383
384 uint16_t sub01Size = 50;
385 uint16_t sub02Size = limit - sub01Size;
386
387 auto sub01 =
388 TestWifiSubElement(sub01Size - 2, 53); // minus 2 to account for Subelement ID and Length
389 auto sub02 = TestWifiSubElement(sub02Size - 2, 26);
390
392 testIe.AddSubelement(std::move(sub01));
393 testIe.AddSubelement(std::move(sub02));
394
395 {
396 Buffer buffer = SerializeIntoBuffer(testIe);
397 CheckSerializedByte(buffer, 1, 255); // element length is the maximum length
398 if (m_extended)
399 {
400 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
401 }
402 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
403 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
404 CheckSerializedByte(buffer,
405 (m_extended ? 3 : 2) + sub01Size,
406 TestWifiSubElement().ElementId());
407 CheckSerializedByte(buffer,
408 (m_extended ? 3 : 2) + sub01Size + 1,
409 sub02Size - 2); // subelement 2 Length
410 }
411
412 header.AddTestIe(std::move(testIe));
413 uint32_t expectedHdrSize = 2 + 255;
414 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
416
417 /*
418 * Add an IE (containing 2 subelements) that is fragmented into 2 fragments.
419 * Subelements are not fragmented
420 */
421 sub01Size = 65;
422 sub02Size = limit + 1 - sub01Size;
423
424 sub01 =
425 TestWifiSubElement(sub01Size - 2, 47); // minus 2 to account for Subelement ID and Length
426 sub02 = TestWifiSubElement(sub02Size - 2, 71);
427
429 testIe.AddSubelement(std::move(sub01));
430 testIe.AddSubelement(std::move(sub02));
431
432 {
433 Buffer buffer = SerializeIntoBuffer(testIe);
434 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
435 if (m_extended)
436 {
437 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
438 }
439 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
440 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
441 CheckSerializedByte(buffer,
442 (m_extended ? 3 : 2) + sub01Size,
443 TestWifiSubElement().ElementId());
444 CheckSerializedByte(buffer,
445 (m_extended ? 3 : 2) + sub01Size + 1,
446 sub02Size - 2); // subelement 2 Length
447 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
448 CheckSerializedByte(buffer,
449 2 + 255 + 1,
450 1); // the length of the second element fragment is 1
451 }
452
453 header.AddTestIe(std::move(testIe));
454 expectedHdrSize += 2 + 255 // first fragment
455 + 2 + 1; // second fragment
456 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
458
459 /*
460 * Add an IE (containing 3 subelements) that is fragmented into 2 fragments.
461 * Subelements are not fragmented
462 */
463 sub01Size = 200;
464 sub02Size = 200;
465 uint16_t sub03Size = limit + 255 - sub01Size - sub02Size;
466
467 sub01 =
468 TestWifiSubElement(sub01Size - 2, 16); // minus 2 to account for Subelement ID and Length
469 sub02 = TestWifiSubElement(sub02Size - 2, 83);
470 auto sub03 = TestWifiSubElement(sub03Size - 2, 98);
471
473 testIe.AddSubelement(std::move(sub01));
474 testIe.AddSubelement(std::move(sub02));
475 testIe.AddSubelement(std::move(sub03));
476
477 {
478 Buffer buffer = SerializeIntoBuffer(testIe);
479 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
480 if (m_extended)
481 {
482 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
483 }
484 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
485 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
486 CheckSerializedByte(buffer,
487 (m_extended ? 3 : 2) + sub01Size,
488 TestWifiSubElement().ElementId());
489 CheckSerializedByte(buffer,
490 (m_extended ? 3 : 2) + sub01Size + 1,
491 sub02Size - 2); // subelement 2 Length
492 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
493 CheckSerializedByte(buffer, 2 + 255 + 1, 255); // maximum length for second element fragment
494 }
495
496 header.AddTestIe(std::move(testIe));
497 expectedHdrSize += 2 + 255 // first fragment
498 + 2 + 255; // second fragment
499 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
501
502 /*
503 * Add an IE (containing 3 subelements) that is fragmented into 3 fragments.
504 * Subelements are not fragmented
505 */
506 sub01Size = 200;
507 sub02Size = 200;
508 sub03Size = limit + 255 + 1 - sub01Size - sub02Size;
509
510 sub01 =
511 TestWifiSubElement(sub01Size - 2, 20); // minus 2 to account for Subelement ID and Length
512 sub02 = TestWifiSubElement(sub02Size - 2, 77);
513 sub03 = TestWifiSubElement(sub03Size - 2, 14);
514
516 testIe.AddSubelement(std::move(sub01));
517 testIe.AddSubelement(std::move(sub02));
518 testIe.AddSubelement(std::move(sub03));
519
520 {
521 Buffer buffer = SerializeIntoBuffer(testIe);
522 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
523 if (m_extended)
524 {
525 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
526 }
527 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
528 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
529 CheckSerializedByte(buffer,
530 (m_extended ? 3 : 2) + sub01Size,
531 TestWifiSubElement().ElementId());
532 CheckSerializedByte(buffer,
533 (m_extended ? 3 : 2) + sub01Size + 1,
534 sub02Size - 2); // subelement 2 Length
535 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
536 CheckSerializedByte(buffer, 2 + 255 + 1, 255); // maximum length for second fragment
537 CheckSerializedByte(buffer,
538 (m_extended ? 3 : 2) + sub01Size + 2 + sub02Size,
539 TestWifiSubElement().ElementId());
540 CheckSerializedByte(buffer,
541 (m_extended ? 3 : 2) + sub01Size + 2 + sub02Size + 1,
542 sub03Size - 2); // subelement 3 Length
543 CheckSerializedByte(buffer, 2 * (2 + 255), IE_FRAGMENT); // Fragment ID
544 CheckSerializedByte(buffer, 2 * (2 + 255) + 1, 1); // the length of the third fragment is 1
545 }
546
547 header.AddTestIe(std::move(testIe));
548 expectedHdrSize += 2 + 255 // first fragment
549 + 2 + 255 // second fragment
550 + 2 + 1; // third fragment
551 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
553
554 /*
555 * Add an IE containing one subelement of the maximum size.
556 * The IE is fragmented into 2 fragments.
557 */
558 sub01Size = 2 + 255;
559
560 sub01 =
561 TestWifiSubElement(sub01Size - 2, 47); // minus 2 to account for Subelement ID and Length
562
564 testIe.AddSubelement(std::move(sub01));
565
566 {
567 Buffer buffer = SerializeIntoBuffer(testIe);
568 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
569 if (m_extended)
570 {
571 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
572 }
573 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
574 CheckSerializedByte(buffer, (m_extended ? 3 : 2) + 1, sub01Size - 2); // subelement 1 Length
575 CheckSerializedByte(buffer, 2 + 255, IE_FRAGMENT); // Fragment ID
576 CheckSerializedByte(buffer,
577 2 + 255 + 1,
578 (m_extended ? 3 : 2)); // length of the second element fragment
579 }
580
581 header.AddTestIe(std::move(testIe));
582 expectedHdrSize += 2 + 255 // first fragment
583 + 2 + (m_extended ? 3 : 2); // second fragment
584 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
586
587 /*
588 * Add an IE containing one subelement that gets fragmented.
589 * The IE is fragmented into 2 fragments as well.
590 */
591 sub01Size = 2 + 256;
592
593 sub01 =
594 TestWifiSubElement(sub01Size - 2, 84); // minus 2 to account for Subelement ID and Length
595
597 testIe.AddSubelement(std::move(sub01));
598
599 {
600 Buffer buffer = SerializeIntoBuffer(testIe);
601 CheckSerializedByte(buffer, 1, 255); // maximum length for first element fragment
602 if (m_extended)
603 {
604 CheckSerializedByte(buffer, 2, testIe.ElementIdExt());
605 }
606 CheckSerializedByte(buffer, (m_extended ? 3 : 2), TestWifiSubElement().ElementId());
607 CheckSerializedByte(buffer,
608 (m_extended ? 3 : 2) + 1,
609 255); // first subelement fragment Length
610 CheckSerializedByte(buffer,
611 2 + 255,
612 IE_FRAGMENT); // Fragment ID for second element fragment
613 // Subelement bytes in first element fragment: X = 255 - 1 (Ext ID, if any) - 1 (Sub ID) - 1
614 // (Sub Length) Subelement bytes in second element fragment: Y = 256 - X = (m_extended ? 4 :
615 // 3) Length of the second element fragment: Y + 2 (Fragment ID and Length for second
616 // subelement fragment)
617 CheckSerializedByte(buffer, 2 + 255 + 1, (m_extended ? 6 : 5));
618 CheckSerializedByte(buffer,
619 2 + 255 + 2 + (m_extended ? 3 : 2),
620 IE_FRAGMENT); // Fragment ID for second subelement fragment
621 CheckSerializedByte(buffer,
622 2 + 255 + 2 + (m_extended ? 3 : 2) + 1,
623 1); // Length for second subelement fragment
624 }
625
626 header.AddTestIe(std::move(testIe));
627 expectedHdrSize += 2 + 255 // first fragment
628 + 2 + (m_extended ? 6 : 5); // second fragment
629 NS_TEST_EXPECT_MSG_EQ(header.GetSerializedSize(), expectedHdrSize, "Unexpected header size");
631}
632
640{
641 public:
643};
644
646 : TestSuite("wifi-ie-fragment", UNIT)
647{
648 AddTestCase(new WifiIeFragmentationTest(false), TestCase::QUICK);
649 AddTestCase(new WifiIeFragmentationTest(true), TestCase::QUICK);
650}
651
Test header that can contain multiple test information elements.
uint32_t Deserialize(Buffer::Iterator start) override
void Print(std::ostream &os) const override
uint32_t GetSerializedSize() const override
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
void Serialize(Buffer::Iterator start) const override
static TypeId GetTypeId()
Get the type ID.
std::list< TestWifiInformationElement > m_elements
test information elements
void AddTestIe(TestWifiInformationElement &&element)
Append the given wifi test information element.
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.
WifiIeFragmentationTest(bool extended)
Constructor.
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:100
uint8_t ReadU8()
Definition: buffer.h:1027
bool IsEnd() const
Definition: buffer.cc:799
uint32_t GetDistanceFrom(const Iterator &o) const
Definition: buffer.cc:783
void Next()
go forward by one byte
Definition: buffer.h:853
automatically resized byte buffer
Definition: buffer.h:94
void AddAtStart(uint32_t start)
Definition: buffer.cc:311
Buffer::Iterator Begin() const
Definition: buffer.h:1074
Protocol header serialization and deserialization.
Definition: header.h:44
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, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
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.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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:45
#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:251
Every class exported by the ns3 library is enclosed in the ns3 namespace.
@ extended
Definition: ff-mac-common.h:85
uint8_t WifiInformationElementId
This type is used to represent an Information Element ID.
value
Definition: second.py:41
def start()
Definition: core.py:1861
static WifiIeFragmentationTestSuite g_wifiIeFragmentationTestSuite
the test suite
#define IE_FRAGMENT