diff --git a/src/applications/generic/IPvXTrafGen.cc b/src/applications/generic/IPvXTrafGen.cc index 599711157f4..76b8c78923b 100644 --- a/src/applications/generic/IPvXTrafGen.cc +++ b/src/applications/generic/IPvXTrafGen.cc @@ -24,6 +24,8 @@ #include "IPvXAddressResolver.h" #include "IPv4ControlInfo.h" #include "IPv6ControlInfo.h" +#include "IPv6ExtensionHeaders.h" +#include "IPv4Datagram.h" Define_Module(IPvXTrafGen); @@ -187,6 +189,11 @@ void IPvXTrafGen::sendPacket() IPv4ControlInfo *controlInfo = new IPv4ControlInfo(); controlInfo->setDestAddr(destAddr.get4()); controlInfo->setProtocol(protocol); + if (par("routerAlert").boolValue() == true) + { + controlInfo->setOptions(IPOPTION_ROUTER_ALERT); + } + controlInfo->setOptions(148); payload->setControlInfo(controlInfo); gate = "ipOut"; } @@ -196,6 +203,14 @@ void IPvXTrafGen::sendPacket() IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); controlInfo->setDestAddr(destAddr.get6()); controlInfo->setProtocol(protocol); + if (par("routerAlert").boolValue() == true) + { + // TODO how do we do this extension header handling elegantly? + IPv6HopByHopOptionsHeader *hdr = new IPv6HopByHopOptionsHeader(); + hdr->setOptionsArraySize(1); + hdr->setOptions(0, new IPv6OptionRouterAlert()); + controlInfo->addExtensionHeader(hdr); + } payload->setControlInfo(controlInfo); gate = "ipv6Out"; } diff --git a/src/applications/generic/IPvXTrafGen.ned b/src/applications/generic/IPvXTrafGen.ned index b4e2cea121b..7d92c8f65ba 100644 --- a/src/applications/generic/IPvXTrafGen.ned +++ b/src/applications/generic/IPvXTrafGen.ned @@ -41,6 +41,7 @@ simple IPvXTrafGen like IIPvXTrafficGenerator int protocol; // value for ~IPv4ControlInfo / ~IPv6ControlInfo protocol field volatile int packetLength @unit("B"); // packet length in bytes string destAddresses = default(""); // list of destination addresses, separated by spaces + bool routerAlert = default(false); // set the router alert header option @display("i=block/source"); @signal[sentPk](type=cPacket); @signal[rcvdPk](type=cPacket); diff --git a/src/networklayer/common/IRouterAlertHandler.h b/src/networklayer/common/IRouterAlertHandler.h new file mode 100644 index 00000000000..ef4a566ccc5 --- /dev/null +++ b/src/networklayer/common/IRouterAlertHandler.h @@ -0,0 +1,29 @@ +// +// Copyright (C) 2013 Markus Brueckner +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// + +#ifndef IROUTERALERTHANDLER_H_ +#define IROUTERALERTHANDLER_H_ + +/** + * Base class for all router alert handlers. See the NED file for more + * information. + */ +class IRouterAlertHandler : public cSimpleModule +{ +}; + +#endif /* IROUTERALERTHANDLER_H_ */ diff --git a/src/networklayer/common/IRouterAlertHandler.ned b/src/networklayer/common/IRouterAlertHandler.ned new file mode 100644 index 00000000000..dc0142662a0 --- /dev/null +++ b/src/networklayer/common/IRouterAlertHandler.ned @@ -0,0 +1,35 @@ +// +// Copyright (C) 2013 Markus Brueckner +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// + +package inet.networklayer.common; + +// generic router alert handler interface +// This interface can be sub-classed by modules interested in intercepting +// IPv4 and IPv6 packets with the Router Alert option set. The interface +// offers two gates: one for receiving packets from the network layer (routerAlertIn) +// and one for re-injecting packets into the network layer (routerAlertReturn). +// Packets arriving at routerAlertIn are handed over to the module completely. +// If the packets are to be sent onwards along the normal routing path, they +// have to be re-injected via the routerAlertReturn gate. +moduleinterface IRouterAlertHandler +{ + parameters: + @display("i=block/control_s"); + gates: + input routerAlertIn @labels(IPv4Datagram,IPv6Datagram); + output routerAlertReturn @labels(IPv4Datagram,IPv6Datagram); +} \ No newline at end of file diff --git a/src/networklayer/contract/IPv4ControlInfo.msg b/src/networklayer/contract/IPv4ControlInfo.msg index 69c09fc12ea..a8b21f6240c 100644 --- a/src/networklayer/contract/IPv4ControlInfo.msg +++ b/src/networklayer/contract/IPv4ControlInfo.msg @@ -74,6 +74,7 @@ class IPv4ControlInfo abstract int explicitCongestionNotification; // maps to bits 6-7 of trafficClass short timeToLive; // maximum hop count bool dontFragment; // "don't fragment" bit + int options; // The "options" header field // The following fields are used in the DSR protocol; TODO revise IPv4Address nextHopAddr; // next hop address (DSR) diff --git a/src/networklayer/ipv4/IPv4.cc b/src/networklayer/ipv4/IPv4.cc index c9d9fa80bb9..aec3bb13121 100644 --- a/src/networklayer/ipv4/IPv4.cc +++ b/src/networklayer/ipv4/IPv4.cc @@ -177,6 +177,22 @@ void IPv4::handlePacketFromNetwork(IPv4Datagram *datagram, InterfaceEntry *fromI EV << "Received datagram `" << datagram->getName() << "' with dest=" << destAddr << "\n"; + // handle router alert option field -> This ist handled only on intermediate routers and not on the endpoints + // also the packet is not handled again if it returns from the router alert handler + if ((!datagram->getArrivalGate()->isName("routerAlertReturn")) && !(rt->isLocalAddress(destAddr)) && datagram->getOptionCode() == IPOPTION_ROUTER_ALERT) // FIXME If the option code handling is changed to support multiple options, we have to change this here too + { + // send the datagram to the router alert gate + cGate *rout = gate("routerAlertOut"); + if (rout != 0 && rout->isConnected()) { + send(datagram, rout); + // bail out of the handling. The packet has to be re-injected by the Option handler, when needed + return; // FIXME maybe implement without return? + } + else { + EV << "Router alert option set, but no handler connected. Ignoring.\n"; + } + } + if (fromIE->isLoopback()) { reassembleAndDeliver(datagram); @@ -805,7 +821,9 @@ IPv4Datagram *IPv4::encapsulate(cPacket *transportPacket, IPv4ControlInfo *contr datagram->setTimeToLive(ttl); datagram->setTransportProtocol(controlInfo->getProtocol()); - // setting IPv4 options is currently not supported + if (controlInfo->getOptions() != 0) { + datagram->setOptionCode(controlInfo->getOptions()); // FIXME will only work so long as only one option header is supported + } return datagram; } diff --git a/src/networklayer/ipv4/IPv4.ned b/src/networklayer/ipv4/IPv4.ned index 4b532568bce..8940f0fc7c1 100644 --- a/src/networklayer/ipv4/IPv4.ned +++ b/src/networklayer/ipv4/IPv4.ned @@ -77,7 +77,15 @@ package inet.networklayer.ipv4; // method which determines processing time for a packet, or (2) use a // different base class. // -// @see ~RoutingTable, ~IPv4ControlInfo, ~IPv4RoutingDecision, ~ARP +// Packet interception

