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...
 
PacketaddFragment (Packet *packet, simtime_t now)
 Takes a fragment and inserts it into the reassembly buffer. More...
 
void purgeStaleFragments (Icmp *icmpModule, 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...
 
void flush ()
 Clear all state. More...
 

Protected Types

typedef std::map< Key, DatagramBufferBuffers
 

Protected Attributes

Buffers bufs
 

Detailed Description

Reassembly buffer for fragmented Ipv4 datagrams.

Member Typedef Documentation

◆ Buffers

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

Constructor & Destructor Documentation

◆ Ipv4FragBuf()

inet::Ipv4FragBuf::Ipv4FragBuf ( )

Ctor.

19 {
20 }

◆ ~Ipv4FragBuf()

inet::Ipv4FragBuf::~Ipv4FragBuf ( )

Dtor.

23 {
24  flush();
25 }

Member Function Documentation

◆ addFragment()

Packet * inet::Ipv4FragBuf::addFragment ( Packet packet,
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.

35 {
36  const auto& ipv4Header = packet->peekAtFront<Ipv4Header>();
37  // find datagram buffer
38  Key key;
39  key.id = ipv4Header->getIdentification();
40  key.src = ipv4Header->getSrcAddress();
41  key.dest = ipv4Header->getDestAddress();
42 
43  auto i = bufs.find(key);
44 
45  DatagramBuffer *curBuf = nullptr;
46 
47  if (i == bufs.end()) {
48  // this is the first fragment of that datagram, create reassembly buffer for it
49  curBuf = &bufs[key];
50  i = bufs.find(key);
51  }
52  else {
53  // use existing buffer
54  curBuf = &(i->second);
55  }
56 
57  // add fragment into reassembly buffer
58  ASSERT(ipv4Header->getTotalLengthField() > ipv4Header->getHeaderLength());
59  B bytes = ipv4Header->getTotalLengthField() - ipv4Header->getHeaderLength();
60  curBuf->buf.replace(B(ipv4Header->getFragmentOffset()), packet->peekDataAt(B(ipv4Header->getHeaderLength()), bytes));
61  if (!ipv4Header->getMoreFragments()) {
62  curBuf->buf.setExpectedLength(B(ipv4Header->getFragmentOffset()) + bytes);
63  }
64  if (ipv4Header->getFragmentOffset() == 0 || curBuf->packet == nullptr) {
65  delete curBuf->packet;
66  curBuf->packet = packet;
67  }
68  else {
69  delete packet;
70  }
71 
72  // do we have the complete datagram?
73  if (curBuf->buf.isComplete()) {
74  // datagram complete: deallocate buffer and return complete datagram
75  std::string pkName(curBuf->packet->getName());
76  std::size_t found = pkName.find("-frag-");
77  if (found != std::string::npos)
78  pkName.resize(found);
79  auto hdr = Ptr<Ipv4Header>(curBuf->packet->peekAtFront<Ipv4Header>()->dup());
80  Packet *pk = curBuf->packet;
81  pk->setName(pkName.c_str());
82  pk->removeAll();
83  const auto& payload = curBuf->buf.getReassembledData();
84  hdr->setTotalLengthField(hdr->getHeaderLength() + payload->getChunkLength());
85  hdr->setFragmentOffset(0);
86  hdr->setMoreFragments(false);
87  pk->insertAtFront(hdr);
88  pk->insertAtBack(payload);
89  bufs.erase(i);
90  return pk;
91  }
92  else {
93  // there are still missing fragments
94  curBuf->lastupdate = now;
95  return nullptr;
96  }
97 }

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

◆ flush()

void inet::Ipv4FragBuf::flush ( )

Clear all state.

28 {
29  for (auto i = bufs.begin(); i != bufs.end(); ++i)
30  delete i->second.packet;
31  bufs.clear();
32 }

Referenced by inet::Ipv4::flush(), and ~Ipv4FragBuf().

◆ purgeStaleFragments()

void inet::Ipv4FragBuf::purgeStaleFragments ( Icmp icmpModule,
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.

100 {
101  // this method shouldn't be called too often because iteration on
102  // an std::map is *very* slow...
103 
104  ASSERT(icmpModule);
105 
106  for (auto i = bufs.begin(); i != bufs.end();) {
107  // if too old, remove it
108  DatagramBuffer& buf = i->second;
109  if (buf.lastupdate < lastupdate) {
110  // send ICMP error.
111  // Note: receiver MUST NOT call decapsulate() on the datagram fragment,
112  // because its length (being a fragment) is smaller than the encapsulated
113  // packet, resulting in "length became negative" error. Use getEncapsulatedPacket().
114  EV_WARN << "datagram fragment timed out in reassembly buffer, sending ICMP_TIME_EXCEEDED\n";
115  if (buf.packet != nullptr) {
116  icmpModule->sendErrorMessage(buf.packet, -1 /*TODO*/, ICMP_TIME_EXCEEDED, 0);
117  delete buf.packet;
118  }
119 
120  // delete
121  auto oldi = i++;
122  bufs.erase(oldi);
123  }
124  else {
125  ++i;
126  }
127  }
128 }

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

Member Data Documentation

◆ bufs

Buffers inet::Ipv4FragBuf::bufs
protected

The documentation for this class was generated from the following files:
inet::Ipv4FragBuf::bufs
Buffers bufs
Definition: Ipv4FragBuf.h:55
inet::Ipv4FragBuf::flush
void flush()
Clear all state.
Definition: Ipv4FragBuf.cc:27
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::ICMP_TIME_EXCEEDED
@ ICMP_TIME_EXCEEDED
Definition: IcmpHeader_m.h:83
inet::Macho::Key
void * Key
Definition: Macho.h:327