INET Framework for OMNeT++/OMNEST
inet::ICMPv6 Class Reference

ICMPv6 implementation. More...

#include <ICMPv6.h>

Inheritance diagram for inet::ICMPv6:
inet::ILifecycle

Public Member Functions

virtual void sendErrorMessage (IPv6Datagram *datagram, ICMPv6Type type, int code)
 This method can be called from other modules to send an ICMPv6 error packet. More...
 
virtual void sendErrorMessage (cPacket *transportPacket, IPv6ControlInfo *ctrl, ICMPv6Type type, int code)
 This method can be called from other modules to send an ICMP error packet in response to a received bogus packet from the transport layer (like UDP). More...
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 

Protected Types

typedef std::map< long, int > PingMap
 

Protected Member Functions

virtual void sendToIP (ICMPv6Message *msg, const IPv6Address &dest)
 
virtual void sendToIP (ICMPv6Message *msg)
 
virtual ICMPv6MessagecreateDestUnreachableMsg (int code)
 
virtual ICMPv6MessagecreatePacketTooBigMsg (int mtu)
 
virtual ICMPv6MessagecreateTimeExceededMsg (int code)
 
virtual ICMPv6MessagecreateParamProblemMsg (int code)
 
virtual void initialize (int stage) override
 Initialization. More...
 
virtual int numInitStages () const override
 
virtual void handleMessage (cMessage *msg) override
 Processing of messages that arrive in this module. More...
 
virtual void processICMPv6Message (ICMPv6Message *)
 
virtual bool handleOperationStage (LifecycleOperation *operation, int stage, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 
virtual void processEchoRequest (ICMPv6EchoRequestMsg *)
 Respond to the machine that tried to ping us. More...
 
virtual void processEchoReply (ICMPv6EchoReplyMsg *)
 Forward the ping reply to the "pingOut" of this module. More...
 
virtual void sendEchoRequest (PingPayload *)
 Ping a machine. More...
 
virtual bool validateDatagramPromptingError (IPv6Datagram *datagram)
 Validate the received IPv6 datagram before responding with error message. More...
 
virtual void errorOut (ICMPv6Message *)
 

Protected Attributes

PingMap pingMap
 

Detailed Description

ICMPv6 implementation.

Member Typedef Documentation

typedef std::map<long, int> inet::ICMPv6::PingMap
protected

Member Function Documentation

ICMPv6Message * inet::ICMPv6::createDestUnreachableMsg ( int  code)
protectedvirtual

Referenced by sendErrorMessage().

273 {
274  ICMPv6DestUnreachableMsg *errorMsg = new ICMPv6DestUnreachableMsg("Dest Unreachable");
275  errorMsg->setType(ICMPv6_DESTINATION_UNREACHABLE);
276  errorMsg->setCode(code);
277  return errorMsg;
278 }
Definition: ICMPv6Message_m.h:71
ICMPv6Message * inet::ICMPv6::createPacketTooBigMsg ( int  mtu)
protectedvirtual

Referenced by sendErrorMessage().

281 {
282  ICMPv6PacketTooBigMsg *errorMsg = new ICMPv6PacketTooBigMsg("Packet Too Big");
283  errorMsg->setType(ICMPv6_PACKET_TOO_BIG);
284  errorMsg->setCode(0); //Set to 0 by sender and ignored by receiver.
285  errorMsg->setMTU(mtu);
286  return errorMsg;
287 }
Definition: ICMPv6Message_m.h:72
ICMPv6Message * inet::ICMPv6::createParamProblemMsg ( int  code)
protectedvirtual

Referenced by sendErrorMessage().

298 {
299  ICMPv6ParamProblemMsg *errorMsg = new ICMPv6ParamProblemMsg("Parameter Problem");
300  errorMsg->setType(ICMPv6_PARAMETER_PROBLEM);
301  errorMsg->setCode(code);
302  //TODO: What Pointer? section 3.4
303  return errorMsg;
304 }
Definition: ICMPv6Message_m.h:74
ICMPv6Message * inet::ICMPv6::createTimeExceededMsg ( int  code)
protectedvirtual

Referenced by sendErrorMessage().

290 {
291  ICMPv6TimeExceededMsg *errorMsg = new ICMPv6TimeExceededMsg("Time Exceeded");
292  errorMsg->setType(ICMPv6_TIME_EXCEEDED);
293  errorMsg->setCode(code);
294  return errorMsg;
295 }
Definition: ICMPv6Message_m.h:73
void inet::ICMPv6::errorOut ( ICMPv6Message icmpv6msg)
protectedvirtual

Referenced by processICMPv6Message().

328 {
329  send(icmpv6msg, "errorOut");
330 }
void inet::ICMPv6::handleMessage ( cMessage *  msg)
overrideprotectedvirtual

Processing of messages that arrive in this module.

Messages arrived here could be for ICMP ping requests or ICMPv6 messages that require processing.

58 {
59  ASSERT(!msg->isSelfMessage()); // no timers in ICMPv6
60 
61  // process arriving ICMP message
62  if (msg->getArrivalGate()->isName("ipv6In")) {
63  EV_INFO << "Processing ICMPv6 message.\n";
64  processICMPv6Message(check_and_cast<ICMPv6Message *>(msg));
65  return;
66  }
67 
68  // request from application
69  if (msg->getArrivalGate()->isName("pingIn")) {
70  sendEchoRequest(check_and_cast<PingPayload *>(msg));
71  return;
72  }
73 }
virtual void processICMPv6Message(ICMPv6Message *)
Definition: ICMPv6.cc:75
virtual void sendEchoRequest(PingPayload *)
Ping a machine.
Definition: ICMPv6.cc:173
bool inet::ICMPv6::handleOperationStage ( LifecycleOperation operation,
int  stage,
IDoneCallback doneCallback 
)
overrideprotectedvirtual

Perform one stage of a lifecycle operation.

Processing may be done entirely within this method, or may be a longer process that involves nonzero simulation time or several events, and is triggered by this method call.

Return value: true = "done"; false = "not yet done, will invoke doneCallback when done"

Implements inet::ILifecycle.

333 {
334  //pingMap.clear();
335  throw cRuntimeError("Lifecycle operation support not implemented");
336 }
void inet::ICMPv6::initialize ( int  stage)
overrideprotectedvirtual

Initialization.

41 {
42  cSimpleModule::initialize(stage);
43 
44  if (stage == INITSTAGE_NETWORK_LAYER) {
45  bool isOperational;
46  NodeStatus *nodeStatus = dynamic_cast<NodeStatus *>(findContainingNode(this)->getSubmodule("status"));
47  isOperational = (!nodeStatus) || nodeStatus->getState() == NodeStatus::UP;
48  if (!isOperational)
49  throw cRuntimeError("This module doesn't support starting in node DOWN state");
50  }
51  if (stage == INITSTAGE_NETWORK_LAYER_2) {
52  IPSocket socket(gate("ipv6Out"));
53  socket.registerProtocol(IP_PROT_IPv6_ICMP);
54  }
55 }
cModule * findContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:56
Initialization of network-layer protocols, stage 1.
Definition: InitStages.h:72
Initialization of network-layer protocols, stage 2.
Definition: InitStages.h:78
Definition: IPProtocolId_m.h:87
Definition: NodeStatus.h:40
virtual int inet::ICMPv6::numInitStages ( ) const
inlineoverrideprotectedvirtual
80 { return NUM_INIT_STAGES; }
The number of initialization stages.
Definition: InitStages.h:116
void inet::ICMPv6::processEchoReply ( ICMPv6EchoReplyMsg reply)
protectedvirtual

Forward the ping reply to the "pingOut" of this module.

Referenced by processICMPv6Message().

158 {
159  IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo *>(reply->removeControlInfo());
160  PingPayload *payload = check_and_cast<PingPayload *>(reply->decapsulate());
161  payload->setControlInfo(ctrl);
162  delete reply;
163  long originatorId = payload->getOriginatorId();
164  auto i = pingMap.find(originatorId);
165  if (i != pingMap.end())
166  send(payload, "pingOut", i->second);
167  else {
168  EV_WARN << "Received ECHO REPLY has an unknown originator ID: " << originatorId << ", packet dropped." << endl;
169  delete payload;
170  }
171 }
PingMap pingMap
Definition: ICMPv6.h:116
void inet::ICMPv6::processEchoRequest ( ICMPv6EchoRequestMsg request)
protectedvirtual

Respond to the machine that tried to ping us.

Referenced by processICMPv6Message().

128 {
129  //Create an ICMPv6 Reply Message
130  ICMPv6EchoReplyMsg *reply = new ICMPv6EchoReplyMsg("Echo Reply");
131  reply->setName((std::string(request->getName()) + "-reply").c_str());
132  reply->setType(ICMPv6_ECHO_REPLY);
133  reply->encapsulate(request->decapsulate());
134 
135  IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo *>(request->getControlInfo());
136  IPv6ControlInfo *replyCtrl = new IPv6ControlInfo();
137  replyCtrl->setProtocol(IP_PROT_IPv6_ICMP);
138  replyCtrl->setDestAddr(ctrl->getSrcAddr());
139 
140  if (ctrl->getDestAddr().isMulticast() /*TODO check for anycast too*/) {
141  IInterfaceTable *it = getModuleFromPar<IInterfaceTable>(par("interfaceTableModule"), this);
142  IPv6InterfaceData *ipv6Data = it->getInterfaceById(ctrl->getInterfaceId())->ipv6Data();
143  replyCtrl->setSrcAddr(ipv6Data->getPreferredAddress());
144  // TODO implement default address selection properly.
145  // According to RFC 3484, the source address to be used
146  // depends on the destination address
147  }
148  else
149  replyCtrl->setSrcAddr(ctrl->getDestAddr());
150 
151  reply->setControlInfo(replyCtrl);
152 
153  delete request;
154  sendToIP(reply);
155 }
Definition: ICMPv6Message_m.h:76
virtual void sendToIP(ICMPv6Message *msg, const IPv6Address &dest)
Definition: ICMPv6.cc:256
Definition: IPProtocolId_m.h:87
void inet::ICMPv6::processICMPv6Message ( ICMPv6Message icmpv6msg)
protectedvirtual

Referenced by handleMessage(), and sendErrorMessage().

76 {
77  ASSERT(dynamic_cast<ICMPv6Message *>(icmpv6msg));
78  if (dynamic_cast<ICMPv6DestUnreachableMsg *>(icmpv6msg)) {
79  EV_INFO << "ICMPv6 Destination Unreachable Message Received." << endl;
80  errorOut(icmpv6msg);
81  }
82  else if (dynamic_cast<ICMPv6PacketTooBigMsg *>(icmpv6msg)) {
83  EV_INFO << "ICMPv6 Packet Too Big Message Received." << endl;
84  errorOut(icmpv6msg);
85  }
86  else if (dynamic_cast<ICMPv6TimeExceededMsg *>(icmpv6msg)) {
87  EV_INFO << "ICMPv6 Time Exceeded Message Received." << endl;
88  errorOut(icmpv6msg);
89  }
90  else if (dynamic_cast<ICMPv6ParamProblemMsg *>(icmpv6msg)) {
91  EV_INFO << "ICMPv6 Parameter Problem Message Received." << endl;
92  errorOut(icmpv6msg);
93  }
94  else if (dynamic_cast<ICMPv6EchoRequestMsg *>(icmpv6msg)) {
95  EV_INFO << "ICMPv6 Echo Request Message Received." << endl;
96  processEchoRequest((ICMPv6EchoRequestMsg *)icmpv6msg);
97  }
98  else if (dynamic_cast<ICMPv6EchoReplyMsg *>(icmpv6msg)) {
99  EV_INFO << "ICMPv6 Echo Reply Message Received." << endl;
100  processEchoReply((ICMPv6EchoReplyMsg *)icmpv6msg);
101  }
102  else
103  throw cRuntimeError("Unknown message type received: (%s)%s.\n", icmpv6msg->getClassName(),icmpv6msg->getName());
104 }
virtual void processEchoReply(ICMPv6EchoReplyMsg *)
Forward the ping reply to the "pingOut" of this module.
Definition: ICMPv6.cc:157
virtual void errorOut(ICMPv6Message *)
Definition: ICMPv6.cc:327
virtual void processEchoRequest(ICMPv6EchoRequestMsg *)
Respond to the machine that tried to ping us.
Definition: ICMPv6.cc:127
void inet::ICMPv6::sendEchoRequest ( PingPayload msg)
protectedvirtual

Ping a machine.

The information needed to do this is in the cMessage parameter. TODO where in cMessage? document!!!

Referenced by handleMessage().

174 {
175  cGate *arrivalGate = msg->getArrivalGate();
176  int i = arrivalGate->getIndex();
177  pingMap[msg->getOriginatorId()] = i;
178 
179  IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo *>(msg->removeControlInfo());
180  ctrl->setProtocol(IP_PROT_IPv6_ICMP);
181  ICMPv6EchoRequestMsg *request = new ICMPv6EchoRequestMsg(msg->getName());
182  request->setType(ICMPv6_ECHO_REQUEST);
183  request->encapsulate(msg);
184  request->setControlInfo(ctrl);
185  sendToIP(request);
186 }
PingMap pingMap
Definition: ICMPv6.h:116
Definition: ICMPv6Message_m.h:75
virtual void sendToIP(ICMPv6Message *msg, const IPv6Address &dest)
Definition: ICMPv6.cc:256
Definition: IPProtocolId_m.h:87
void inet::ICMPv6::sendErrorMessage ( IPv6Datagram datagram,
ICMPv6Type  type,
int  code 
)
virtual

This method can be called from other modules to send an ICMPv6 error packet.

RFC 2463, Section 3: ICMPv6 Error Messages There are a total of 4 ICMPv6 error messages as described in the RFC. This method will construct and send error messages corresponding to the given type. Error Types:

  • Destination Unreachable Message - 1
  • Packet Too Big Message - 2
  • Time Exceeded Message - 3
  • Parameter Problem Message - 4 Code Types have different semantics for each error type. See RFC 2463.

Referenced by inet::IPv6FragBuf::addFragment(), inet::IPv6NeighbourDiscovery::dropQueuedPacketsAwaitingAR(), inet::IPv6NeighbourDiscovery::processIPv6Datagram(), inet::UDP::processUndeliverablePacket(), inet::IPv6FragBuf::purgeStaleFragments(), and sendErrorMessage().

189 {
190  Enter_Method("sendErrorMessage(datagram, type=%d, code=%d)", type, code);
191 
192  // get ownership
193  take(origDatagram);
194 
195  if (!validateDatagramPromptingError(origDatagram))
196  return;
197 
198  ICMPv6Message *errorMsg;
199 
200  if (type == ICMPv6_DESTINATION_UNREACHABLE)
201  errorMsg = createDestUnreachableMsg(code);
202  //TODO: implement MTU support.
203  else if (type == ICMPv6_PACKET_TOO_BIG)
204  errorMsg = createPacketTooBigMsg(0);
205  else if (type == ICMPv6_TIME_EXCEEDED)
206  errorMsg = createTimeExceededMsg(code);
207  else if (type == ICMPv6_PARAMETER_PROBLEM)
208  errorMsg = createParamProblemMsg(code);
209  else
210  throw cRuntimeError("Unknown ICMPv6 error type: %d\n", type);
211 
212  // Encapsulate the original datagram, but the whole ICMPv6 error
213  // packet cannot be larger than the minimum IPv6 MTU (RFC 4443 2.4. (c)).
214  // NOTE: since we just overwrite the errorMsg length without actually
215  // truncating origDatagram, one can get "packet length became negative"
216  // error when decapsulating the origDatagram on the receiver side.
217  // A workaround is to avoid decapsulation, or to manually set the
218  // errorMessage length to be larger than the encapsulated message.
219  errorMsg->encapsulate(origDatagram);
220  if (errorMsg->getByteLength() + IPv6_HEADER_BYTES > IPv6_MIN_MTU)
221  errorMsg->setByteLength(IPv6_MIN_MTU - IPv6_HEADER_BYTES);
222 
223  // debugging information
224  EV_DEBUG << "sending ICMP error: (" << errorMsg->getClassName() << ")" << errorMsg->getName()
225  << " type=" << type << " code=" << code << endl;
226 
227  // if srcAddr is not filled in, we're still in the src node, so we just
228  // process the ICMP message locally, right away
229  if (origDatagram->getSrcAddress().isUnspecified()) {
230  // pretend it came from the IP layer
231  IPv6ControlInfo *ctrlInfo = new IPv6ControlInfo();
232  ctrlInfo->setSrcAddr(IPv6Address::LOOPBACK_ADDRESS); // FIXME maybe use configured loopback address
233  ctrlInfo->setProtocol(IP_PROT_ICMP);
234  errorMsg->setControlInfo(ctrlInfo);
235 
236  // then process it locally
237  processICMPv6Message(errorMsg);
238  }
239  else {
240  sendToIP(errorMsg, origDatagram->getSrcAddress());
241  }
242 }
virtual ICMPv6Message * createDestUnreachableMsg(int code)
Definition: ICMPv6.cc:272
static const IPv6Address LOOPBACK_ADDRESS
The loopback address.
Definition: IPv6Address.h:69
Definition: ICMPv6Message_m.h:72
virtual ICMPv6Message * createTimeExceededMsg(int code)
Definition: ICMPv6.cc:289
Definition: ICMPv6Message_m.h:74
virtual bool validateDatagramPromptingError(IPv6Datagram *datagram)
Validate the received IPv6 datagram before responding with error message.
Definition: ICMPv6.cc:306
#define IPv6_MIN_MTU
Definition: IPv6InterfaceData.h:38
Definition: ICMPv6Message_m.h:71
virtual void processICMPv6Message(ICMPv6Message *)
Definition: ICMPv6.cc:75
Definition: IPProtocolId_m.h:77
virtual ICMPv6Message * createParamProblemMsg(int code)
Definition: ICMPv6.cc:297
virtual void sendToIP(ICMPv6Message *msg, const IPv6Address &dest)
Definition: ICMPv6.cc:256
const int IPv6_HEADER_BYTES
Definition: IPv6Datagram_m.h:44
virtual ICMPv6Message * createPacketTooBigMsg(int mtu)
Definition: ICMPv6.cc:280
Definition: ICMPv6Message_m.h:73
void inet::ICMPv6::sendErrorMessage ( cPacket *  transportPacket,
IPv6ControlInfo ctrl,
ICMPv6Type  type,
int  code 
)
virtual

This method can be called from other modules to send an ICMP error packet in response to a received bogus packet from the transport layer (like UDP).

The ICMP error packet needs to include (part of) the original IP datagram, so this function will wrap back the transport packet into the IP datagram based on its IPv4ControlInfo.

245 {
246  Enter_Method("sendErrorMessage(transportPacket, ctrl, type=%d, code=%d)", type, code);
247 
248  IPv6Datagram *datagram = ctrl->removeOrigDatagram();
249  delete ctrl;
250  take(transportPacket);
251  take(datagram);
252  datagram->encapsulate(transportPacket);
253  sendErrorMessage(datagram, type, code);
254 }
virtual void sendErrorMessage(IPv6Datagram *datagram, ICMPv6Type type, int code)
This method can be called from other modules to send an ICMPv6 error packet.
Definition: ICMPv6.cc:188
void inet::ICMPv6::sendToIP ( ICMPv6Message msg,
const IPv6Address dest 
)
protectedvirtual

Referenced by processEchoRequest(), sendEchoRequest(), and sendErrorMessage().

257 {
258  IPv6ControlInfo *ctrlInfo = new IPv6ControlInfo();
259  ctrlInfo->setDestAddr(dest);
260  ctrlInfo->setProtocol(IP_PROT_IPv6_ICMP);
261  msg->setControlInfo(ctrlInfo);
262 
263  send(msg, "ipv6Out");
264 }
Definition: IPProtocolId_m.h:87
void inet::ICMPv6::sendToIP ( ICMPv6Message msg)
protectedvirtual
267 {
268  // assumes IPv6ControlInfo is already attached
269  send(msg, "ipv6Out");
270 }
bool inet::ICMPv6::validateDatagramPromptingError ( IPv6Datagram datagram)
protectedvirtual

Validate the received IPv6 datagram before responding with error message.

Referenced by sendErrorMessage().

307 {
308  // don't send ICMP error messages for multicast messages
309  if (origDatagram->getDestAddress().isMulticast()) {
310  EV_INFO << "won't send ICMP error messages for multicast message " << origDatagram << endl;
311  delete origDatagram;
312  return false;
313  }
314 
315  // do not reply with error message to error message
316  if (origDatagram->getTransportProtocol() == IP_PROT_IPv6_ICMP) {
317  ICMPv6Message *recICMPMsg = check_and_cast<ICMPv6Message *>(origDatagram->getEncapsulatedPacket());
318  if (recICMPMsg->getType() < 128) {
319  EV_INFO << "ICMP error received -- do not reply to it" << endl;
320  delete origDatagram;
321  return false;
322  }
323  }
324  return true;
325 }
Definition: IPProtocolId_m.h:87

Member Data Documentation

PingMap inet::ICMPv6::pingMap
protected

The documentation for this class was generated from the following files: