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

Reassembly buffer for fragmented IPv4 datagrams. More...

#include <IPv4FragBuf.h>

Classes

struct  DatagramBuffer
 
struct  Key
 

Public Member Functions

 IPv4FragBuf ()
 Ctor. More...
 
 ~IPv4FragBuf ()
 Dtor. More...
 
void init (ICMP *icmp)
 Initialize fragmentation buffer. More...
 
IPv4DatagramaddFragment (IPv4Datagram *datagram, 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
 
ICMPicmpModule
 

Detailed Description

Reassembly buffer for fragmented IPv4 datagrams.

Member Typedef Documentation

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

Constructor & Destructor Documentation

inet::IPv4FragBuf::IPv4FragBuf ( )

Ctor.

33 {
34  icmpModule = nullptr;
35 }
ICMP * icmpModule
Definition: IPv4FragBuf.h:71
inet::IPv4FragBuf::~IPv4FragBuf ( )

Dtor.

38 {
39  while (!bufs.empty()) {
40  if (bufs.begin()->second.datagram)
41  delete bufs.begin()->second.datagram;
42 
43  bufs.erase(bufs.begin());
44  }
45 }
Buffers bufs
Definition: IPv4FragBuf.h:68

Member Function Documentation

IPv4Datagram * inet::IPv4FragBuf::addFragment ( IPv4Datagram datagram,
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.

Referenced by inet::IPv4::reassembleAndDeliver().

53 {
54  // find datagram buffer
55  Key key;
56  key.id = datagram->getIdentification();
57  key.src = datagram->getSrcAddress();
58  key.dest = datagram->getDestAddress();
59 
60  auto i = bufs.find(key);
61 
62  DatagramBuffer *buf = nullptr;
63 
64  if (i == bufs.end()) {
65  // this is the first fragment of that datagram, create reassembly buffer for it
66  buf = &bufs[key];
67  buf->datagram = nullptr;
68  }
69  else {
70  // use existing buffer
71  buf = &(i->second);
72  }
73 
74  // add fragment into reassembly buffer
75  int bytes = datagram->getByteLength() - datagram->getHeaderLength();
76  bool isComplete = buf->buf.addFragment(datagram->getFragmentOffset(),
77  datagram->getFragmentOffset() + bytes,
78  !datagram->getMoreFragments());
79 
80  // store datagram. Only one fragment carries the actual modelled
81  // content (getEncapsulatedPacket()), other (empty) ones are only
82  // preserved so that we can send them in ICMP if reassembly times out.
83  if (buf->datagram == nullptr) {
84  if (dynamic_cast<RawPacket *>(datagram->getEncapsulatedPacket())) {
85  RawPacket * rp = static_cast<RawPacket *>(datagram->getEncapsulatedPacket());
86  // move raw bytes to its offset in RawPacket
87  if (datagram->getFragmentOffset()) {
88  rp->getByteArray().expandData(datagram->getFragmentOffset(), 0);
89  rp->addByteLength(datagram->getFragmentOffset());
90  }
91  }
92 
93  buf->datagram = datagram;
94  }
95  else if (buf->datagram->getEncapsulatedPacket() == nullptr && datagram->getEncapsulatedPacket() != nullptr) {
96  delete buf->datagram;
97 
98  if (dynamic_cast<RawPacket *>(datagram->getEncapsulatedPacket())) {
99  RawPacket *rp = static_cast<RawPacket *>(datagram->getEncapsulatedPacket());
100  // move raw bytes to its offset in RawPacket
101  if (datagram->getFragmentOffset()) {
102  rp->getByteArray().expandData(datagram->getFragmentOffset(), 0);
103  rp->setByteLength(rp->getByteArray().getDataArraySize());
104  }
105  }
106 
107  buf->datagram = datagram;
108  }
109  else {
110  RawPacket *brp = dynamic_cast<RawPacket *>(buf->datagram->getEncapsulatedPacket());
111  RawPacket *rp = dynamic_cast<RawPacket *>(datagram->getEncapsulatedPacket());
112  if (brp && rp) {
113  // merge encapsulated raw data
114  brp->getByteArray().copyDataFromBuffer(datagram->getFragmentOffset(), rp->getByteArray().getDataPtr(), rp->getByteArray().getDataArraySize());
115  brp->setByteLength(rp->getByteArray().getDataArraySize());
116  }
117  delete datagram;
118  }
119 
120  // do we have the complete datagram?
121  if (isComplete) {
122  // datagram complete: deallocate buffer and return complete datagram
123  IPv4Datagram *ret = buf->datagram;
124  ret->setByteLength(ret->getHeaderLength() + buf->buf.getTotalLength());
125  ret->setFragmentOffset(0);
126  ret->setMoreFragments(false);
127  bufs.erase(i);
128  if (dynamic_cast<RawPacket *>(ret->getEncapsulatedPacket())) {
129  using namespace serializer;
130  RawPacket *rp = static_cast<RawPacket *>(ret->getEncapsulatedPacket());
131  char ipv4addresses[8]; // 2 * 4 bytes for 2 IPv4 addresses
132  Buffer hdr(ipv4addresses, sizeof(ipv4addresses));
133  hdr.writeIPv4Address(ret->getSrcAddress());
134  hdr.writeIPv4Address(ret->getDestAddress());
135  Buffer b(rp->getByteArray().getDataPtr(), rp->getByteArray().getDataArraySize());
136  Context c;
137  c.l3AddressesPtr = ipv4addresses;
138  c.l3AddressesLength = sizeof(ipv4addresses);
139  cPacket *enc = SerializerBase::lookupAndDeserialize(b, c, IP_PROT, ret->getTransportProtocol());
140  if (enc) {
141  delete ret->decapsulate();
142  ret->encapsulate(enc);
143  }
144  }
145  return ret;
146  }
147  else {
148  // there are still missing fragments
149  buf->lastupdate = now;
150  return nullptr;
151  }
152 }
Buffers bufs
Definition: IPv4FragBuf.h:68
Definition: SerializerBase.h:38
const value< double, compose< units::m, pow< units::s,-1 > > > c(299792458)
void * Key
Definition: Macho.h:325
static cPacket * lookupAndDeserialize(const Buffer &b, Context &context, ProtocolGroup group, int id, unsigned int maxLength=(unsigned int)(-1))
Definition: SerializerBase.cc:99
value< double, units::m > b
Definition: Units.h:1054
void inet::IPv4FragBuf::init ( ICMP icmp)

Initialize fragmentation buffer.

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

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

48 {
49  icmpModule = icmp;
50 }
ICMP * icmpModule
Definition: IPv4FragBuf.h:71
void inet::IPv4FragBuf::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.

Referenced by inet::IPv4::reassembleAndDeliver().

155 {
156  // this method shouldn't be called too often because iteration on
157  // an std::map is *very* slow...
158 
159  ASSERT(icmpModule);
160 
161  for (auto i = bufs.begin(); i != bufs.end(); ) {
162  // if too old, remove it
163  DatagramBuffer& buf = i->second;
164  if (buf.lastupdate < lastupdate) {
165  // send ICMP error.
166  // Note: receiver MUST NOT call decapsulate() on the datagram fragment,
167  // because its length (being a fragment) is smaller than the encapsulated
168  // packet, resulting in "length became negative" error. Use getEncapsulatedPacket().
169  EV_WARN << "datagram fragment timed out in reassembly buffer, sending ICMP_TIME_EXCEEDED\n";
170  icmpModule->sendErrorMessage(buf.datagram, -1 /*TODO*/, ICMP_TIME_EXCEEDED, 0);
171 
172  // delete
173  auto oldi = i++;
174  bufs.erase(oldi);
175  }
176  else {
177  ++i;
178  }
179  }
180 }
virtual void sendErrorMessage(IPv4Datagram *datagram, int inputInterfaceId, ICMPType type, ICMPCode code)
This method can be called from other modules to send an ICMP error packet in response to a received b...
Definition: ICMP.cc:66
Buffers bufs
Definition: IPv4FragBuf.h:68
ICMP * icmpModule
Definition: IPv4FragBuf.h:71
Definition: ICMPMessage_m.h:72

Member Data Documentation

Buffers inet::IPv4FragBuf::bufs
protected
ICMP* inet::IPv4FragBuf::icmpModule
protected

The documentation for this class was generated from the following files: