00001 #include "icmpv4-l4-protocol.h"
00002 #include "ipv4-interface.h"
00003 #include "ipv4-l3-protocol.h"
00004 #include "ns3/assert.h"
00005 #include "ns3/log.h"
00006 #include "ns3/node.h"
00007 #include "ns3/packet.h"
00008 #include "ns3/boolean.h"
00009
00010 namespace ns3 {
00011
00012 NS_LOG_COMPONENT_DEFINE ("Icmpv4L4Protocol");
00013
00014 NS_OBJECT_ENSURE_REGISTERED (Icmpv4L4Protocol);
00015
00016
00017 enum {
00018 ICMP_PROTOCOL = 1
00019 };
00020
00021 TypeId
00022 Icmpv4L4Protocol::GetTypeId (void)
00023 {
00024 static TypeId tid = TypeId ("ns3::Icmpv4L4Protocol")
00025 .SetParent<Ipv4L4Protocol> ()
00026 .AddConstructor<Icmpv4L4Protocol> ()
00027 .AddAttribute ("CalcChecksum",
00028 "Control whether the icmp header checksum is calculated and stored in outgoing icmpv4 headers",
00029 BooleanValue (false),
00030 MakeBooleanAccessor (&Icmpv4L4Protocol::m_calcChecksum),
00031 MakeBooleanChecker ())
00032 ;
00033 return tid;
00034 }
00035
00036 Icmpv4L4Protocol::Icmpv4L4Protocol ()
00037 : m_node (0)
00038 {}
00039 Icmpv4L4Protocol::~Icmpv4L4Protocol ()
00040 {
00041 NS_ASSERT (m_node == 0);
00042 }
00043
00044 void
00045 Icmpv4L4Protocol::SetNode (Ptr<Node> node)
00046 {
00047 m_node = node;
00048 }
00049
00050 uint16_t
00051 Icmpv4L4Protocol::GetStaticProtocolNumber (void)
00052 {
00053 return ICMP_PROTOCOL;
00054 }
00055
00056 int
00057 Icmpv4L4Protocol::GetProtocolNumber (void) const
00058 {
00059 return ICMP_PROTOCOL;
00060 }
00061 void
00062 Icmpv4L4Protocol::SendMessage (Ptr<Packet> packet, Ipv4Address dest, uint8_t type, uint8_t code)
00063 {
00064 Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
00065 uint32_t i;
00066 if (!ipv4->GetIfIndexForDestination (dest, i))
00067 {
00068 NS_LOG_WARN ("drop icmp message");
00069 return;
00070 }
00071 Ipv4Address source = ipv4->GetAddress (i);
00072 SendMessage (packet, source, dest, type, code);
00073 }
00074
00075 void
00076 Icmpv4L4Protocol::SendMessage (Ptr<Packet> packet, Ipv4Address source, Ipv4Address dest, uint8_t type, uint8_t code)
00077 {
00078 Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
00079 Icmpv4Header icmp;
00080 icmp.SetType (type);
00081 icmp.SetCode (code);
00082 if (m_calcChecksum)
00083 {
00084 icmp.EnableChecksum ();
00085 }
00086 packet->AddHeader (icmp);
00087 ipv4->Send (packet, source, dest, ICMP_PROTOCOL);
00088 }
00089 void
00090 Icmpv4L4Protocol::SendDestUnreachFragNeeded (Ipv4Header header,
00091 Ptr<const Packet> orgData,
00092 uint16_t nextHopMtu)
00093 {
00094 NS_LOG_FUNCTION (this << header << *orgData << nextHopMtu);
00095 SendDestUnreach (header, orgData, Icmpv4DestinationUnreachable::FRAG_NEEDED, nextHopMtu);
00096 }
00097 void
00098 Icmpv4L4Protocol::SendDestUnreachPort (Ipv4Header header,
00099 Ptr<const Packet> orgData)
00100 {
00101 NS_LOG_FUNCTION (this << header << *orgData);
00102 SendDestUnreach (header, orgData, Icmpv4DestinationUnreachable::PORT_UNREACHABLE, 0);
00103 }
00104 void
00105 Icmpv4L4Protocol::SendDestUnreach (Ipv4Header header, Ptr<const Packet> orgData,
00106 uint8_t code, uint16_t nextHopMtu)
00107 {
00108 NS_LOG_FUNCTION (this << header << *orgData << (uint32_t) code << nextHopMtu);
00109 Ptr<Packet> p = Create<Packet> ();
00110 Icmpv4DestinationUnreachable unreach;
00111 unreach.SetNextHopMtu (nextHopMtu);
00112 unreach.SetHeader (header);
00113 unreach.SetData (orgData);
00114 p->AddHeader (unreach);
00115 SendMessage (p, header.GetSource (), Icmpv4Header::DEST_UNREACH, code);
00116 }
00117
00118 void
00119 Icmpv4L4Protocol::SendTimeExceededTtl (Ipv4Header header, Ptr<const Packet> orgData)
00120 {
00121 NS_LOG_FUNCTION (this << header << *orgData);
00122 Ptr<Packet> p = Create<Packet> ();
00123 Icmpv4TimeExceeded time;
00124 time.SetHeader (header);
00125 time.SetData (orgData);
00126 p->AddHeader (time);
00127 SendMessage (p, header.GetSource (), Icmpv4Header::TIME_EXCEEDED, Icmpv4TimeExceeded::TIME_TO_LIVE);
00128 }
00129
00130 void
00131 Icmpv4L4Protocol::HandleEcho (Ptr<Packet> p,
00132 Icmpv4Header header,
00133 Ipv4Address source,
00134 Ipv4Address destination)
00135 {
00136 NS_LOG_FUNCTION (this << p << header << source << destination);
00137
00138 Ptr<Packet> reply = Create<Packet> ();
00139 Icmpv4Echo echo;
00140 p->RemoveHeader (echo);
00141 reply->AddHeader (echo);
00142 SendMessage (reply, destination, source, Icmpv4Header::ECHO_REPLY, 0);
00143 }
00144 void
00145 Icmpv4L4Protocol::Forward (Ipv4Address source, Icmpv4Header icmp,
00146 uint32_t info, Ipv4Header ipHeader,
00147 const uint8_t payload[8])
00148 {
00149 Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
00150 Ptr<Ipv4L4Protocol> l4 = ipv4->GetProtocol (ipHeader.GetProtocol ());
00151 if (l4 != 0)
00152 {
00153 l4->ReceiveIcmp (source, ipHeader.GetTtl (), icmp.GetType (), icmp.GetCode (),
00154 info, ipHeader.GetSource (), ipHeader.GetDestination (), payload);
00155 }
00156 }
00157 void
00158 Icmpv4L4Protocol::HandleDestUnreach (Ptr<Packet> p,
00159 Icmpv4Header icmp,
00160 Ipv4Address source,
00161 Ipv4Address destination)
00162 {
00163 NS_LOG_FUNCTION (this << p << icmp << source << destination);
00164
00165 Icmpv4DestinationUnreachable unreach;
00166 p->PeekHeader (unreach);
00167 uint8_t payload[8];
00168 unreach.GetData (payload);
00169 Ipv4Header ipHeader = unreach.GetHeader ();
00170 Forward (source, icmp, unreach.GetNextHopMtu (), ipHeader, payload);
00171 }
00172 void
00173 Icmpv4L4Protocol::HandleTimeExceeded (Ptr<Packet> p,
00174 Icmpv4Header icmp,
00175 Ipv4Address source,
00176 Ipv4Address destination)
00177 {
00178 NS_LOG_FUNCTION (this << p << icmp << source << destination);
00179
00180 Icmpv4TimeExceeded time;
00181 p->PeekHeader (time);
00182 uint8_t payload[8];
00183 time.GetData (payload);
00184 Ipv4Header ipHeader = time.GetHeader ();
00185
00186 Forward (source, icmp, 0, ipHeader, payload);
00187 }
00188
00189 enum Ipv4L4Protocol::RxStatus
00190 Icmpv4L4Protocol::Receive(Ptr<Packet> p,
00191 Ipv4Address const &source,
00192 Ipv4Address const &destination,
00193 Ptr<Ipv4Interface> incomingInterface)
00194 {
00195 NS_LOG_FUNCTION (this << p << source << destination << incomingInterface);
00196
00197 Icmpv4Header icmp;
00198 p->RemoveHeader (icmp);
00199 switch (icmp.GetType ()) {
00200 case Icmpv4Header::ECHO:
00201 HandleEcho (p, icmp, source, destination);
00202 break;
00203 case Icmpv4Header::DEST_UNREACH:
00204 HandleDestUnreach (p, icmp, source, destination);
00205 break;
00206 case Icmpv4Header::TIME_EXCEEDED:
00207 HandleTimeExceeded (p, icmp, source, destination);
00208 break;
00209 default:
00210 NS_LOG_DEBUG (icmp << " " << *p);
00211 break;
00212 }
00213 return Ipv4L4Protocol::RX_OK;
00214 }
00215 void
00216 Icmpv4L4Protocol::DoDispose (void)
00217 {
00218 NS_LOG_FUNCTION (this);
00219 m_node = 0;
00220 Ipv4L4Protocol::DoDispose ();
00221 }
00222
00223 }