INET Framework for OMNeT++/OMNEST
inet::Ipv6FragBuf Class Reference

Reassembly buffer for fragmented Ipv6 datagrams. More...

#include <Ipv6FragBuf.h>

Classes

struct  DatagramBuffer
 
struct  Key
 

Public Member Functions

 Ipv6FragBuf ()
 Ctor. More...
 
 ~Ipv6FragBuf ()
 Dtor. More...
 
void init (Icmpv6 *icmp)
 Initialize fragmentation buffer. More...
 
PacketaddFragment (Packet *packet, const Ipv6Header *dg, const Ipv6FragmentHeader *fh, simtime_t now)
 Takes a fragment and inserts it into the reassembly buffer. More...
 
void purgeStaleFragments (simtime_t lastupdate)
 Throws out all fragments which are incomplete and their last update (last fragment arrival) was before "lastupdate", and sends ICMP TIME EXCEEDED message about them. More...
 

Protected Types

typedef std::map< Key, DatagramBufferBuffers
 

Protected Attributes

Buffers bufs
 
Icmpv6icmpModule = nullptr
 

Detailed Description

Reassembly buffer for fragmented Ipv6 datagrams.

Member Typedef Documentation

◆ Buffers

typedef std::map<Key, DatagramBuffer> inet::Ipv6FragBuf::Buffers
protected

Constructor & Destructor Documentation

◆ Ipv6FragBuf()

inet::Ipv6FragBuf::Ipv6FragBuf ( )

Ctor.

21 {
22  icmpModule = nullptr;
23 }

◆ ~Ipv6FragBuf()

inet::Ipv6FragBuf::~Ipv6FragBuf ( )

Dtor.

26 {
27  for (auto& elem : bufs) {
28  delete elem.second.packet;
29  }
30 }

Member Function Documentation

◆ addFragment()

Packet * inet::Ipv6FragBuf::addFragment ( Packet packet,
const Ipv6Header dg,
const Ipv6FragmentHeader fh,
simtime_t  now 
)

Takes a fragment and inserts it into the reassembly buffer.

If this fragment completes a datagram, the full reassembled datagram is returned, otherwise nullptr.

38 {
39  // find datagram buffer
40  Key key;
41  key.id = fh->getIdentification();
42  key.src = ipv6Header->getSrcAddress();
43  key.dest = ipv6Header->getDestAddress();
44 
45  auto i = bufs.find(key);
46 
47  DatagramBuffer *buf = nullptr;
48  if (i == bufs.end()) {
49  // this is the first fragment of that datagram, create reassembly buffer for it
50  buf = &bufs[key];
51  buf->packet = nullptr;
52  buf->createdAt = now;
53  }
54  else {
55  // use existing buffer
56  buf = &(i->second);
57  }
58 
59  int fragmentLength = pk->getByteLength() - B(ipv6Header->getChunkLength()).get(); // datagram->calculateFragmentLength();
60  unsigned short offset = fh->getFragmentOffset();
61  bool moreFragments = fh->getMoreFragments();
62 
63  // RFC 2460 4.5:
64  // If the length of a fragment, as derived from the fragment packet's
65  // Payload Length field, is not a multiple of 8 octets and the M flag
66  // of that fragment is 1, then that fragment must be discarded and an
67  // ICMP Parameter Problem, Code 0, message should be sent to the
68  // source of the fragment, pointing to the Payload Length field of
69  // the fragment packet.
70  if (moreFragments && (fragmentLength % 8) != 0) {
72  delete pk;
73  return nullptr;
74  }
75 
76  // RFC 2460 4.5:
77  // If the length and offset of a fragment are such that the Payload
78  // Length of the packet reassembled from that fragment would exceed
79  // 65,535 octets, then that fragment must be discarded and an ICMP
80  // Parameter Problem, Code 0, message should be sent to the source of
81  // the fragment, pointing to the Fragment Offset field of the
82  // fragment packet.
83  if (offset + fragmentLength > 65535) {
85  delete pk;
86  return nullptr;
87  }
88 
89  // add fragment to buffer
90  buf->buf.replace(B(offset), pk->peekDataAt(ipv6Header->getChunkLength(), B(fragmentLength)));
91 
92  if (!moreFragments) {
93  buf->buf.setExpectedLength(B(offset + fragmentLength));
94  }
95 
96  // Store the first fragment. The first fragment contains the whole
97  // encapsulated payload, and extension headers of the
98  // original datagram.
99  if (offset == 0) {
100  delete buf->packet;
101  buf->packet = pk;
102  }
103  else {
104  delete pk;
105  }
106 
107  // do we have the complete datagram?
108  if (buf->buf.isComplete()) {
109  // datagram complete: deallocate buffer and return complete datagram
110  std::string pkName(buf->packet->getName());
111  std::size_t found = pkName.find("-frag-");
112  if (found != std::string::npos)
113  pkName.resize(found);
114  Packet *pk = new Packet(pkName.c_str());
115  pk->copyTags(*buf->packet);
116  auto hdr = Ptr<Ipv6Header>(buf->packet->peekAtFront<Ipv6Header>()->dup());
117  const auto& payload = buf->buf.getReassembledData();
118  hdr->removeExtensionHeader(IP_PROT_IPv6EXT_FRAGMENT);
119  hdr->setChunkLength(B(hdr->calculateUnfragmentableHeaderByteLength()));
120  pk->insertAtFront(hdr);
121  pk->insertAtBack(payload);
122  delete buf->packet;
123  bufs.erase(i);
124  return pk;
125  }
126  else {
127  // there are still missing fragments
128  return nullptr;
129  }
130 }

