Bug 932 - Support IP_HDRINCL option for Ipv4RawSocket
authorHajime Tazaki <tazaki@sfc.wide.ad.jp>
Fri, 04 Jun 2010 07:09:30 +0900
changeset 6334 c9373f264dfe
parent 6333 c461f7a25895
child 6335 069840de4fac
Bug 932 - Support IP_HDRINCL option for Ipv4RawSocket
src/internet-stack/ipv4-l3-protocol.cc
src/internet-stack/ipv4-l3-protocol.h
src/internet-stack/ipv4-raw-socket-impl.cc
src/internet-stack/ipv4-raw-socket-impl.h
src/internet-stack/ipv4-raw-test.cc
--- a/src/internet-stack/ipv4-l3-protocol.cc	Fri Jun 04 07:05:22 2010 +0900
+++ b/src/internet-stack/ipv4-l3-protocol.cc	Fri Jun 04 07:09:30 2010 +0900
@@ -520,6 +520,17 @@
 
 void 
 Ipv4L3Protocol::Send (Ptr<Packet> packet, 
+                      Ipv4Header ipHeader,
+                      Ptr<Ipv4Route> route)
+{
+  NS_LOG_FUNCTION (this << packet << ipHeader << route);
+  Ipv4Header hdr;
+  packet->RemoveHeader (hdr);
+  SendRealOut (route, packet, hdr);
+}
+
+void 
+Ipv4L3Protocol::Send (Ptr<Packet> packet, 
             Ipv4Address source, 
             Ipv4Address destination,
             uint8_t protocol,
--- a/src/internet-stack/ipv4-l3-protocol.h	Fri Jun 04 07:05:22 2010 +0900
+++ b/src/internet-stack/ipv4-l3-protocol.h	Fri Jun 04 07:09:30 2010 +0900
@@ -162,6 +162,15 @@
    */
   void Send (Ptr<Packet> packet, Ipv4Address source, 
 	     Ipv4Address destination, uint8_t protocol, Ptr<Ipv4Route> 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> packet, Ipv4Header ipHeader, Ptr<Ipv4Route> route);
 
   uint32_t AddInterface (Ptr<NetDevice> device);
   Ptr<Ipv4Interface> GetInterface (uint32_t i) const;
--- a/src/internet-stack/ipv4-raw-socket-impl.cc	Fri Jun 04 07:05:22 2010 +0900
+++ b/src/internet-stack/ipv4-raw-socket-impl.cc	Fri Jun 04 07:09:30 2010 +0900
@@ -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 @@
 		   UintegerValue (0),
 		   MakeUintegerAccessor (&Ipv4RawSocketImpl::m_icmpFilter),
 		   MakeUintegerChecker<uint32_t> ())
+    // 
+    //  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 @@
   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<Ipv4Route> route;
       Ptr<NetDevice> oif = m_boundnetdevice; //specify non-zero if bound to a source address
@@ -192,7 +214,14 @@
       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();
--- a/src/internet-stack/ipv4-raw-socket-impl.h	Fri Jun 04 07:05:22 2010 +0900
+++ b/src/internet-stack/ipv4-raw-socket-impl.h	Fri Jun 04 07:09:30 2010 +0900
@@ -59,6 +59,7 @@
   bool m_shutdownSend;
   bool m_shutdownRecv;
   uint32_t m_icmpFilter;
+  bool m_iphdrincl;
 };
 
 } // namespace ns3
--- a/src/internet-stack/ipv4-raw-test.cc	Fri Jun 04 07:05:22 2010 +0900
+++ b/src/internet-stack/ipv4-raw-test.cc	Fri Jun 04 07:09:30 2010 +0900
@@ -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 @@
   Ptr<Packet> m_receivedPacket2;
   void DoSendData (Ptr<Socket> socket, std::string to);
   void SendData (Ptr<Socket> socket, std::string to);
+  void DoSendData_IpHdr (Ptr<Socket> socket, std::string to);
+  void SendData_IpHdr (Ptr<Socket> socket, std::string to);
 
 public:
   virtual bool DoRun (void);
@@ -139,6 +142,35 @@
   Simulator::Run ();
 }
 
+void
+Ipv4RawSocketImplTest::DoSendData_IpHdr (Ptr<Socket> socket, std::string to)
+{
+  Address realTo = InetSocketAddress (Ipv4Address(to.c_str()), 0);
+  socket->SetAttribute ("IpHeaderInclude", BooleanValue (true));
+  Ptr<Packet> p = Create<Packet> (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> socket, std::string to)
+{
+  m_receivedPacket = Create<Packet> ();
+  m_receivedPacket2 = Create<Packet> ();
+  Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0),
+                                  &Ipv4RawSocketImplTest::DoSendData_IpHdr, this, socket, to);
+  Simulator::Run ();
+}
+
 bool
 Ipv4RawSocketImplTest::DoRun (void)
 {
@@ -229,6 +261,14 @@
   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