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 
27 using namespace ns3;
28 
29 NS_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;
56  void SerializeInformationField(Buffer::Iterator start) 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 
75 uint16_t
77 {
78  return m_content.size();
79 }
80 
81 void
83 {
84  NS_LOG_FUNCTION(this);
85  for (const auto& byte : m_content)
86  {
87  start.WriteU8(byte);
88  }
89 }
90 
91 uint16_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;
130  void SerializeInformationField(Buffer::Iterator start) const override;
131  uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
132 
133  bool m_extended;
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 
156 void
158 {
159  NS_LOG_FUNCTION(this);
160  m_content.push_back(std::move(subelement));
161 }
162 
163 uint16_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 
174 void
176 {
177  NS_LOG_FUNCTION(this);
178  for (const auto& subelement : m_content)
179  {
180  start = subelement.Serialize(start);
181  }
182 }
183 
184 uint16_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 
208 class 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;
220  uint32_t Deserialize(Buffer::Iterator start) override;
221  void Print(std::ostream& os) const override;
222 
228  void AddTestIe(TestWifiInformationElement&& element);
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 
246 TypeId
248 {
249  return GetTypeId();
250 }
251 
252 void
253 TestHeader::Print(std::ostream& os) const
254 {
255 }
256 
257 uint32_t
259 {
260  uint32_t size = 0;
261  for (const auto& elem : m_elements)
262  {
263  size += elem.GetSerializedSize();
264  }
265  return size;
266 }
267 
268 void
270 {
271  NS_LOG_FUNCTION(this);
272  for (const auto& elem : m_elements)
273  {
274  start = elem.Serialize(start);
275  }
276 }
277 
278 uint32_t
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 
302 void
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 
345  bool m_extended;
346 };
347 
349  : HeaderSerializationTestCase("Check fragmentation of Information Elements"),
350  m_extended(extended)
351 {
352 }
353 
354 Buffer
356 {
357  Buffer buffer;
358  buffer.AddAtStart(element.GetSerializedSize());
359  element.Serialize(buffer.Begin());
360  return buffer;
361 }
362 
363 void
364 WifiIeFragmentationTest::CheckSerializedByte(const Buffer& buffer, uint32_t position, uint8_t value)
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 
372 void
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 
391  auto testIe = TestWifiInformationElement(m_extended);
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");
415  TestHeaderSerialization(header);
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");
457  TestHeaderSerialization(header);
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");
500  TestHeaderSerialization(header);
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");
552  TestHeaderSerialization(header);
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");
585  TestHeaderSerialization(header);
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");
630  TestHeaderSerialization(header);
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.
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
virtual uint32_t Deserialize(Buffer::Iterator start)=0
Deserialize the object from a buffer iterator.
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:46
#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
static WifiIeFragmentationTestSuite g_wifiIeFragmentationTestSuite
the test suite
#define IE_FRAGMENT