diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5f13e5551..eff6dcf45 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -29,6 +29,7 @@ New user-visible features Bugs fixed ---------- - bug 1566 - WiFi SNR tag improvements +- Bug 1582 - IPv6 raw socket return value is not like Linux socket Known issues ------------ diff --git a/src/internet/model/ipv6-raw-socket-impl.cc b/src/internet/model/ipv6-raw-socket-impl.cc index 4e3f9be39..d5597ecb7 100644 --- a/src/internet/model/ipv6-raw-socket-impl.cc +++ b/src/internet/model/ipv6-raw-socket-impl.cc @@ -245,6 +245,8 @@ int Ipv6RawSocketImpl::SendTo (Ptr p, uint32_t flags, const Address& toA } ipv6->Send (p, route->GetSource (), dst, m_protocol, route); + // Return only payload size (as Linux does). + return p->GetSize () - hdr.GetSerializedSize (); } else { @@ -273,7 +275,7 @@ Ptr Ipv6RawSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, Addre /* get packet */ struct Data data = m_data.front (); m_data.pop_front (); - + fromAddress = Inet6SocketAddress (data.fromIp, data.fromProtocol); if (data.packet->GetSize () > maxSize) { Ptr first = data.packet->CreateFragment (0, maxSize); @@ -285,7 +287,6 @@ Ptr Ipv6RawSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, Addre return first; } - fromAddress = Inet6SocketAddress (data.fromIp, data.fromProtocol); return data.packet; } diff --git a/src/internet/test/ipv6-raw-test.cc b/src/internet/test/ipv6-raw-test.cc new file mode 100644 index 000000000..74483b1f1 --- /dev/null +++ b/src/internet/test/ipv6-raw-test.cc @@ -0,0 +1,275 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 Hajime Tazaki + * + * 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: Hajime Tazaki + */ +/** + * This is the test code for ipv6-raw-socket-impl.cc. + */ + +#include "ns3/test.h" +#include "ns3/socket-factory.h" +#include "ns3/ipv6-raw-socket-factory.h" +#include "ns3/simulator.h" +#include "ns3/simple-channel.h" +#include "ns3/simple-net-device.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/socket.h" + +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/inet6-socket-address.h" +#include "ns3/boolean.h" +#include "ns3/uinteger.h" + +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/icmpv6-l4-protocol.h" +#include "ns3/ipv6-list-routing.h" +#include "ns3/ipv6-static-routing.h" + +#include +#include +#include +#include +#include + +using namespace ns3; + +static void +AddInternetStack (Ptr node) +{ + Ptr ipv6 = CreateObject (); + Ptr icmpv6 = CreateObject (); + node->AggregateObject (ipv6); + node->AggregateObject (icmpv6); + ipv6->Insert (icmpv6); + icmpv6->SetAttribute ("DAD", BooleanValue (false)); + + //Routing for Ipv6 + Ptr ipv6Routing = CreateObject (); + ipv6->SetRoutingProtocol (ipv6Routing); + Ptr ipv6staticRouting = CreateObject (); ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0); + /* register IPv6 extensions and options */ + ipv6->RegisterExtensions (); ipv6->RegisterOptions (); +} + + +class Ipv6RawSocketImplTest : public TestCase +{ + Ptr m_receivedPacket; + Ptr m_receivedPacket2; + void DoSendData (Ptr socket, std::string to); + void SendData (Ptr socket, std::string to); + +public: + virtual void DoRun (void); + Ipv6RawSocketImplTest (); + + void ReceivePacket (Ptr socket, Ptr packet, const Address &from); + void ReceivePacket2 (Ptr socket, Ptr packet, const Address &from); + void ReceivePkt (Ptr socket); + void ReceivePkt2 (Ptr socket); +}; + + +Ipv6RawSocketImplTest::Ipv6RawSocketImplTest () + : TestCase ("Ipv6 Raw socket implementation") +{ +} + +void Ipv6RawSocketImplTest::ReceivePacket (Ptr socket, Ptr packet, const Address &from) +{ + m_receivedPacket = packet; +} + +void Ipv6RawSocketImplTest::ReceivePacket2 (Ptr socket, Ptr packet, const Address &from) +{ + m_receivedPacket2 = packet; +} + +void Ipv6RawSocketImplTest::ReceivePkt (Ptr socket) +{ + uint32_t availableData; + availableData = socket->GetRxAvailable (); + m_receivedPacket = socket->Recv (2, MSG_PEEK); + NS_ASSERT (m_receivedPacket->GetSize () == 2); + m_receivedPacket = socket->Recv (std::numeric_limits::max (), 0); + NS_ASSERT (availableData == m_receivedPacket->GetSize ()); +} + +void Ipv6RawSocketImplTest::ReceivePkt2 (Ptr socket) +{ + uint32_t availableData; + Address addr; + availableData = socket->GetRxAvailable (); + m_receivedPacket2 = socket->Recv (2, MSG_PEEK); + NS_ASSERT (m_receivedPacket2->GetSize () == 2); + m_receivedPacket2 = socket->RecvFrom (std::numeric_limits::max (), 0, addr); + NS_ASSERT (availableData == m_receivedPacket2->GetSize ()); + Inet6SocketAddress v6addr = Inet6SocketAddress::ConvertFrom (addr); + NS_TEST_EXPECT_MSG_EQ (v6addr.GetIpv6 (),Ipv6Address ("fe80:0000:0000:0000:0200:00ff:fe00:0003"), "recvfrom"); +} + +void +Ipv6RawSocketImplTest::DoSendData (Ptr socket, std::string to) +{ + Address realTo = Inet6SocketAddress (Ipv6Address (to.c_str ()), 0); + NS_TEST_EXPECT_MSG_EQ (socket->SendTo (Create (123), 0, realTo), + 123, to); +} + +void +Ipv6RawSocketImplTest::SendData (Ptr socket, std::string to) +{ + m_receivedPacket = Create (); + m_receivedPacket2 = Create (); + Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), + &Ipv6RawSocketImplTest::DoSendData, this, socket, to); + Simulator::Run (); +} + +void +Ipv6RawSocketImplTest::DoRun (void) +{ + // Create topology + + // Receiver Node + Ptr rxNode = CreateObject (); + AddInternetStack (rxNode); + Ptr rxDev1, rxDev2; + { // first interface + rxDev1 = CreateObject (); + rxDev1->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + rxNode->AddDevice (rxDev1); + Ptr ipv6 = rxNode->GetObject (); + uint32_t netdev_idx = ipv6->AddInterface (rxDev1); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:db8:0::1"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + { // second interface + rxDev2 = CreateObject (); + rxDev2->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + rxNode->AddDevice (rxDev2); + Ptr ipv6 = rxNode->GetObject (); + uint32_t netdev_idx = ipv6->AddInterface (rxDev2); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:db8:1::1"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // Sender Node + Ptr txNode = CreateObject (); + AddInternetStack (txNode); + Ptr txDev1; + { + txDev1 = CreateObject (); + txDev1->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + txNode->AddDevice (txDev1); + Ptr ipv6 = txNode->GetObject (); + uint32_t netdev_idx = ipv6->AddInterface (txDev1); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:db8:0::2"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + Ptr txDev2; + { + txDev2 = CreateObject (); + txDev2->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + txNode->AddDevice (txDev2); + Ptr ipv6 = txNode->GetObject (); + uint32_t netdev_idx = ipv6->AddInterface (txDev2); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:db8:1::2"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // link the two nodes + Ptr channel1 = CreateObject (); + rxDev1->SetChannel (channel1); + txDev1->SetChannel (channel1); + + Ptr channel2 = CreateObject (); + rxDev2->SetChannel (channel2); + txDev2->SetChannel (channel2); + + + // Create the Ipv6 Raw sockets + Ptr rxSocketFactory = rxNode->GetObject (); + Ptr rxSocket = rxSocketFactory->CreateSocket (); + NS_TEST_EXPECT_MSG_EQ (rxSocket->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 0)), 0, "trivial"); + rxSocket->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6)); + rxSocket->SetRecvCallback (MakeCallback (&Ipv6RawSocketImplTest::ReceivePkt, this)); + + Ptr rxSocket2 = rxSocketFactory->CreateSocket (); + rxSocket2->SetRecvCallback (MakeCallback (&Ipv6RawSocketImplTest::ReceivePkt2, this)); + rxSocket2->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6)); + NS_TEST_EXPECT_MSG_EQ (rxSocket2->Bind (Inet6SocketAddress (Ipv6Address ("2001:db8:1::1"), 0)), 0, "trivial"); + + Ptr txSocketFactory = txNode->GetObject (); + Ptr txSocket = txSocketFactory->CreateSocket (); + txSocket->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6)); + + // ------ Now the tests ------------ + + // Unicast test + SendData (txSocket, "2001:db8:0::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 163, "recv: 2001:db8:0::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket2->GetSize (), 0, "second interface should not receive it"); + + m_receivedPacket->RemoveAllByteTags (); + m_receivedPacket2->RemoveAllByteTags (); + + // Simple Link-local multicast test + txSocket->Bind (Inet6SocketAddress (Ipv6Address ("2001:db8:0::2"), 0)); + SendData (txSocket, "ff02::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 163, "recv: ff02::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket2->GetSize (), 0, "second socket should not receive it (it is bound specifically to the second interface's address"); + + m_receivedPacket->RemoveAllByteTags (); + m_receivedPacket2->RemoveAllByteTags (); + + // Broadcast test with multiple receiving sockets + + // When receiving broadcast packets, all sockets sockets bound to + // the address/port should receive a copy of the same packet -- if + // the socket address matches. + rxSocket2->Dispose (); + rxSocket2 = rxSocketFactory->CreateSocket (); + rxSocket2->SetRecvCallback (MakeCallback (&Ipv6RawSocketImplTest::ReceivePkt2, this)); + rxSocket2->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6)); + NS_TEST_EXPECT_MSG_EQ (rxSocket2->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 0)), 0, "trivial"); + + SendData (txSocket, "ff02::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 163, "recv: ff02::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket2->GetSize (), 163, "recv: ff02::1"); + + m_receivedPacket = 0; + m_receivedPacket2 = 0; + + Simulator::Destroy (); +} +//----------------------------------------------------------------------------- +class Ipv6RawTestSuite : public TestSuite +{ +public: + Ipv6RawTestSuite () : TestSuite ("ipv6-raw", UNIT) + { + AddTestCase (new Ipv6RawSocketImplTest); + } +} g_ipv6rawTestSuite; diff --git a/src/internet/wscript b/src/internet/wscript index 62bb4fd05..ea90beeb5 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -202,6 +202,7 @@ def build(bld): 'test/ipv6-list-routing-test-suite.cc', 'test/ipv6-packet-info-tag-test-suite.cc', 'test/ipv6-test.cc', + 'test/ipv6-raw-test.cc', 'test/tcp-test.cc', 'test/udp-test.cc', 'test/ipv6-address-generator-test-suite.cc',