+// +// Implementers interested in intercepting packets that pass through the IP layer +// can hook a ~IRouterAlertHandler-like module to the routerAlertOut gate. The +// IP module will then hand over all packets carrying the router alert option field +// to this module for detailled processing. In order to carry on with normal routing, +// packets must be returned using the routerAlertReturn gate. +// +// @see ~RoutingTable, ~IPv4ControlInfo, ~IPv4RoutingDecision, ~ARP, ~IRouterAlertHandler // // @author Andras Varga // @@ -96,4 +104,6 @@ simple IPv4 output transportOut[] @labels(IPv4ControlInfo/up,TCPSegment,UDPPacket); input queueIn[] @labels(IPv4Datagram); output queueOut @labels(IPv4Datagram); + output routerAlertOut @labels(IPv4Datagram); + input routerAlertReturn @labels(IPv4Datagram); } diff --git a/src/networklayer/ipv6/IPv6.cc b/src/networklayer/ipv6/IPv6.cc index 368d7de1a5a..825f23795bf 100644 --- a/src/networklayer/ipv6/IPv6.cc +++ b/src/networklayer/ipv6/IPv6.cc @@ -152,6 +152,32 @@ void IPv6::endService(cPacket *msg) // 2. The Ethernet or PPP frame is dropped by the link-layer if there is a transmission error. ASSERT(!datagram->hasBitError()); + if (!rt->isLocalAddress(datagram->getDestAddress())) + { + // handle router alert options, if set + cGate *rout = gate("routerAlertOut"); + // only check if we have a handler and this datagram wasn't returned from it already + if (rout && rout->isConnected() && !(datagram->arrivedOn("routerAlertReturn"))) + { + for (int i = datagram->getExtensionHeaderArraySize() - 1; i >= 0; --i) + { + // check whether the router alert extension header is set + IPv6ExtensionHeaderPtr extHdr = datagram->getExtensionHeader(i); + if (extHdr->getExtensionType() == IP_PROT_IPv6EXT_HOP) { + // check whether the router alert option is set + IPv6HopByHopOptionsHeader *optHdr = check_and_cast(extHdr); + for (int hi = optHdr->getOptionsArraySize() - 1 ; hi >= 0; --hi) { + if (optHdr->getOptions(hi)->getOptionType() == 5) { // FIXME implement symbolic constant + // we have router alert set -> hand it over to the router alert handler + send(datagram, rout); + return; // TODO break out here without using return? + } + } + } + } + } + } + // remove control info delete datagram->removeControlInfo(); diff --git a/src/networklayer/ipv6/IPv6.ned b/src/networklayer/ipv6/IPv6.ned index 9a4e086248b..c3f5c6a359c 100644 --- a/src/networklayer/ipv6/IPv6.ned +++ b/src/networklayer/ipv6/IPv6.ned @@ -70,7 +70,16 @@ package inet.networklayer.ipv6; // datagrams are processed in order. The processing time is determined by the // procDelay module parameter. // -// @see ~RoutingTable6, ~IPv6ControlInfo, ~IPv6NeighbourDiscovery, ~ICMPv6 +// Packet interception

