Files
ns-3-dev/src/internet-stack/icmpv4-l4-protocol.cc
T

254 lines
6.8 KiB
C++

#include "icmpv4-l4-protocol.h"
#include "ipv4-raw-socket-factory-impl.h"
#include "ipv4-interface.h"
#include "ipv4-l3-protocol.h"
#include "ns3/assert.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/boolean.h"
#include "ns3/ipv4-route.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("Icmpv4L4Protocol");
NS_OBJECT_ENSURE_REGISTERED (Icmpv4L4Protocol);
// see rfc 792
const uint8_t Icmpv4L4Protocol::PROT_NUMBER = 1;
TypeId
Icmpv4L4Protocol::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Icmpv4L4Protocol")
.SetParent<Ipv4L4Protocol> ()
.AddConstructor<Icmpv4L4Protocol> ()
;
return tid;
}
Icmpv4L4Protocol::Icmpv4L4Protocol ()
: m_node (0)
{}
Icmpv4L4Protocol::~Icmpv4L4Protocol ()
{
NS_ASSERT (m_node == 0);
}
void
Icmpv4L4Protocol::SetNode (Ptr<Node> node)
{
m_node = node;
}
/*
* This method is called by AddAgregate and completes the aggregation
* by setting the node in the ICMP stack and adding ICMP factory to
* IPv4 stack connected to the node
*/
void
Icmpv4L4Protocol::NotifyNewAggregate ()
{
if (m_node == 0)
{
Ptr<Node> node = this->GetObject<Node> ();
if (node != 0)
{
Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
if (ipv4 != 0)
{
this->SetNode (node);
ipv4->Insert (this);
Ptr<Ipv4RawSocketFactoryImpl> rawFactory = CreateObject<Ipv4RawSocketFactoryImpl> ();
ipv4->AggregateObject (rawFactory);
}
}
}
Object::NotifyNewAggregate ();
}
uint16_t
Icmpv4L4Protocol::GetStaticProtocolNumber (void)
{
return PROT_NUMBER;
}
int
Icmpv4L4Protocol::GetProtocolNumber (void) const
{
return PROT_NUMBER;
}
void
Icmpv4L4Protocol::SendMessage (Ptr<Packet> packet, Ipv4Address dest, uint8_t type, uint8_t code)
{
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
NS_ASSERT (ipv4 != 0 && ipv4->GetRoutingProtocol () != 0);
Ipv4Header header;
header.SetDestination (dest);
Socket::SocketErrno errno_;
Ptr<Ipv4Route> route;
uint32_t oif = 0; //specify non-zero if bound to a source address
route = ipv4->GetRoutingProtocol ()->RouteOutput (packet, header, oif, errno_);
if (route != 0)
{
NS_LOG_LOGIC ("Route exists");
Ipv4Address source = route->GetSource ();
SendMessage (packet, source, dest, type, code, route);
}
else
{
NS_LOG_WARN ("drop icmp message");
}
}
void
Icmpv4L4Protocol::SendMessage (Ptr<Packet> packet, Ipv4Address source, Ipv4Address dest, uint8_t type, uint8_t code, Ptr<Ipv4Route> route)
{
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
Icmpv4Header icmp;
icmp.SetType (type);
icmp.SetCode (code);
if (Node::ChecksumEnabled ())
{
icmp.EnableChecksum ();
}
packet->AddHeader (icmp);
ipv4->Send (packet, source, dest, PROT_NUMBER, route);
}
void
Icmpv4L4Protocol::SendDestUnreachFragNeeded (Ipv4Header header,
Ptr<const Packet> orgData,
uint16_t nextHopMtu)
{
NS_LOG_FUNCTION (this << header << *orgData << nextHopMtu);
SendDestUnreach (header, orgData, Icmpv4DestinationUnreachable::FRAG_NEEDED, nextHopMtu);
}
void
Icmpv4L4Protocol::SendDestUnreachPort (Ipv4Header header,
Ptr<const Packet> orgData)
{
NS_LOG_FUNCTION (this << header << *orgData);
SendDestUnreach (header, orgData, Icmpv4DestinationUnreachable::PORT_UNREACHABLE, 0);
}
void
Icmpv4L4Protocol::SendDestUnreach (Ipv4Header header, Ptr<const Packet> orgData,
uint8_t code, uint16_t nextHopMtu)
{
NS_LOG_FUNCTION (this << header << *orgData << (uint32_t) code << nextHopMtu);
Ptr<Packet> p = Create<Packet> ();
Icmpv4DestinationUnreachable unreach;
unreach.SetNextHopMtu (nextHopMtu);
unreach.SetHeader (header);
unreach.SetData (orgData);
p->AddHeader (unreach);
SendMessage (p, header.GetSource (), Icmpv4Header::DEST_UNREACH, code);
}
void
Icmpv4L4Protocol::SendTimeExceededTtl (Ipv4Header header, Ptr<const Packet> orgData)
{
NS_LOG_FUNCTION (this << header << *orgData);
Ptr<Packet> p = Create<Packet> ();
Icmpv4TimeExceeded time;
time.SetHeader (header);
time.SetData (orgData);
p->AddHeader (time);
SendMessage (p, header.GetSource (), Icmpv4Header::TIME_EXCEEDED, Icmpv4TimeExceeded::TIME_TO_LIVE);
}
void
Icmpv4L4Protocol::HandleEcho (Ptr<Packet> p,
Icmpv4Header header,
Ipv4Address source,
Ipv4Address destination)
{
NS_LOG_FUNCTION (this << p << header << source << destination);
Ptr<Packet> reply = Create<Packet> ();
Icmpv4Echo echo;
p->RemoveHeader (echo);
reply->AddHeader (echo);
SendMessage (reply, destination, source, Icmpv4Header::ECHO_REPLY, 0, 0);
}
void
Icmpv4L4Protocol::Forward (Ipv4Address source, Icmpv4Header icmp,
uint32_t info, Ipv4Header ipHeader,
const uint8_t payload[8])
{
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
Ptr<Ipv4L4Protocol> l4 = ipv4->GetProtocol (ipHeader.GetProtocol ());
if (l4 != 0)
{
l4->ReceiveIcmp (source, ipHeader.GetTtl (), icmp.GetType (), icmp.GetCode (),
info, ipHeader.GetSource (), ipHeader.GetDestination (), payload);
}
}
void
Icmpv4L4Protocol::HandleDestUnreach (Ptr<Packet> p,
Icmpv4Header icmp,
Ipv4Address source,
Ipv4Address destination)
{
NS_LOG_FUNCTION (this << p << icmp << source << destination);
Icmpv4DestinationUnreachable unreach;
p->PeekHeader (unreach);
uint8_t payload[8];
unreach.GetData (payload);
Ipv4Header ipHeader = unreach.GetHeader ();
Forward (source, icmp, unreach.GetNextHopMtu (), ipHeader, payload);
}
void
Icmpv4L4Protocol::HandleTimeExceeded (Ptr<Packet> p,
Icmpv4Header icmp,
Ipv4Address source,
Ipv4Address destination)
{
NS_LOG_FUNCTION (this << p << icmp << source << destination);
Icmpv4TimeExceeded time;
p->PeekHeader (time);
uint8_t payload[8];
time.GetData (payload);
Ipv4Header ipHeader = time.GetHeader ();
// info field is zero for TimeExceeded on linux
Forward (source, icmp, 0, ipHeader, payload);
}
enum Ipv4L4Protocol::RxStatus
Icmpv4L4Protocol::Receive(Ptr<Packet> p,
Ipv4Address const &source,
Ipv4Address const &destination,
Ptr<Ipv4Interface> incomingInterface)
{
NS_LOG_FUNCTION (this << p << source << destination << incomingInterface);
Icmpv4Header icmp;
p->RemoveHeader (icmp);
switch (icmp.GetType ()) {
case Icmpv4Header::ECHO:
HandleEcho (p, icmp, source, destination);
break;
case Icmpv4Header::DEST_UNREACH:
HandleDestUnreach (p, icmp, source, destination);
break;
case Icmpv4Header::TIME_EXCEEDED:
HandleTimeExceeded (p, icmp, source, destination);
break;
default:
NS_LOG_DEBUG (icmp << " " << *p);
break;
}
return Ipv4L4Protocol::RX_OK;
}
void
Icmpv4L4Protocol::DoDispose (void)
{
NS_LOG_FUNCTION (this);
m_node = 0;
Ipv4L4Protocol::DoDispose ();
}
} // namespace ns3