ICMP.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2000 Institut fuer Telematik, Universitaet Karlsruhe
00003 // Copyright (C) 2004 Andras Varga
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 //  Cleanup and rewrite: Andras Varga, 2004
00020 
00021 #include <omnetpp.h>
00022 #include <string.h>
00023 
00024 #include "IPDatagram.h"
00025 #include "IPControlInfo.h"
00026 #include "ICMP.h"
00027 
00028 Define_Module(ICMP);
00029 
00030 
00031 void ICMP::handleMessage(cMessage *msg)
00032 {
00033     cGate *arrivalGate = msg->getArrivalGate();
00034 
00035     // process arriving ICMP message
00036     if (!strcmp(arrivalGate->getName(), "localIn"))
00037     {
00038         processICMPMessage(check_and_cast<ICMPMessage *>(msg));
00039         return;
00040     }
00041 
00042     // request from application
00043     if (!strcmp(arrivalGate->getName(), "pingIn"))
00044     {
00045         sendEchoRequest(PK(msg));
00046         return;
00047     }
00048 }
00049 
00050 
00051 void ICMP::sendErrorMessage(IPDatagram *origDatagram, ICMPType type, ICMPCode code)
00052 {
00053     Enter_Method("sendErrorMessage(datagram, type=%d, code=%d)", type, code);
00054 
00055     // get ownership
00056     take(origDatagram);
00057 
00058     // don't send ICMP error messages for multicast messages
00059     if (origDatagram->getDestAddress().isMulticast())
00060     {
00061         EV << "won't send ICMP error messages for multicast message " << origDatagram << endl;
00062         delete origDatagram;
00063         return;
00064     }
00065 
00066     // do not reply with error message to error message
00067     if (origDatagram->getTransportProtocol() == IP_PROT_ICMP)
00068     {
00069         ICMPMessage *recICMPMsg = check_and_cast<ICMPMessage *>(origDatagram->getEncapsulatedMsg());
00070         if (recICMPMsg->getType()<128)
00071         {
00072             EV << "ICMP error received -- do not reply to it" << endl;
00073             delete origDatagram;
00074             return;
00075         }
00076     }
00077 
00078     // assemble a message name
00079     char msgname[32];
00080     static long ctr;
00081     sprintf(msgname, "ICMP-error-#%ld-type%d-code%d", ++ctr, type, code);
00082 
00083     // debugging information
00084     EV << "sending ICMP error " << msgname << endl;
00085 
00086     // create and send ICMP packet
00087     ICMPMessage *errorMessage = new ICMPMessage(msgname);
00088     errorMessage->setType(type);
00089     errorMessage->setCode(code);
00090     errorMessage->encapsulate(origDatagram);
00091 
00092     // ICMP message length: the internet header plus the first 8 bytes of
00093     // the original datagram's data is returned to the sender.
00094     //
00095     // NOTE: since we just overwrite the errorMessage length without actually
00096     // truncating origDatagram, one can get "packet length became negative"
00097     // error when decapsulating the origDatagram on the receiver side.
00098     // A workaround is to avoid decapsulation, or to manually set the
00099     // errorMessage length to be larger than the encapsulated message.
00100     int dataLength = origDatagram->getByteLength() - origDatagram->getHeaderLength();
00101     int truncatedDataLength = dataLength <= 8 ? dataLength : 8;
00102     errorMessage->setByteLength(8 + origDatagram->getHeaderLength() + truncatedDataLength);
00103 
00104     // if srcAddr is not filled in, we're still in the src node, so we just
00105     // process the ICMP message locally, right away
00106     if (origDatagram->getSrcAddress().isUnspecified())
00107     {
00108         // pretend it came from the IP layer
00109         IPControlInfo *controlInfo = new IPControlInfo();
00110         controlInfo->setSrcAddr(IPAddress::LOOPBACK_ADDRESS); // FIXME maybe use configured loopback address
00111         controlInfo->setProtocol(IP_PROT_ICMP);
00112         errorMessage->setControlInfo(controlInfo);
00113 
00114         // then process it locally
00115         processICMPMessage(errorMessage);
00116     }
00117     else
00118     {
00119         sendToIP(errorMessage, origDatagram->getSrcAddress());
00120     }
00121 }
00122 
00123 void ICMP::sendErrorMessage(cPacket *transportPacket, IPControlInfo *ctrl, ICMPType type, ICMPCode code)
00124 {
00125     Enter_Method("sendErrorMessage(transportPacket, ctrl, type=%d, code=%d)", type, code);
00126 
00127     IPDatagram *datagram = ctrl->removeOrigDatagram();
00128     take(transportPacket);
00129     take(datagram);
00130     datagram->encapsulate(transportPacket);
00131     sendErrorMessage(datagram, type, code);
00132 }
00133 
00134 void ICMP::processICMPMessage(ICMPMessage *icmpmsg)
00135 {
00136     switch (icmpmsg->getType())
00137     {
00138         case ICMP_DESTINATION_UNREACHABLE:
00139             errorOut(icmpmsg);
00140             break;
00141         case ICMP_REDIRECT:
00142             errorOut(icmpmsg);
00143             break;
00144         case ICMP_TIME_EXCEEDED:
00145             errorOut(icmpmsg);
00146             break;
00147         case ICMP_PARAMETER_PROBLEM:
00148             errorOut(icmpmsg);
00149             break;
00150         case ICMP_ECHO_REQUEST:
00151             processEchoRequest(icmpmsg);
00152             break;
00153         case ICMP_ECHO_REPLY:
00154             processEchoReply(icmpmsg);
00155             break;
00156         case ICMP_TIMESTAMP_REQUEST:
00157             processEchoRequest(icmpmsg);
00158             break;
00159         case ICMP_TIMESTAMP_REPLY:
00160             processEchoReply(icmpmsg);
00161             break;
00162         default:
00163             opp_error("Unknown ICMP type %d", icmpmsg->getType());
00164     }
00165 }
00166 
00167 void ICMP::errorOut(ICMPMessage *icmpmsg)
00168 {
00169     send(icmpmsg, "errorOut");
00170 }
00171 
00172 void ICMP::processEchoRequest(ICMPMessage *request)
00173 {
00174     // turn request into a reply
00175     ICMPMessage *reply = request;
00176     reply->setName((std::string(request->getName())+"-reply").c_str());
00177     reply->setType(ICMP_ECHO_REPLY);
00178 
00179     // swap src and dest
00180     // TBD check what to do if dest was multicast etc?
00181     IPControlInfo *ctrl = check_and_cast<IPControlInfo *>(reply->getControlInfo());
00182     IPAddress src = ctrl->getSrcAddr();
00183     IPAddress dest = ctrl->getDestAddr();
00184     ctrl->setSrcAddr(dest);
00185     ctrl->setDestAddr(src);
00186 
00187     sendToIP(reply);
00188 }
00189 
00190 void ICMP::processEchoReply(ICMPMessage *reply)
00191 {
00192     IPControlInfo *ctrl = check_and_cast<IPControlInfo*>(reply->removeControlInfo());
00193     cPacket *payload = reply->decapsulate();
00194     payload->setControlInfo(ctrl);
00195     delete reply;
00196     send(payload, "pingOut");
00197 }
00198 
00199 void ICMP::sendEchoRequest(cPacket *msg)
00200 {
00201     IPControlInfo *ctrl = check_and_cast<IPControlInfo*>(msg->removeControlInfo());
00202     ctrl->setProtocol(IP_PROT_ICMP);
00203     ICMPMessage *request = new ICMPMessage(msg->getName());
00204     request->setType(ICMP_ECHO_REQUEST);
00205     request->encapsulate(msg);
00206     request->setControlInfo(ctrl);
00207     sendToIP(request);
00208 }
00209 
00210 void ICMP::sendToIP(ICMPMessage *msg, const IPAddress& dest)
00211 {
00212     IPControlInfo *controlInfo = new IPControlInfo();
00213     controlInfo->setDestAddr(dest);
00214     controlInfo->setProtocol(IP_PROT_ICMP);
00215     msg->setControlInfo(controlInfo);
00216 
00217     send(msg, "sendOut");
00218 }
00219 
00220 void ICMP::sendToIP(ICMPMessage *msg)
00221 {
00222     // assumes IPControlInfo is already attached
00223     send(msg, "sendOut");
00224 }
00225