+// +// Implementers interested in intercepting packets that pass through the IP layer +// can hook a ~IRouterAlertHandler-like module to the routerAlertOut gate. The +// IP module will then hand over all packets carrying the router alert option field +// in the HopByHopExtensionHeader to this module for detailled processing. +// In order to carry on with normal routing, packets must be returned using +// the routerAlertReturn gate. +// +// @see ~RoutingTable6, ~IPv6ControlInfo, ~IPv6NeighbourDiscovery, ~ICMPv6, ~IRouterAlertHandler // // @author Andras Varga // @@ -97,5 +106,8 @@ simple IPv6 //the following gates are added by Zarrar Yousaf on 19.06.07 input xMIPv6In; output xMIPv6Out; + // gates for handling IPv6 Router Alert options + input routerAlertReturn @labels(IPv6Datagram); + output routerAlertOut @labels(IPv6Datagram); } diff --git a/src/networklayer/ipv6/IPv6ExtensionHeaders.cc b/src/networklayer/ipv6/IPv6ExtensionHeaders.cc index 9e8bf186aae..bc1cf470c1a 100644 --- a/src/networklayer/ipv6/IPv6ExtensionHeaders.cc +++ b/src/networklayer/ipv6/IPv6ExtensionHeaders.cc @@ -23,3 +23,42 @@ void IPv6RoutingHeader::setAddressArraySize(unsigned int size) IPv6RoutingHeader_Base::setAddressArraySize(size); byteLength_var = 8 + 16 * size; } + +void IPv6HopByHopOptionsHeader::clean() +{ + // clean away the options + for (int i = getOptionsArraySize()-1; i >= 0; --i) + { + delete getOptions(i); + } +} + +void IPv6HopByHopOptionsHeader::copy(const IPv6HopByHopOptionsHeader& other) +{ + if (getOptionsArraySize() > 0) + { + clean(); + } + setOptionsArraySize(other.getOptionsArraySize()); + for (int i = other.getOptionsArraySize()-1; i >= 0; --i) + { + setOptions(i, other.getOptions(i)->dup()); + } +} + +IPv6HopByHopOptionsHeader::~IPv6HopByHopOptionsHeader() +{ + clean(); +} + +IPv6HopByHopOptionsHeader::IPv6HopByHopOptionsHeader(const IPv6HopByHopOptionsHeader &other) +{ + setOptionsArraySize(0); + copy(other); +} + +IPv6HopByHopOptionsHeader& IPv6HopByHopOptionsHeader::operator=(const IPv6HopByHopOptionsHeader& other) +{ + copy(other); + return *this; +} diff --git a/src/networklayer/ipv6/IPv6ExtensionHeaders.h b/src/networklayer/ipv6/IPv6ExtensionHeaders.h index cbe6d6fe9f3..22fa512ed5d 100644 --- a/src/networklayer/ipv6/IPv6ExtensionHeaders.h +++ b/src/networklayer/ipv6/IPv6ExtensionHeaders.h @@ -32,4 +32,17 @@ class IPv6RoutingHeader : public IPv6RoutingHeader_Base virtual void setAddressArraySize(unsigned int size); }; +class IPv6HopByHopOptionsHeader : public IPv6HopByHopOptionsHeader_Base +{ + private: + void clean(); + void copy(const IPv6HopByHopOptionsHeader& other); + public: + IPv6HopByHopOptionsHeader() : IPv6HopByHopOptionsHeader_Base() {} + ~IPv6HopByHopOptionsHeader(); + IPv6HopByHopOptionsHeader(const IPv6HopByHopOptionsHeader& other); + IPv6HopByHopOptionsHeader& operator=(const IPv6HopByHopOptionsHeader& other); + virtual IPv6HopByHopOptionsHeader *dup() const {return new IPv6HopByHopOptionsHeader(*this);} + // ADD CODE HERE to redefine and implement pure virtual functions from IPv6HopByHopOptionsHeader_Base +}; #endif // __INET_IPV6EXTENSIONHEADERS_H_ diff --git a/src/networklayer/ipv6/IPv6ExtensionHeaders.msg b/src/networklayer/ipv6/IPv6ExtensionHeaders.msg index c1960cc2569..9994188dfaa 100644 --- a/src/networklayer/ipv6/IPv6ExtensionHeaders.msg +++ b/src/networklayer/ipv6/IPv6ExtensionHeaders.msg @@ -23,6 +23,8 @@ cplusplus {{ #include "IPProtocolId_m.h" #define IPv6_FRAGMENT_HEADER_LENGTH 8 +class IPv6Option; +typedef IPv6Option *IPv6OptionPtr; }} @@ -30,6 +32,20 @@ class noncobject IPv6Address; class noncobject IPv6ExtensionHeader; +class noncobject IPv6OptionPtr; + +class IPv6Option +{ + unsigned char optionType; + unsigned char optionLength; +} + +class IPv6OptionRouterAlert extends IPv6Option +{ + optionType = 5; // FIXME use symbolic constant + optionLength = 2; +} + // // Hop-by-Hop Options Header. // RFC 2460 Section 4.3 @@ -37,8 +53,10 @@ class noncobject IPv6ExtensionHeader; // class IPv6HopByHopOptionsHeader extends IPv6ExtensionHeader { + @customize(true); extensionType = IP_PROT_IPv6EXT_HOP; byteLength = 8; // FIXME verify + IPv6OptionPtr options[]; } // diff --git a/src/nodes/inet/NetworkLayer.ned b/src/nodes/inet/NetworkLayer.ned index f327cea40d2..32cdf6da9d4 100644 --- a/src/nodes/inet/NetworkLayer.ned +++ b/src/nodes/inet/NetworkLayer.ned @@ -19,6 +19,7 @@ package inet.nodes.inet; import inet.networklayer.arp.ARP; +import inet.networklayer.common.IRouterAlertHandler; import inet.networklayer.autorouting.ipv4.IPv4NodeConfigurator; import inet.networklayer.ipv4.ErrorHandling; import inet.networklayer.ipv4.ICMP; @@ -37,6 +38,10 @@ module NetworkLayer @display("i=block/fork"); bool proxyARP = default(true); string igmpType = default("IGMPv2"); + // router alert handler type. Put here a string naming the type of router alert handler + // module that you want to use (if any). The network layer will then instantiate and + // connect the respective module automatically. + string routerAlertHandlerType = default(""); gates: input ifIn[] @labels(IPv4Datagram); input tcpIn @labels(TCPSegment,IPv4ControlInfo/down); @@ -57,6 +62,7 @@ module NetworkLayer output manetOut; output igmpOut; + submodules: configurator: IPv4NodeConfigurator { @display("p=39,158"); @@ -89,7 +95,9 @@ module NetworkLayer parameters: @display("p=239,63"); } - + routerAlertHandler: like IRouterAlertHandler if routerAlertHandlerType != "" { + @display("p=294,103"); + } connections allowunconnected: // transport Layer ip.transportOut[0] --> { @display("m=n"); } --> tcpOut; @@ -136,5 +144,10 @@ module NetworkLayer for i=0..sizeof(ifOut)-1 { arp.nicOut[i] --> { @display("m=s"); } --> ifOut[i]; } + + if routerAlertHandlerType != "" { + ip.routerAlertOut --> routerAlertHandler.routerAlertIn; + routerAlertHandler.routerAlertReturn --> ip.routerAlertReturn; + } } diff --git a/src/nodes/ipv6/NetworkLayer6.ned b/src/nodes/ipv6/NetworkLayer6.ned index 8508baeb66a..245ec7cc339 100644 --- a/src/nodes/ipv6/NetworkLayer6.ned +++ b/src/nodes/ipv6/NetworkLayer6.ned @@ -19,13 +19,13 @@ // package inet.nodes.ipv6; -import inet.networklayer.ipv6.IPv6ErrorHandling; -import inet.networklayer.ipv6.IPv6; -import inet.networklayer.icmpv6.IPv6NeighbourDiscovery; -import inet.networklayer.icmpv6.ICMPv6; -import inet.networklayer.IxMIPv6Support; import inet.networklayer.IIPv6Tunneling; -import inet.base.IHook; +import inet.networklayer.IxMIPv6Support; +import inet.networklayer.common.IRouterAlertHandler; +import inet.networklayer.icmpv6.ICMPv6; +import inet.networklayer.icmpv6.IPv6NeighbourDiscovery; +import inet.networklayer.ipv6.IPv6; +import inet.networklayer.ipv6.IPv6ErrorHandling; // @@ -38,6 +38,10 @@ module NetworkLayer6 { parameters: bool xMIPv6Support = default(false); + // router alert handler type. Put here a string naming the type of router alert handler + // module that you want to use (if any). The network layer will then instantiate and + // connect the respective module automatically. + string routerAlertHandlerType = default(""); @display("i=block/fork"); gates: input ifIn[] @labels(IPv6Datagram); @@ -85,6 +89,9 @@ module NetworkLayer6 parameters: @display("p=44,79"); } + routerAlertHandler: like IRouterAlertHandler if routerAlertHandlerType != "" { + @display("p=189,254"); + } connections allowunconnected: // FIXME remove 'nocheck'! // IPv6 to transport Layer ipv6.transportOut[0] --> { @display("m=n"); } --> tcpOut; @@ -138,5 +145,10 @@ module NetworkLayer6 for i=0..sizeof(ifOut)-1 { ipv6.queueOut[i] --> { @display("m=s"); } --> ifOut[i]; } + + if routerAlertHandlerType != "" { + ipv6.routerAlertOut --> routerAlertHandler.routerAlertIn; + routerAlertHandler.routerAlertReturn --> ipv6.routerAlertReturn; + } }