diff --git a/src/internet-stack/ipv4-l3-protocol.cc b/src/internet-stack/ipv4-l3-protocol.cc index 2d20b2123..6891bd1fb 100644 --- a/src/internet-stack/ipv4-l3-protocol.cc +++ b/src/internet-stack/ipv4-l3-protocol.cc @@ -518,6 +518,17 @@ Ipv4L3Protocol::IsUnicast (Ipv4Address ad, Ipv4Mask interfaceMask) const return !ad.IsMulticast () && !ad.IsSubnetDirectedBroadcast (interfaceMask); } +void +Ipv4L3Protocol::Send (Ptr packet, + Ipv4Header ipHeader, + Ptr route) +{ + NS_LOG_FUNCTION (this << packet << ipHeader << route); + Ipv4Header hdr; + packet->RemoveHeader (hdr); + SendRealOut (route, packet, hdr); +} + void Ipv4L3Protocol::Send (Ptr packet, Ipv4Address source, diff --git a/src/internet-stack/ipv4-l3-protocol.h b/src/internet-stack/ipv4-l3-protocol.h index def314481..e6650543e 100644 --- a/src/internet-stack/ipv4-l3-protocol.h +++ b/src/internet-stack/ipv4-l3-protocol.h @@ -162,6 +162,15 @@ public: */ void Send (Ptr packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol, Ptr route); + /** + * \param packet packet to send + * \param ipHeader IP Heeader + * \param route route entry + * + * Higher-level layers call this method to send a packet with IPv4 Header + * (Intend to be used with IpHeaderInclude attribute.) + */ + void Send (Ptr packet, Ipv4Header ipHeader, Ptr route); uint32_t AddInterface (Ptr device); Ptr GetInterface (uint32_t i) const; diff --git a/src/internet-stack/ipv4-raw-socket-impl.cc b/src/internet-stack/ipv4-raw-socket-impl.cc index 53b647045..d70520b89 100644 --- a/src/internet-stack/ipv4-raw-socket-impl.cc +++ b/src/internet-stack/ipv4-raw-socket-impl.cc @@ -6,6 +6,7 @@ #include "ns3/node.h" #include "ns3/packet.h" #include "ns3/uinteger.h" +#include "ns3/boolean.h" #include "ns3/log.h" NS_LOG_COMPONENT_DEFINE ("Ipv4RawSocketImpl"); @@ -28,6 +29,19 @@ Ipv4RawSocketImpl::GetTypeId (void) UintegerValue (0), MakeUintegerAccessor (&Ipv4RawSocketImpl::m_icmpFilter), MakeUintegerChecker ()) + // + // from raw (7), linux, returned length of Send/Recv should be + // + // | IP_HDRINC on | off | + // ----------+---------------+-------------+- + // Send(Ipv4)| hdr + payload | payload | + // Recv(Ipv4)| hdr + payload | hdr+payload | + // ----------+---------------+-------------+- + .AddAttribute ("IpHeaderInclude", + "Include IP Header information (a.k.a setsockopt (IP_HDRINCL)).", + BooleanValue (false), + MakeBooleanAccessor (&Ipv4RawSocketImpl::m_iphdrincl), + MakeBooleanChecker ()) ; return tid; } @@ -174,8 +188,16 @@ Ipv4RawSocketImpl::SendTo (Ptr p, uint32_t flags, if (ipv4->GetRoutingProtocol ()) { Ipv4Header header; - header.SetDestination (dst); - header.SetProtocol (m_protocol); + if (!m_iphdrincl) + { + header.SetDestination (dst); + header.SetProtocol (m_protocol); + } + else + { + p->PeekHeader (header); + dst = header.GetDestination (); + } SocketErrno errno_ = ERROR_NOTERROR;//do not use errno as it is the standard C last error number Ptr route; Ptr oif = m_boundnetdevice; //specify non-zero if bound to a source address @@ -192,7 +214,14 @@ Ipv4RawSocketImpl::SendTo (Ptr p, uint32_t flags, if (route != 0) { NS_LOG_LOGIC ("Route exists"); - ipv4->Send (p, route->GetSource (), dst, m_protocol, route); + if (!m_iphdrincl) + { + ipv4->Send (p, route->GetSource (), dst, m_protocol, route); + } + else + { + ipv4->Send (p, header, route); + } NotifyDataSent (p->GetSize ()); NotifySend (GetTxAvailable ()); return p->GetSize(); diff --git a/src/internet-stack/ipv4-raw-socket-impl.h b/src/internet-stack/ipv4-raw-socket-impl.h index 7d3784604..783af8c49 100644 --- a/src/internet-stack/ipv4-raw-socket-impl.h +++ b/src/internet-stack/ipv4-raw-socket-impl.h @@ -59,6 +59,7 @@ private: bool m_shutdownSend; bool m_shutdownRecv; uint32_t m_icmpFilter; + bool m_iphdrincl; }; } // namespace ns3 diff --git a/src/internet-stack/ipv4-raw-test.cc b/src/internet-stack/ipv4-raw-test.cc index f485098b4..07b8e6615 100644 --- a/src/internet-stack/ipv4-raw-test.cc +++ b/src/internet-stack/ipv4-raw-test.cc @@ -33,6 +33,7 @@ #include "ns3/log.h" #include "ns3/node.h" #include "ns3/inet-socket-address.h" +#include "ns3/boolean.h" #include "arp-l3-protocol.h" #include "ipv4-l3-protocol.h" @@ -74,6 +75,8 @@ class Ipv4RawSocketImplTest: public TestCase Ptr m_receivedPacket2; void DoSendData (Ptr socket, std::string to); void SendData (Ptr socket, std::string to); + void DoSendData_IpHdr (Ptr socket, std::string to); + void SendData_IpHdr (Ptr socket, std::string to); public: virtual bool DoRun (void); @@ -139,6 +142,35 @@ Ipv4RawSocketImplTest::SendData (Ptr socket, std::string to) Simulator::Run (); } +void +Ipv4RawSocketImplTest::DoSendData_IpHdr (Ptr socket, std::string to) +{ + Address realTo = InetSocketAddress (Ipv4Address(to.c_str()), 0); + socket->SetAttribute ("IpHeaderInclude", BooleanValue (true)); + Ptr p = Create (123); + Ipv4Header ipHeader; + ipHeader.SetSource (Ipv4Address ("10.0.0.2")); + ipHeader.SetDestination (Ipv4Address (to.c_str ())); + ipHeader.SetProtocol (0); + ipHeader.SetPayloadSize (p->GetSize ()); + ipHeader.SetTtl (255); + p->AddHeader (ipHeader); + + NS_TEST_EXPECT_MSG_EQ (socket->SendTo (p, 0, realTo), + 143, to); + socket->SetAttribute ("IpHeaderInclude", BooleanValue (false)); +} + +void +Ipv4RawSocketImplTest::SendData_IpHdr (Ptr socket, std::string to) +{ + m_receivedPacket = Create (); + m_receivedPacket2 = Create (); + Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), + &Ipv4RawSocketImplTest::DoSendData_IpHdr, this, socket, to); + Simulator::Run (); +} + bool Ipv4RawSocketImplTest::DoRun (void) { @@ -229,6 +261,14 @@ Ipv4RawSocketImplTest::DoRun (void) m_receivedPacket->RemoveAllByteTags (); m_receivedPacket2->RemoveAllByteTags (); + // Unicast w/ header test + SendData_IpHdr (txSocket, "10.0.0.1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 143, "recv(hdrincl): 10.0.0.1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket2->GetSize (), 0, "second interface should not receive it"); + + m_receivedPacket->RemoveAllByteTags (); + m_receivedPacket2->RemoveAllByteTags (); + #if 0 // Simple broadcast test