|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004 Andras Varga 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU Lesser General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU Lesser General Public License 00015 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 00019 #include <omnetpp.h> 00020 #include <stdlib.h> 00021 #include <string.h> 00022 00023 #include "IPFragBuf.h" 00024 #include "ICMP.h" 00025 00026 00027 IPFragBuf::IPFragBuf() 00028 { 00029 icmpModule = NULL; 00030 } 00031 00032 IPFragBuf::~IPFragBuf() 00033 { 00034 } 00035 00036 void IPFragBuf::init(ICMP *icmp) 00037 { 00038 icmpModule = icmp; 00039 } 00040 00041 IPDatagram *IPFragBuf::addFragment(IPDatagram *datagram, simtime_t now) 00042 { 00043 // find datagram buffer 00044 Key key; 00045 key.id = datagram->getIdentification(); 00046 key.src = datagram->getSrcAddress(); 00047 key.dest = datagram->getDestAddress(); 00048 00049 Buffers::iterator i = bufs.find(key); 00050 00051 DatagramBuffer *buf = NULL; 00052 if (i==bufs.end()) 00053 { 00054 // this is the first fragment of that datagram, create reassembly buffer for it 00055 buf = &bufs[key]; 00056 buf->datagram = NULL; 00057 } 00058 else 00059 { 00060 // use existing buffer 00061 buf = &(i->second); 00062 } 00063 00064 // add fragment into reassembly buffer 00065 int bytes = datagram->getByteLength() - datagram->getHeaderLength(); 00066 bool isComplete = buf->buf.addFragment(datagram->getFragmentOffset(), 00067 datagram->getFragmentOffset() + bytes, 00068 !datagram->getMoreFragments()); 00069 00070 // store datagram. Only one fragment carries the actual modelled 00071 // content (getEncapsulatedPacket()), other (empty) ones are only 00072 // preserved so that we can send them in ICMP if reassembly times out. 00073 if (datagram->getEncapsulatedPacket()) 00074 { 00075 delete buf->datagram; 00076 buf->datagram = datagram; 00077 } 00078 else 00079 { 00080 delete datagram; 00081 } 00082 00083 // do we have the complete datagram? 00084 if (isComplete) 00085 { 00086 // datagram complete: deallocate buffer and return complete datagram 00087 IPDatagram *ret = buf->datagram; 00088 ret->setByteLength(ret->getHeaderLength()+buf->buf.getTotalLength()); 00089 ret->setFragmentOffset(0); 00090 ret->setMoreFragments(false); 00091 bufs.erase(i); 00092 return ret; 00093 } 00094 else 00095 { 00096 // there are still missing fragments 00097 buf->lastupdate = now; 00098 return NULL; 00099 } 00100 } 00101 00102 void IPFragBuf::purgeStaleFragments(simtime_t lastupdate) 00103 { 00104 // this method shouldn't be called too often because iteration on 00105 // an std::map is *very* slow... 00106 00107 ASSERT(icmpModule); 00108 00109 for (Buffers::iterator i=bufs.begin(); i!=bufs.end(); ) 00110 { 00111 // if too old, remove it 00112 DatagramBuffer& buf = i->second; 00113 if (buf.lastupdate < lastupdate) 00114 { 00115 // send ICMP error. 00116 // Note: receiver MUST NOT call decapsulate() on the datagram fragment, 00117 // because its length (being a fragment) is smaller than the encapsulated 00118 // packet, resulting in "length became negative" error. Use getEncapsulatedPacket(). 00119 EV << "datagram fragment timed out in reassembly buffer, sending ICMP_TIME_EXCEEDED\n"; 00120 icmpModule->sendErrorMessage(buf.datagram, ICMP_TIME_EXCEEDED, 0); 00121 00122 // delete 00123 Buffers::iterator oldi = i++; 00124 bufs.erase(oldi); 00125 } 00126 else 00127 { 00128 ++i; 00129 } 00130 } 00131 } 00132