338 lines
8.3 KiB
C++
338 lines
8.3 KiB
C++
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2007-2009 Strasbourg University
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
|
|
*/
|
|
|
|
#include "ns3/inet6-socket-address.h"
|
|
#include "ns3/node.h"
|
|
#include "ns3/packet.h"
|
|
#include "ns3/uinteger.h"
|
|
#include "ns3/log.h"
|
|
#include "ns3/ipv6-route.h"
|
|
#include "ns3/ipv6-routing-protocol.h"
|
|
|
|
#include "ipv6-l3-protocol.h"
|
|
#include "ipv6-raw-socket-impl.h"
|
|
#include "icmpv6-header.h"
|
|
#include "icmpv6-l4-protocol.h"
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE ("Ipv6RawSocketImpl");
|
|
|
|
|
|
NS_OBJECT_ENSURE_REGISTERED (Ipv6RawSocketImpl);
|
|
|
|
TypeId Ipv6RawSocketImpl::GetTypeId ()
|
|
{
|
|
static TypeId tid = TypeId ("ns3::Ipv6RawSocketImpl")
|
|
.SetParent<Socket> ()
|
|
.AddAttribute ("Protocol", "Protocol number to match.",
|
|
UintegerValue (0),
|
|
MakeUintegerAccessor (&Ipv6RawSocketImpl::m_protocol),
|
|
MakeUintegerChecker<uint16_t> ())
|
|
.AddAttribute ("IcmpFilter", "Any ICMPv6 header whose type field matches a bit in this filter is dropped.",
|
|
UintegerValue (0),
|
|
MakeUintegerAccessor (&Ipv6RawSocketImpl::m_icmpFilter),
|
|
MakeUintegerChecker<uint32_t> ())
|
|
;
|
|
return tid;
|
|
}
|
|
|
|
Ipv6RawSocketImpl::Ipv6RawSocketImpl ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_err = Socket::ERROR_NOTERROR;
|
|
m_node = 0;
|
|
m_src = Ipv6Address::GetAny ();
|
|
m_dst = Ipv6Address::GetAny ();
|
|
m_protocol = 0;
|
|
m_shutdownSend = false;
|
|
m_shutdownRecv = false;
|
|
}
|
|
|
|
Ipv6RawSocketImpl::~Ipv6RawSocketImpl ()
|
|
{
|
|
}
|
|
|
|
void Ipv6RawSocketImpl::DoDispose ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_node = 0;
|
|
Socket::DoDispose ();
|
|
}
|
|
|
|
void Ipv6RawSocketImpl::SetNode (Ptr<Node> node)
|
|
{
|
|
NS_LOG_FUNCTION (this << node);
|
|
m_node = node;
|
|
}
|
|
|
|
Ptr<Node> Ipv6RawSocketImpl::GetNode () const
|
|
{
|
|
return m_node;
|
|
}
|
|
|
|
enum Socket::SocketErrno Ipv6RawSocketImpl::GetErrno () const
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
return m_err;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Bind (const Address& address)
|
|
{
|
|
NS_LOG_FUNCTION (this << address);
|
|
|
|
if (!Inet6SocketAddress::IsMatchingType (address))
|
|
{
|
|
m_err = Socket::ERROR_INVAL;
|
|
return -1;
|
|
}
|
|
Inet6SocketAddress ad = Inet6SocketAddress::ConvertFrom (address);
|
|
m_src = ad.GetIpv6 ();
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Bind ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_src = Ipv6Address::GetAny ();
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::GetSockName (Address& address) const
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
address = Inet6SocketAddress (m_src, 0);
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Close ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
|
|
|
|
if (ipv6)
|
|
{
|
|
ipv6->DeleteRawSocket (this);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::ShutdownSend ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_shutdownSend = true;
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::ShutdownRecv ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_shutdownRecv = true;
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Connect (const Address& address)
|
|
{
|
|
NS_LOG_FUNCTION (this << address);
|
|
|
|
if (!Inet6SocketAddress::IsMatchingType (address))
|
|
{
|
|
m_err = Socket::ERROR_INVAL;
|
|
return -1;
|
|
}
|
|
|
|
Inet6SocketAddress ad = Inet6SocketAddress::ConvertFrom (address);
|
|
m_dst = ad.GetIpv6 ();
|
|
return 0;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Listen ()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
m_err = Socket::ERROR_OPNOTSUPP;
|
|
return -1;
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::Send (Ptr<Packet> p, uint32_t flags)
|
|
{
|
|
NS_LOG_FUNCTION (this << p << flags);
|
|
Inet6SocketAddress to = Inet6SocketAddress (m_dst, m_protocol);
|
|
return SendTo (p, flags, to);
|
|
}
|
|
|
|
int Ipv6RawSocketImpl::SendTo (Ptr<Packet> p, uint32_t flags, const Address& toAddress)
|
|
{
|
|
NS_LOG_FUNCTION (this << p << flags << toAddress);
|
|
|
|
if (!Inet6SocketAddress::IsMatchingType (toAddress))
|
|
{
|
|
m_err = Socket::ERROR_INVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (m_shutdownSend)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Inet6SocketAddress ad = Inet6SocketAddress::ConvertFrom (toAddress);
|
|
Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
|
|
Ipv6Address dst = ad.GetIpv6 ();
|
|
|
|
if (ipv6->GetRoutingProtocol ())
|
|
{
|
|
Ipv6Header hdr;
|
|
hdr.SetDestinationAddress (dst);
|
|
SocketErrno err = ERROR_NOTERROR;
|
|
Ptr<Ipv6Route> route = 0;
|
|
Ptr<NetDevice> oif (0); /*specify non-zero if bound to a source address */
|
|
|
|
if (!m_src.IsAny ())
|
|
{
|
|
int32_t index = ipv6->GetInterfaceForAddress (m_src);
|
|
NS_ASSERT (index >= 0);
|
|
oif = ipv6->GetNetDevice (index);
|
|
}
|
|
|
|
route = ipv6->GetRoutingProtocol ()->RouteOutput (p, hdr, oif, err);
|
|
|
|
if (route)
|
|
{
|
|
NS_LOG_LOGIC ("Route exists");
|
|
if (m_protocol == Icmpv6L4Protocol::GetStaticProtocolNumber ())
|
|
{
|
|
/* calculate checksum here for ICMPv6 echo request (sent by ping6)
|
|
* as we cannot determine source IPv6 address at application level
|
|
*/
|
|
if (*p->PeekData () == Icmpv6Header::ICMPV6_ECHO_REQUEST)
|
|
{
|
|
Icmpv6Echo hdr (1);
|
|
p->RemoveHeader (hdr);
|
|
hdr.CalculatePseudoHeaderChecksum (route->GetSource (), dst, p->GetSize () + hdr.GetSerializedSize (), Icmpv6L4Protocol::GetStaticProtocolNumber ());
|
|
p->AddHeader (hdr);
|
|
}
|
|
}
|
|
|
|
ipv6->Send (p, route->GetSource (), dst, m_protocol, route);
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_DEBUG ("No route, dropped!");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Ptr<Packet> Ipv6RawSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
|
|
{
|
|
NS_LOG_FUNCTION (this << maxSize << flags);
|
|
Address tmp;
|
|
return RecvFrom (maxSize, flags, tmp);
|
|
}
|
|
|
|
Ptr<Packet> Ipv6RawSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, Address& fromAddress)
|
|
{
|
|
NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
|
|
|
|
if (m_data.empty ())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* get packet */
|
|
struct Data data = m_data.front ();
|
|
m_data.pop_front ();
|
|
|
|
if (data.packet->GetSize () > maxSize)
|
|
{
|
|
Ptr<Packet> first = data.packet->CreateFragment (0, maxSize);
|
|
data.packet->RemoveAtStart (maxSize);
|
|
m_data.push_front (data);
|
|
return first;
|
|
}
|
|
|
|
fromAddress = Inet6SocketAddress (data.fromIp, data.fromProtocol);
|
|
return data.packet;
|
|
}
|
|
|
|
uint32_t Ipv6RawSocketImpl::GetTxAvailable () const
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
return 0xffffffff;
|
|
}
|
|
|
|
uint32_t Ipv6RawSocketImpl::GetRxAvailable () const
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS ();
|
|
uint32_t rx = 0;
|
|
|
|
for (std::list<Data>::const_iterator it = m_data.begin () ; it != m_data.end () ; ++it)
|
|
{
|
|
rx+= (it->packet)->GetSize ();
|
|
}
|
|
|
|
return rx;
|
|
}
|
|
|
|
bool Ipv6RawSocketImpl::ForwardUp (Ptr<const Packet> p, Ipv6Header hdr, Ptr<NetDevice> device)
|
|
{
|
|
NS_LOG_FUNCTION (this << *p << hdr << device);
|
|
|
|
if (m_shutdownRecv)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ((m_src == Ipv6Address::GetAny () || hdr.GetDestinationAddress () == m_src) &&
|
|
(m_dst == Ipv6Address::GetAny () || hdr.GetSourceAddress () == m_dst) &&
|
|
hdr.GetNextHeader () == m_protocol)
|
|
{
|
|
Ptr<Packet> copy = p->Copy ();
|
|
|
|
if (m_protocol == Icmpv6L4Protocol::GetStaticProtocolNumber ())
|
|
{
|
|
/* filter */
|
|
Icmpv6Header icmpHeader;
|
|
copy->PeekHeader (icmpHeader);
|
|
uint8_t type = icmpHeader.GetType ();
|
|
|
|
if ((1 << type) & m_icmpFilter)
|
|
{
|
|
/* packet filtered */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
copy->AddHeader (hdr);
|
|
struct Data data;
|
|
data.packet = copy;
|
|
data.fromIp = hdr.GetSourceAddress ();
|
|
data.fromProtocol = hdr.GetNextHeader ();
|
|
m_data.push_back (data);
|
|
NotifyDataRecv ();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} /* namespace ns3 */
|
|
|