|
INET Framework for OMNeT++/OMNEST
|
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->getEncapsulatedPacket()); 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 }