/* -*- 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 */ #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 () .AddAttribute ("Protocol", "Protocol number to match.", UintegerValue (0), MakeUintegerAccessor (&Ipv6RawSocketImpl::m_protocol), MakeUintegerChecker ()) .AddAttribute ("IcmpFilter", "Any ICMPv6 header whose type field matches a bit in this filter is dropped.", UintegerValue (0), MakeUintegerAccessor (&Ipv6RawSocketImpl::m_icmpFilter), MakeUintegerChecker ()) ; 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) { NS_LOG_FUNCTION (this << node); m_node = node; } Ptr 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 ipv6 = m_node->GetObject (); 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 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 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 ipv6 = m_node->GetObject (); Ipv6Address dst = ad.GetIpv6 (); if (ipv6->GetRoutingProtocol ()) { Ipv6Header hdr; hdr.SetDestinationAddress (dst); SocketErrno err = ERROR_NOTERROR; Ptr route = 0; Ptr 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 Ipv6RawSocketImpl::Recv (uint32_t maxSize, uint32_t flags) { NS_LOG_FUNCTION (this << maxSize << flags); Address tmp; return RecvFrom (maxSize, flags, tmp); } Ptr 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 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::const_iterator it = m_data.begin () ; it != m_data.end () ; ++it) { rx+= (it->packet)->GetSize (); } return rx; } bool Ipv6RawSocketImpl::ForwardUp (Ptr p, Ipv6Header hdr, Ptr 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 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 */