Referenced by inet::Ipv6::localDeliver().

◆ init()

void inet::Ipv6FragBuf::init ( Icmpv6 icmp)

Initialize fragmentation buffer.

ICMP module is needed for sending TIME_EXCEEDED ICMP message in purgeStaleFragments().

33 {
34  icmpModule = icmp;
35 }

Referenced by inet::Ipv6::initialize().

◆ purgeStaleFragments()

void inet::Ipv6FragBuf::purgeStaleFragments ( simtime_t  lastupdate)

Throws out all fragments which are incomplete and their last update (last fragment arrival) was before "lastupdate", and sends ICMP TIME EXCEEDED message about them.

Timeout should be between 60 seconds and 120 seconds (RFC1122). This method should be called more frequently, maybe every 10..30 seconds or so.

144 {
145  // this method shouldn't be called too often because iteration on
146  // an std::map is *very* slow...
147 
148  ASSERT(icmpModule);
149 
150  for (auto i = bufs.begin(); i != bufs.end();) {
151  // if too old, remove it
152  DatagramBuffer& buf = i->second;
153  if (buf.createdAt < lastupdate) {
154  if (buf.packet) {
155  // send ICMP error
156  EV_INFO << "datagram fragment timed out in reassembly buffer, sending ICMP_TIME_EXCEEDED\n";
158  delete buf.packet;
159  }
160 
161  // delete
162  auto oldi = i++;
163  bufs.erase(oldi);
164  }
165  else {
166  ++i;
167  }
168  }
169 }

Referenced by inet::Ipv6::localDeliver().

Member Data Documentation

◆ bufs

Buffers inet::Ipv6FragBuf::bufs
protected

◆ icmpModule

Icmpv6* inet::Ipv6FragBuf::icmpModule = nullptr
protected

The documentation for this class was generated from the following files:
inet::Icmpv6::sendErrorMessage
virtual void sendErrorMessage(Packet *datagram, Icmpv6Type type, int code)
This method can be called from other modules to send an ICMPv6 error packet.
Definition: Icmpv6.cc:184
inet::Ipv6FragBuf::bufs
Buffers bufs
Definition: Ipv6FragBuf.h:57
inet::IP_PROT_IPv6EXT_FRAGMENT
@ IP_PROT_IPv6EXT_FRAGMENT
Definition: IpProtocolId_m.h:114
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::ICMPv6_PARAMETER_PROBLEM
@ ICMPv6_PARAMETER_PROBLEM
Definition: Icmpv6Header_m.h:88
inet::ICMPv6_TIME_EXCEEDED
@ ICMPv6_TIME_EXCEEDED
Definition: Icmpv6Header_m.h:87
inet::Ipv6FragBuf::icmpModule
Icmpv6 * icmpModule
Definition: Ipv6FragBuf.h:60
inet::Macho::Key
void * Key
Definition: Macho.h:327
inet::ERROREOUS_HDR_FIELD
@ ERROREOUS_HDR_FIELD
Definition: Icmpv6Header_m.h:168