ICMPv6.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Andras Varga
00003 // Copyright (C) 2005 Wei Yang, Ng
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 #include <omnetpp.h>
00020 #include "ICMPv6.h"
00021 
00022 
00023 Define_Module(ICMPv6);
00024 
00025 
00026 void ICMPv6::initialize()
00027 {
00028 }
00029 
00030 void ICMPv6::handleMessage(cMessage *msg)
00031 {
00032     ASSERT(!msg->isSelfMessage()); // no timers in ICMPv6
00033 
00034     // process arriving ICMP message
00035     if (msg->getArrivalGate()->isName("ipv6In"))
00036     {
00037         EV << "Processing ICMPv6 message.\n";
00038         processICMPv6Message(check_and_cast<ICMPv6Message *>(msg));
00039         return;
00040     }
00041 
00042     // request from application
00043     if (msg->getArrivalGate()->isName("pingIn"))
00044     {
00045         sendEchoRequest(PK(msg));
00046         return;
00047     }
00048 }
00049 
00050 void ICMPv6::processICMPv6Message(ICMPv6Message *icmpv6msg)
00051 {
00052     ASSERT(dynamic_cast<ICMPv6Message *>(icmpv6msg));
00053     if (dynamic_cast<ICMPv6DestUnreachableMsg *>(icmpv6msg))
00054     {
00055         EV << "ICMPv6 Destination Unreachable Message Received." << endl;
00056         errorOut(icmpv6msg);
00057     }
00058     else if (dynamic_cast<ICMPv6PacketTooBigMsg *>(icmpv6msg))
00059     {
00060         EV << "ICMPv6 Packet Too Big Message Received." << endl;
00061         errorOut(icmpv6msg);
00062     }
00063     else if (dynamic_cast<ICMPv6TimeExceededMsg *>(icmpv6msg))
00064     {
00065         EV << "ICMPv6 Time Exceeded Message Received." << endl;
00066         errorOut(icmpv6msg);
00067     }
00068     else if (dynamic_cast<ICMPv6ParamProblemMsg *>(icmpv6msg))
00069     {
00070         EV << "ICMPv6 Parameter Problem Message Received." << endl;
00071         errorOut(icmpv6msg);
00072     }
00073     else if (dynamic_cast<ICMPv6EchoRequestMsg *>(icmpv6msg))
00074     {
00075         EV << "ICMPv6 Echo Request Message Received." << endl;
00076         processEchoRequest((ICMPv6EchoRequestMsg *)icmpv6msg);
00077     }
00078     else if (dynamic_cast<ICMPv6EchoReplyMsg *>(icmpv6msg))
00079     {
00080         EV << "ICMPv6 Echo Reply Message Received." << endl;
00081         processEchoReply((ICMPv6EchoReplyMsg *)icmpv6msg);
00082     }
00083     else
00084         error("Unknown message type received.\n");
00085 }
00086 
00087 void ICMPv6::processEchoRequest(ICMPv6EchoRequestMsg *request)
00088 {
00089     //Create an ICMPv6 Reply Message
00090     ICMPv6EchoReplyMsg *reply = new ICMPv6EchoReplyMsg("Echo Reply");
00091     reply->setName((std::string(request->getName())+"-reply").c_str());
00092     reply->setType(ICMPv6_ECHO_REPLY);
00093     reply->encapsulate(request->decapsulate());
00094 
00095     // TBD check what to do if dest was multicast etc?
00096     IPv6ControlInfo *ctrl
00097         = check_and_cast<IPv6ControlInfo *>(request->getControlInfo());
00098     IPv6ControlInfo *replyCtrl = new IPv6ControlInfo();
00099     replyCtrl->setProtocol(IP_PROT_IPv6_ICMP);
00100     //set Msg's source addr as the dest addr of request msg.
00101     replyCtrl->setSrcAddr(ctrl->getDestAddr());
00102     //set Msg's dest addr as the source addr of request msg.
00103     replyCtrl->setDestAddr(ctrl->getSrcAddr());
00104     reply->setControlInfo(replyCtrl);
00105 
00106     delete request;
00107     sendToIP(reply);
00108 }
00109 
00110 void ICMPv6::processEchoReply(ICMPv6EchoReplyMsg *reply)
00111 {
00112     IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo*>(reply->removeControlInfo());
00113     cPacket *payload = reply->decapsulate();
00114     payload->setControlInfo(ctrl);
00115     delete reply;
00116     send(payload, "pingOut");
00117 }
00118 
00119 void ICMPv6::sendEchoRequest(cPacket *msg)
00120 {
00121     IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo*>(msg->removeControlInfo());
00122     ctrl->setProtocol(IP_PROT_IPv6_ICMP);
00123     ICMPv6EchoRequestMsg *request = new ICMPv6EchoRequestMsg(msg->getName());
00124     request->setType(ICMPv6_ECHO_REQUEST);
00125     request->encapsulate(msg);
00126     request->setControlInfo(ctrl);
00127     sendToIP(request);
00128 }
00129 
00130 void ICMPv6::sendErrorMessage(IPv6Datagram *origDatagram, ICMPv6Type type, int code)
00131 {
00132     Enter_Method("sendErrorMessage(datagram, type=%d, code=%d)", type, code);
00133 
00134     // get ownership
00135     take(origDatagram);
00136 
00137     if (!validateDatagramPromptingError(origDatagram))
00138         return;
00139 
00140     ICMPv6Message *errorMsg;
00141 
00142     if (type == ICMPv6_DESTINATION_UNREACHABLE) errorMsg = createDestUnreachableMsg(code);
00143     //TODO: implement MTU support.
00144     else if (type == ICMPv6_PACKET_TOO_BIG) errorMsg = createPacketTooBigMsg(0);
00145     else if (type == ICMPv6_TIME_EXCEEDED) errorMsg = createTimeExceededMsg(code);
00146     else if (type == ICMPv6_PARAMETER_PROBLEM) errorMsg = createParamProblemMsg(code);
00147     else error("Unknown ICMPv6 error type\n");
00148 
00149     errorMsg->encapsulate(origDatagram);
00150 
00151     // debugging information
00152     EV << "sending ICMP error: (" << errorMsg->getClassName() << ")" << errorMsg->getName()
00153        << " type=" << type << " code=" << code << endl;
00154 
00155     // ICMP message length: the internet header plus the first 8 bytes of
00156     // the original datagram's data is returned to the sender
00157     //errorMessage->setByteLength(4 + origDatagram->getHeaderLength() + 8); FIXME What is this for?
00158 
00159     // if srcAddr is not filled in, we're still in the src node, so we just
00160     // process the ICMP message locally, right away
00161     if (origDatagram->getSrcAddress().isUnspecified())
00162     {
00163         // pretend it came from the IP layer
00164         IPv6ControlInfo *ctrlInfo = new IPv6ControlInfo();
00165         ctrlInfo->setSrcAddr(IPv6Address::LOOPBACK_ADDRESS); // FIXME maybe use configured loopback address
00166         ctrlInfo->setProtocol(IP_PROT_ICMP);
00167         errorMsg->setControlInfo(ctrlInfo);
00168 
00169         // then process it locally
00170         processICMPv6Message(errorMsg);
00171     }
00172     else
00173     {
00174         sendToIP(errorMsg, origDatagram->getSrcAddress());
00175     }
00176 }
00177 
00178 void ICMPv6::sendErrorMessage(cPacket *transportPacket, IPv6ControlInfo *ctrl, ICMPv6Type type, int code)
00179 {
00180     Enter_Method("sendErrorMessage(transportPacket, ctrl, type=%d, code=%d)", type, code);
00181 
00182     IPv6Datagram *datagram = ctrl->removeOrigDatagram();
00183     datagram->encapsulate(transportPacket);
00184     sendErrorMessage(datagram, type, code);
00185 }
00186 
00187 void ICMPv6::sendToIP(ICMPv6Message *msg, const IPv6Address& dest)
00188 {
00189 
00190     IPv6ControlInfo *ctrlInfo = new IPv6ControlInfo();
00191     ctrlInfo->setDestAddr(dest);
00192     ctrlInfo->setProtocol(IP_PROT_IPv6_ICMP);
00193     msg->setControlInfo(ctrlInfo);
00194 
00195     send(msg,"ipv6Out");
00196 }
00197 
00198 void ICMPv6::sendToIP(ICMPv6Message *msg)
00199 {
00200     // assumes IPControlInfo is already attached
00201     send(msg,"ipv6Out");
00202 }
00203 
00204 ICMPv6Message *ICMPv6::createDestUnreachableMsg(int code)
00205 {
00206     ICMPv6DestUnreachableMsg *errorMsg = new ICMPv6DestUnreachableMsg("Dest Unreachable");
00207     errorMsg->setType(ICMPv6_DESTINATION_UNREACHABLE);
00208     errorMsg->setCode(code);
00209     return errorMsg;
00210 }
00211 
00212 ICMPv6Message *ICMPv6::createPacketTooBigMsg(int mtu)
00213 {
00214     ICMPv6PacketTooBigMsg *errorMsg = new ICMPv6PacketTooBigMsg("Packet Too Big");
00215     errorMsg->setType(ICMPv6_PACKET_TOO_BIG);
00216     errorMsg->setCode(0);//Set to 0 by sender and ignored by receiver.
00217     errorMsg->setMTU(mtu);
00218     return errorMsg;
00219 }
00220 
00221 ICMPv6Message *ICMPv6::createTimeExceededMsg(int code)
00222 {
00223     ICMPv6TimeExceededMsg *errorMsg = new ICMPv6TimeExceededMsg("Time Exceeded");
00224     errorMsg->setType(ICMPv6_TIME_EXCEEDED);
00225     errorMsg->setCode(code);
00226     return errorMsg;
00227 }
00228 
00229 ICMPv6Message *ICMPv6::createParamProblemMsg(int code)
00230 {
00231     ICMPv6ParamProblemMsg *errorMsg = new ICMPv6ParamProblemMsg("Parameter Problem");
00232     errorMsg->setType(ICMPv6_PARAMETER_PROBLEM);
00233     errorMsg->setCode(code);
00234     //TODO: What Pointer? section 3.4
00235     return errorMsg;
00236 }
00237 
00238 bool ICMPv6::validateDatagramPromptingError(IPv6Datagram *origDatagram)
00239 {
00240     // don't send ICMP error messages for multicast messages
00241     if (origDatagram->getDestAddress().isMulticast())
00242     {
00243         EV << "won't send ICMP error messages for multicast message " << origDatagram << endl;
00244         delete origDatagram;
00245         return false;
00246     }
00247 
00248     // do not reply with error message to error message
00249     if (origDatagram->getTransportProtocol() == IP_PROT_IPv6_ICMP)
00250     {
00251         ICMPv6Message *recICMPMsg = check_and_cast<ICMPv6Message *>(origDatagram->getEncapsulatedMsg());
00252         if (recICMPMsg->getType()<128)
00253         {
00254             EV << "ICMP error received -- do not reply to it" << endl;
00255             delete origDatagram;
00256             return false;
00257         }
00258     }
00259     return true;
00260 }
00261 
00262 void ICMPv6::errorOut(ICMPv6Message *icmpv6msg)
00263 {
00264     send(icmpv6msg, "errorOut");
00265 }