Bug 2016 - Radvd do not consider the SendAdvert option and don't reply to RS
authorTommaso Pecorella <tommaso.pecorella@unifi.it>
Wed, 19 Nov 2014 00:13:58 +0100
changeset 11062 91a7bee99048
parent 11061 dc318c5a42de
child 11063 3bfdbd13f978
Bug 2016 - Radvd do not consider the SendAdvert option and don't reply to RS
RELEASE_NOTES
examples/ipv6/radvd.cc
src/applications/bindings/modulegen__gcc_ILP32.py
src/applications/bindings/modulegen__gcc_LP64.py
src/applications/model/radvd-interface.cc
src/applications/model/radvd-interface.h
src/applications/model/radvd.cc
src/applications/model/radvd.h
--- a/RELEASE_NOTES	Thu Nov 13 23:34:10 2014 +0100
+++ b/RELEASE_NOTES	Wed Nov 19 00:13:58 2014 +0100
@@ -42,6 +42,7 @@
 - Bug 1991 - PcapFileWrapper::CaptureSize attribute (snaplen) has no effect.
 - Bug 1997 - Fix PlotProbe() documentation and usage for GnuplotHelper and FileHelper
 - Bug 2011 - Default Speed attribute in ConstantSpeedPropagationDelayModel
+- Bug 2016 - Radvd do not consider the SendAdvert option and don't reply to RS
 
 Known issues
 ------------
--- a/examples/ipv6/radvd.cc	Thu Nov 13 23:34:10 2014 +0100
+++ b/examples/ipv6/radvd.cc	Wed Nov 19 00:13:58 2014 +0100
@@ -115,10 +115,15 @@
 
   /* radvd configuration */
   RadvdHelper radvdHelper;
+
   /* R interface (n0 - R) */
-  radvdHelper.AddAnnouncedPrefix(iic1.GetInterfaceIndex (1), Ipv6Address("2001:1::0"), 64);
+  /* n0 will receive unsolicited (periodic) RA */
+  radvdHelper.AddAnnouncedPrefix (iic1.GetInterfaceIndex (1), Ipv6Address("2001:1::0"), 64);
+
   /* R interface (R - n1) */
+  /* n1 will have to use RS, as RA are not sent automatically */
   radvdHelper.AddAnnouncedPrefix(iic2.GetInterfaceIndex (1), Ipv6Address("2001:2::0"), 64);
+  radvdHelper.GetRadvdInterface (iic2.GetInterfaceIndex (1))->SetSendAdvert (false);
 
   ApplicationContainer radvdApps = radvdHelper.Install (r);
   radvdApps.Start (Seconds (1.0));
--- a/src/applications/bindings/modulegen__gcc_ILP32.py	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/bindings/modulegen__gcc_ILP32.py	Wed Nov 19 00:13:58 2014 +0100
@@ -4193,7 +4193,6 @@
     return
 
 def register_Ns3Int64x64_t_methods(root_module, cls):
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_inplace_numeric_operator('+=', param('ns3::int64x64_t const &', u'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('ns3::int64x64_t const &', u'right'))
@@ -4207,6 +4206,7 @@
     cls.add_inplace_numeric_operator('-=', param('ns3::int64x64_t const &', u'right'))
     cls.add_inplace_numeric_operator('/=', param('ns3::int64x64_t const &', u'right'))
     cls.add_output_stream_operator()
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## int64x64-double.h (module 'core'): ns3::int64x64_t::int64x64_t() [constructor]
@@ -5913,7 +5913,6 @@
     return
 
 def register_Ns3Time_methods(root_module, cls):
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_inplace_numeric_operator('+=', param('ns3::Time const &', u'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::Time'], root_module['ns3::Time'], param('int64_t const &', u'right'))
@@ -5924,6 +5923,7 @@
     cls.add_binary_comparison_operator('>')
     cls.add_inplace_numeric_operator('-=', param('ns3::Time const &', u'right'))
     cls.add_output_stream_operator()
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## nstime.h (module 'core'): ns3::Time::Time() [constructor]
@@ -7000,14 +7000,14 @@
     cls.add_constructor([param('ns3::EnumChecker const &', 'arg0')])
     ## enum.h (module 'core'): ns3::EnumChecker::EnumChecker() [constructor]
     cls.add_constructor([])
-    ## enum.h (module 'core'): void ns3::EnumChecker::Add(int v, std::string name) [member function]
+    ## enum.h (module 'core'): void ns3::EnumChecker::Add(int value, std::string name) [member function]
     cls.add_method('Add', 
                    'void', 
-                   [param('int', 'v'), param('std::string', 'name')])
-    ## enum.h (module 'core'): void ns3::EnumChecker::AddDefault(int v, std::string name) [member function]
+                   [param('int', 'value'), param('std::string', 'name')])
+    ## enum.h (module 'core'): void ns3::EnumChecker::AddDefault(int value, std::string name) [member function]
     cls.add_method('AddDefault', 
                    'void', 
-                   [param('int', 'v'), param('std::string', 'name')])
+                   [param('int', 'value'), param('std::string', 'name')])
     ## enum.h (module 'core'): bool ns3::EnumChecker::Check(ns3::AttributeValue const & value) const [member function]
     cls.add_method('Check', 
                    'bool', 
@@ -7045,8 +7045,8 @@
     cls.add_constructor([param('ns3::EnumValue const &', 'arg0')])
     ## enum.h (module 'core'): ns3::EnumValue::EnumValue() [constructor]
     cls.add_constructor([])
-    ## enum.h (module 'core'): ns3::EnumValue::EnumValue(int v) [constructor]
-    cls.add_constructor([param('int', 'v')])
+    ## enum.h (module 'core'): ns3::EnumValue::EnumValue(int value) [constructor]
+    cls.add_constructor([param('int', 'value')])
     ## enum.h (module 'core'): ns3::Ptr<ns3::AttributeValue> ns3::EnumValue::Copy() const [member function]
     cls.add_method('Copy', 
                    'ns3::Ptr< ns3::AttributeValue >', 
@@ -7067,10 +7067,10 @@
                    'std::string', 
                    [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
                    is_const=True, is_virtual=True)
-    ## enum.h (module 'core'): void ns3::EnumValue::Set(int v) [member function]
+    ## enum.h (module 'core'): void ns3::EnumValue::Set(int value) [member function]
     cls.add_method('Set', 
                    'void', 
-                   [param('int', 'v')])
+                   [param('int', 'value')])
     return
 
 def register_Ns3ErlangRandomVariable_methods(root_module, cls):
@@ -9869,8 +9869,14 @@
                    'ns3::TypeId', 
                    [], 
                    is_static=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MAX_INITIAL_RTR_ADVERTISEMENTS [variable]
+    cls.add_static_attribute('MAX_INITIAL_RTR_ADVERTISEMENTS', 'uint32_t const', is_const=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MAX_INITIAL_RTR_ADVERT_INTERVAL [variable]
+    cls.add_static_attribute('MAX_INITIAL_RTR_ADVERT_INTERVAL', 'uint32_t const', is_const=True)
     ## radvd.h (module 'applications'): ns3::Radvd::MAX_RA_DELAY_TIME [variable]
     cls.add_static_attribute('MAX_RA_DELAY_TIME', 'uint32_t const', is_const=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MIN_DELAY_BETWEEN_RAS [variable]
+    cls.add_static_attribute('MIN_DELAY_BETWEEN_RAS', 'uint32_t const', is_const=True)
     ## radvd.h (module 'applications'): void ns3::Radvd::DoDispose() [member function]
     cls.add_method('DoDispose', 
                    'void', 
@@ -9929,6 +9935,10 @@
                    'uint32_t', 
                    [], 
                    is_const=True)
+    ## radvd-interface.h (module 'applications'): ns3::Time ns3::RadvdInterface::GetLastRaTxTime() [member function]
+    cls.add_method('GetLastRaTxTime', 
+                   'ns3::Time', 
+                   [])
     ## radvd-interface.h (module 'applications'): uint32_t ns3::RadvdInterface::GetLinkMtu() const [member function]
     cls.add_method('GetLinkMtu', 
                    'uint32_t', 
@@ -9974,6 +9984,10 @@
                    'bool', 
                    [], 
                    is_const=True)
+    ## radvd-interface.h (module 'applications'): bool ns3::RadvdInterface::IsInitialRtrAdv() [member function]
+    cls.add_method('IsInitialRtrAdv', 
+                   'bool', 
+                   [])
     ## radvd-interface.h (module 'applications'): bool ns3::RadvdInterface::IsIntervalOpt() const [member function]
     cls.add_method('IsIntervalOpt', 
                    'bool', 
@@ -10036,6 +10050,10 @@
     cls.add_method('SetIntervalOpt', 
                    'void', 
                    [param('bool', 'intervalOpt')])
+    ## radvd-interface.h (module 'applications'): void ns3::RadvdInterface::SetLastRaTxTime(ns3::Time now) [member function]
+    cls.add_method('SetLastRaTxTime', 
+                   'void', 
+                   [param('ns3::Time', 'now')])
     ## radvd-interface.h (module 'applications'): void ns3::RadvdInterface::SetLinkMtu(uint32_t linkMtu) [member function]
     cls.add_method('SetLinkMtu', 
                    'void', 
--- a/src/applications/bindings/modulegen__gcc_LP64.py	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/bindings/modulegen__gcc_LP64.py	Wed Nov 19 00:13:58 2014 +0100
@@ -4193,7 +4193,6 @@
     return
 
 def register_Ns3Int64x64_t_methods(root_module, cls):
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_inplace_numeric_operator('+=', param('ns3::int64x64_t const &', u'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('ns3::int64x64_t const &', u'right'))
@@ -4207,6 +4206,7 @@
     cls.add_inplace_numeric_operator('-=', param('ns3::int64x64_t const &', u'right'))
     cls.add_inplace_numeric_operator('/=', param('ns3::int64x64_t const &', u'right'))
     cls.add_output_stream_operator()
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## int64x64-double.h (module 'core'): ns3::int64x64_t::int64x64_t() [constructor]
@@ -5913,7 +5913,6 @@
     return
 
 def register_Ns3Time_methods(root_module, cls):
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_inplace_numeric_operator('+=', param('ns3::Time const &', u'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::Time'], root_module['ns3::Time'], param('int64_t const &', u'right'))
@@ -5924,6 +5923,7 @@
     cls.add_binary_comparison_operator('>')
     cls.add_inplace_numeric_operator('-=', param('ns3::Time const &', u'right'))
     cls.add_output_stream_operator()
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## nstime.h (module 'core'): ns3::Time::Time() [constructor]
@@ -7000,14 +7000,14 @@
     cls.add_constructor([param('ns3::EnumChecker const &', 'arg0')])
     ## enum.h (module 'core'): ns3::EnumChecker::EnumChecker() [constructor]
     cls.add_constructor([])
-    ## enum.h (module 'core'): void ns3::EnumChecker::Add(int v, std::string name) [member function]
+    ## enum.h (module 'core'): void ns3::EnumChecker::Add(int value, std::string name) [member function]
     cls.add_method('Add', 
                    'void', 
-                   [param('int', 'v'), param('std::string', 'name')])
-    ## enum.h (module 'core'): void ns3::EnumChecker::AddDefault(int v, std::string name) [member function]
+                   [param('int', 'value'), param('std::string', 'name')])
+    ## enum.h (module 'core'): void ns3::EnumChecker::AddDefault(int value, std::string name) [member function]
     cls.add_method('AddDefault', 
                    'void', 
-                   [param('int', 'v'), param('std::string', 'name')])
+                   [param('int', 'value'), param('std::string', 'name')])
     ## enum.h (module 'core'): bool ns3::EnumChecker::Check(ns3::AttributeValue const & value) const [member function]
     cls.add_method('Check', 
                    'bool', 
@@ -7045,8 +7045,8 @@
     cls.add_constructor([param('ns3::EnumValue const &', 'arg0')])
     ## enum.h (module 'core'): ns3::EnumValue::EnumValue() [constructor]
     cls.add_constructor([])
-    ## enum.h (module 'core'): ns3::EnumValue::EnumValue(int v) [constructor]
-    cls.add_constructor([param('int', 'v')])
+    ## enum.h (module 'core'): ns3::EnumValue::EnumValue(int value) [constructor]
+    cls.add_constructor([param('int', 'value')])
     ## enum.h (module 'core'): ns3::Ptr<ns3::AttributeValue> ns3::EnumValue::Copy() const [member function]
     cls.add_method('Copy', 
                    'ns3::Ptr< ns3::AttributeValue >', 
@@ -7067,10 +7067,10 @@
                    'std::string', 
                    [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
                    is_const=True, is_virtual=True)
-    ## enum.h (module 'core'): void ns3::EnumValue::Set(int v) [member function]
+    ## enum.h (module 'core'): void ns3::EnumValue::Set(int value) [member function]
     cls.add_method('Set', 
                    'void', 
-                   [param('int', 'v')])
+                   [param('int', 'value')])
     return
 
 def register_Ns3ErlangRandomVariable_methods(root_module, cls):
@@ -9869,8 +9869,14 @@
                    'ns3::TypeId', 
                    [], 
                    is_static=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MAX_INITIAL_RTR_ADVERTISEMENTS [variable]
+    cls.add_static_attribute('MAX_INITIAL_RTR_ADVERTISEMENTS', 'uint32_t const', is_const=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MAX_INITIAL_RTR_ADVERT_INTERVAL [variable]
+    cls.add_static_attribute('MAX_INITIAL_RTR_ADVERT_INTERVAL', 'uint32_t const', is_const=True)
     ## radvd.h (module 'applications'): ns3::Radvd::MAX_RA_DELAY_TIME [variable]
     cls.add_static_attribute('MAX_RA_DELAY_TIME', 'uint32_t const', is_const=True)
+    ## radvd.h (module 'applications'): ns3::Radvd::MIN_DELAY_BETWEEN_RAS [variable]
+    cls.add_static_attribute('MIN_DELAY_BETWEEN_RAS', 'uint32_t const', is_const=True)
     ## radvd.h (module 'applications'): void ns3::Radvd::DoDispose() [member function]
     cls.add_method('DoDispose', 
                    'void', 
@@ -9929,6 +9935,10 @@
                    'uint32_t', 
                    [], 
                    is_const=True)
+    ## radvd-interface.h (module 'applications'): ns3::Time ns3::RadvdInterface::GetLastRaTxTime() [member function]
+    cls.add_method('GetLastRaTxTime', 
+                   'ns3::Time', 
+                   [])
     ## radvd-interface.h (module 'applications'): uint32_t ns3::RadvdInterface::GetLinkMtu() const [member function]
     cls.add_method('GetLinkMtu', 
                    'uint32_t', 
@@ -9974,6 +9984,10 @@
                    'bool', 
                    [], 
                    is_const=True)
+    ## radvd-interface.h (module 'applications'): bool ns3::RadvdInterface::IsInitialRtrAdv() [member function]
+    cls.add_method('IsInitialRtrAdv', 
+                   'bool', 
+                   [])
     ## radvd-interface.h (module 'applications'): bool ns3::RadvdInterface::IsIntervalOpt() const [member function]
     cls.add_method('IsIntervalOpt', 
                    'bool', 
@@ -10036,6 +10050,10 @@
     cls.add_method('SetIntervalOpt', 
                    'void', 
                    [param('bool', 'intervalOpt')])
+    ## radvd-interface.h (module 'applications'): void ns3::RadvdInterface::SetLastRaTxTime(ns3::Time now) [member function]
+    cls.add_method('SetLastRaTxTime', 
+                   'void', 
+                   [param('ns3::Time', 'now')])
     ## radvd-interface.h (module 'applications'): void ns3::RadvdInterface::SetLinkMtu(uint32_t linkMtu) [member function]
     cls.add_method('SetLinkMtu', 
                    'void', 
--- a/src/applications/model/radvd-interface.cc	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/model/radvd-interface.cc	Wed Nov 19 00:13:58 2014 +0100
@@ -50,6 +50,7 @@
   m_homeAgentPreference = 0;
   m_mobRtrSupportFlag = false;
   m_intervalOpt = false;
+  m_initialRtrAdvertisementsLeft = 3;
 }
 
 RadvdInterface::RadvdInterface (uint32_t interface, uint32_t maxRtrAdvInterval, uint32_t minRtrAdvInterval)
@@ -76,6 +77,7 @@
   m_homeAgentPreference = 0;
   m_mobRtrSupportFlag = false;
   m_intervalOpt = false;
+  m_initialRtrAdvertisementsLeft = 3;
 }
 
 RadvdInterface::~RadvdInterface ()
@@ -335,5 +337,25 @@
   NS_LOG_FUNCTION (this << intervalOpt);
   m_intervalOpt = intervalOpt;
 }
+
+Time RadvdInterface::GetLastRaTxTime ()
+{
+  return m_lastSendTime;
+}
+
+void RadvdInterface::SetLastRaTxTime (Time now)
+{
+  m_lastSendTime = now;
+  if (m_initialRtrAdvertisementsLeft)
+    {
+      m_initialRtrAdvertisementsLeft --;
+    }
+}
+
+bool RadvdInterface::IsInitialRtrAdv ()
+{
+  return m_initialRtrAdvertisementsLeft;
+}
+
 } /* namespace ns3 */
 
--- a/src/applications/model/radvd-interface.h	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/model/radvd-interface.h	Wed Nov 19 00:13:58 2014 +0100
@@ -23,6 +23,7 @@
 
 #include <list>
 #include "ns3/simple-ref-count.h"
+#include "ns3/nstime.h"
 #include "radvd-prefix.h"
 
 namespace ns3
@@ -308,6 +309,24 @@
    */
   void SetIntervalOpt (bool intervalOpt);
 
+  /**
+   * \brief Get the last time a RA has been sent.
+   * \returns the last RA send time
+   */
+  Time GetLastRaTxTime ();
+
+  /**
+   * \brief Set the last RA send time. It also decrements the initial Rtr Advertisements counter.
+   * \param the last RA send time
+   */
+  void SetLastRaTxTime (Time now);
+
+  /**
+   * \brief Checks if the interface is subject to the initial Rtr Advertisements rule.
+   * \returns true if the initial Rtr Advertisements counter is greater than zero.
+   */
+  bool IsInitialRtrAdv ();
+
 private:
 
   /**
@@ -418,6 +437,17 @@
    * \brief Flag to add Advertisement Interval option in RA.
    */
   bool m_intervalOpt;
+
+  /**
+   * \brief Last RA send time.
+   */
+  Time m_lastSendTime;
+
+  /**
+   * \brief Number of fast announcement to do
+   */
+  uint8_t m_initialRtrAdvertisementsLeft;
+
 };
 
 } /* namespace ns3 */
--- a/src/applications/model/radvd.cc	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/model/radvd.cc	Wed Nov 19 00:13:58 2014 +0100
@@ -21,6 +21,7 @@
  */
 
 #include "ns3/log.h"
+#include "ns3/abort.h"
 #include "ns3/ipv6-address.h"
 #include "ns3/nstime.h"
 #include "ns3/simulator.h"
@@ -29,7 +30,10 @@
 #include "ns3/uinteger.h"
 #include "ns3/inet6-socket-address.h"
 #include "ns3/ipv6.h"
+#include "ns3/ipv6-l3-protocol.h"
+#include "ns3/ipv6-interface.h"
 #include "ns3/ipv6-raw-socket-factory.h"
+#include "ns3/ipv6-packet-info-tag.h"
 #include "ns3/ipv6-header.h"
 #include "ns3/icmpv6-header.h"
 #include "ns3/string.h"
@@ -71,12 +75,22 @@
       *it = 0;
     }
   m_configurations.clear ();
-  m_socket = 0;
+  m_recvSocket = 0;
 }
 
 void Radvd::DoDispose ()
 {
   NS_LOG_FUNCTION (this);
+
+  m_recvSocket->Close ();
+  m_recvSocket = 0;
+
+  for (SocketMapI it = m_sendSockets.begin (); it != m_sendSockets.end (); ++it)
+    {
+      it->second->Close ();
+      it->second = 0;
+    }
+
   Application::DoDispose ();
 }
 
@@ -84,23 +98,39 @@
 {
   NS_LOG_FUNCTION (this);
 
-  if (!m_socket)
+  TypeId tid = TypeId::LookupByName ("ns3::Ipv6RawSocketFactory");
+
+  if (!m_recvSocket)
     {
-      TypeId tid = TypeId::LookupByName ("ns3::Ipv6RawSocketFactory");
-      m_socket = Socket::CreateSocket (GetNode (), tid);
+      m_recvSocket = Socket::CreateSocket (GetNode (), tid);
 
-      NS_ASSERT (m_socket);
+      NS_ASSERT (m_recvSocket);
 
-      /*    m_socket->Bind (Inet6SocketAddress (m_localAddress, 0)); */
-      /*    m_socket->Connect (Inet6SocketAddress (Ipv6Address::GetAllNodesMulticast (), 0)); */
-      m_socket->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6));
-      m_socket->SetRecvCallback (MakeCallback (&Radvd::HandleRead, this));
+      m_recvSocket->Bind (Inet6SocketAddress (Ipv6Address::GetAllRoutersMulticast (), 0));
+      m_recvSocket->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6));
+      m_recvSocket->SetRecvCallback (MakeCallback (&Radvd::HandleRead, this));
+      m_recvSocket->ShutdownSend ();
+      m_recvSocket->SetRecvPktInfo (true);
     }
 
   for (RadvdInterfaceListCI it = m_configurations.begin (); it != m_configurations.end (); it++)
     {
-      m_eventIds[(*it)->GetInterface ()] = EventId ();
-      ScheduleTransmit (Seconds (0.), (*it), m_eventIds[(*it)->GetInterface ()], Ipv6Address::GetAllNodesMulticast (), true); 
+      if ((*it)->IsSendAdvert ())
+        {
+          m_unsolicitedEventIds[(*it)->GetInterface ()] = Simulator::Schedule (Seconds (0.), &Radvd::Send,
+                                                                               this, (*it), Ipv6Address::GetAllNodesMulticast (), true);
+        }
+
+      if (m_sendSockets.find ((*it)->GetInterface ()) == m_sendSockets.end ())
+        {
+          Ptr<Ipv6L3Protocol> ipv6 = GetNode ()->GetObject<Ipv6L3Protocol> ();
+          Ptr<Ipv6Interface> iFace = ipv6->GetInterface ((*it)->GetInterface ());
+
+          m_sendSockets[(*it)->GetInterface ()] = Socket::CreateSocket (GetNode (), tid);
+          m_sendSockets[(*it)->GetInterface ()]->Bind (Inet6SocketAddress (iFace->GetLinkLocalAddress ().GetAddress (), 0));
+          m_sendSockets[(*it)->GetInterface ()]->SetAttribute ("Protocol", UintegerValue (Ipv6Header::IPV6_ICMPV6));
+          m_sendSockets[(*it)->GetInterface ()]->ShutdownRecv ();
+        }
     }
 }
 
@@ -108,16 +138,22 @@
 {
   NS_LOG_FUNCTION (this);
 
-  if (m_socket)
+  if (m_recvSocket)
     {
-      m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
+      m_recvSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
     }
 
-  for (EventIdMapI it = m_eventIds.begin (); it != m_eventIds.end (); ++it)
+  for (EventIdMapI it = m_unsolicitedEventIds.begin (); it != m_unsolicitedEventIds.end (); ++it)
     {
       Simulator::Cancel ((*it).second);
     }
-  m_eventIds.clear ();
+  m_unsolicitedEventIds.clear ();
+
+  for (EventIdMapI it = m_solicitedEventIds.begin (); it != m_solicitedEventIds.end (); ++it)
+    {
+      Simulator::Cancel ((*it).second);
+    }
+  m_solicitedEventIds.clear ();
 }
 
 void Radvd::AddConfiguration (Ptr<RadvdInterface> routerInterface)
@@ -134,26 +170,20 @@
   return 1;
 }
 
-void Radvd::ScheduleTransmit (Time dt, Ptr<RadvdInterface> config, EventId& eventId, Ipv6Address dst, bool reschedule)
-{
-  NS_LOG_FUNCTION (this << dt << config << &eventId << dst << reschedule);
-  eventId = Simulator::Schedule (dt, &Radvd::Send, this, config, dst, reschedule);
-}
-
 void Radvd::Send (Ptr<RadvdInterface> config, Ipv6Address dst, bool reschedule)
 {
   NS_LOG_FUNCTION (this << dst << reschedule);
-  NS_ASSERT (m_eventIds[config->GetInterface ()].IsExpired ());
+
+  if (reschedule == true)
+    {
+      config->SetLastRaTxTime (Simulator::Now ());
+    }
+
   Icmpv6RA raHdr;
   Icmpv6OptionLinkLayerAddress llaHdr;
   Icmpv6OptionMtu mtuHdr;
   Icmpv6OptionPrefixInformation prefixHdr;
 
-  if (m_eventIds.size () == 0)
-    {
-      return;
-    }
-
   std::list<Ptr<RadvdPrefix> > prefixes = config->GetPrefixes ();
   Ptr<Packet> p = Create<Packet> ();
   Ptr<Ipv6> ipv6 = GetNode ()->GetObject<Ipv6> ();
@@ -212,9 +242,9 @@
       p->AddHeader (prefixHdr);
     }
 
-  Ipv6Address src = ipv6->GetAddress (config->GetInterface (), 0).GetAddress ();
-  m_socket->Bind (Inet6SocketAddress (src, 0));
-  m_socket->Connect (Inet6SocketAddress (dst, 0));
+  Address sockAddr;
+  m_sendSockets[config->GetInterface ()]->GetSockName (sockAddr);
+  Ipv6Address src = Inet6SocketAddress::ConvertFrom (sockAddr).GetIpv6 ();
 
   /* as we know interface index that will be used to send RA and 
    * we always send RA with router's link-local address, we can 
@@ -231,15 +261,21 @@
   p->AddPacketTag (ttl);
 
   /* send RA */
-  NS_LOG_LOGIC ("Send RA");
-  m_socket->Send (p, 0);
+  NS_LOG_LOGIC ("Send RA to " << dst);
+  m_sendSockets[config->GetInterface ()]->SendTo (p, 0, Inet6SocketAddress (dst, 0));
 
   if (reschedule)
     {
       uint64_t delay = static_cast<uint64_t> (m_jitter->GetValue (config->GetMinRtrAdvInterval (), config->GetMaxRtrAdvInterval ()) + 0.5);
+      if (config->IsInitialRtrAdv ())
+        {
+          if (delay > MAX_INITIAL_RTR_ADVERT_INTERVAL)
+            delay = MAX_INITIAL_RTR_ADVERT_INTERVAL;
+        }
+
       NS_LOG_INFO ("Reschedule in " << delay);
       Time t = MilliSeconds (delay);
-      ScheduleTransmit (t, config, m_eventIds[config->GetInterface ()], Ipv6Address::GetAllNodesMulticast (), reschedule);
+      m_unsolicitedEventIds[config->GetInterface ()] = Simulator::Schedule (t, &Radvd::Send, this, config, Ipv6Address::GetAllNodesMulticast (), true);
     }
 }
 
@@ -253,9 +289,18 @@
     {
       if (Inet6SocketAddress::IsMatchingType (from))
         {
+          Ipv6PacketInfoTag interfaceInfo;
+          if (!packet->RemovePacketTag (interfaceInfo))
+            {
+              NS_ABORT_MSG ("No incoming interface on RADVD message, aborting.");
+            }
+          uint32_t incomingIf = interfaceInfo.GetRecvIf ();
+          Ptr<NetDevice> dev = GetNode ()->GetDevice (incomingIf);
+          Ptr<Ipv6> ipv6 = GetNode ()->GetObject<Ipv6> ();
+          uint32_t ipInterfaceIndex = ipv6->GetInterfaceForDevice (dev);
+
           Ipv6Header hdr;
           Icmpv6RS rsHdr;
-          Inet6SocketAddress address = Inet6SocketAddress::ConvertFrom (from);
           uint64_t delay = 0;
           Time t;
 
@@ -269,20 +314,44 @@
               packet->RemoveHeader (rsHdr);
               NS_LOG_INFO ("Received ICMPv6 Router Solicitation from " << hdr.GetSourceAddress () << " code = " << (uint32_t)rsHdr.GetCode ());
 
-              /* XXX advertise just prefix(es) for the interface not all */
               for (RadvdInterfaceListCI it = m_configurations.begin (); it != m_configurations.end (); it++)
                 {
-                  /* calculate minimum delay between RA */
-                  delay = static_cast<uint64_t> (m_jitter->GetValue (0, MAX_RA_DELAY_TIME) + 0.5); 
-                  t = Simulator::Now () + MilliSeconds (delay); /* absolute time of solicited RA */
+                  if (ipInterfaceIndex == (*it)->GetInterface ())
+                    {
+                      /* calculate minimum delay between RA */
+                      delay = static_cast<uint64_t> (m_jitter->GetValue (0, MAX_RA_DELAY_TIME) + 0.5);
+                      t = Simulator::Now () + MilliSeconds (delay); /* absolute time of solicited RA */
+
+                      if (Simulator::Now () < (*it)->GetLastRaTxTime () + MilliSeconds (MIN_DELAY_BETWEEN_RAS) )
+                        {
+                          t += MilliSeconds (MIN_DELAY_BETWEEN_RAS);
+                        }
+
+                      /* if our solicited RA is before the next periodic RA, we schedule it */
+                      bool scheduleSingle = true;
 
-                  /* if our solicited RA is before the next periodic RA, we schedule it */
-                  if (t.GetTimeStep () < static_cast<int64_t> (m_eventIds[(*it)->GetInterface ()].GetTs ()))
-                    {
-                      NS_LOG_INFO ("schedule new RA");
-                      EventId ei;
+                      if (m_solicitedEventIds.find ((*it)->GetInterface ()) != m_solicitedEventIds.end ())
+                        {
+                          if (m_solicitedEventIds[(*it)->GetInterface ()].IsRunning ())
+                            {
+                              scheduleSingle = false;
+                            }
+                        }
 
-                      ScheduleTransmit (MilliSeconds (delay), (*it), ei, address.GetIpv6 (), false);
+                      if (m_unsolicitedEventIds.find ((*it)->GetInterface ()) != m_unsolicitedEventIds.end ())
+                        {
+                          if (t.GetTimeStep () > static_cast<int64_t> (m_unsolicitedEventIds[(*it)->GetInterface ()].GetTs ()))
+                            {
+                              scheduleSingle = false;
+                            }
+                        }
+
+                      if (scheduleSingle)
+                        {
+                          NS_LOG_INFO ("schedule new RA");
+                          m_solicitedEventIds[(*it)->GetInterface ()] = Simulator::Schedule (MilliSeconds (delay), &Radvd::Send,
+                                                                                             this, (*it), Ipv6Address::GetAllNodesMulticast (), false);
+                        }
                     }
                 }
               break;
--- a/src/applications/model/radvd.h	Thu Nov 13 23:34:10 2014 +0100
+++ b/src/applications/model/radvd.h	Wed Nov 19 00:13:58 2014 +0100
@@ -67,6 +67,18 @@
    * \brief Default value for maximum delay of RA (ms)
    */
   static const uint32_t MAX_RA_DELAY_TIME = 500;
+  /**
+   * \brief Default value for maximum initial RA advertisements
+   */
+  static const uint32_t MAX_INITIAL_RTR_ADVERTISEMENTS = 3;
+  /**
+   * \brief Default value for maximum initial RA advertisements interval (ms)
+   */
+  static const uint32_t MAX_INITIAL_RTR_ADVERT_INTERVAL = 16000;
+  /**
+   * \brief Default value for minimum delay between RA advertisements (ms)
+   */
+  static const uint32_t MIN_DELAY_BETWEEN_RAS = 3000;
 
   /**
    * \brief Add configuration for an interface;
@@ -105,6 +117,13 @@
   /// Container Const Iterator: interface number, EventId
   typedef std::map<uint32_t, EventId>::const_iterator EventIdMapCI;
 
+  /// Container: interface number, Socket
+  typedef std::map<uint32_t, Ptr<Socket> > SocketMap;
+  /// Container Iterator: interface number, Socket
+  typedef std::map<uint32_t, Ptr<Socket> >::iterator SocketMapI;
+  /// Container Const Iterator: interface number, Socket
+  typedef std::map<uint32_t, Ptr<Socket> >::const_iterator SocketMapCI;
+
   /**
    * \brief Start the application.
    */
@@ -116,16 +135,6 @@
   virtual void StopApplication ();
 
   /**
-   * \brief Schedule sending a packet.
-   * \param dt interval between packet
-   * \param config interface configuration
-   * \param eventId event ID associated
-   * \param dst IPv6 destination address
-   * \param reschedule if true another send will be reschedule (periodic)
-   */
-  void ScheduleTransmit (Time dt, Ptr<RadvdInterface> config, EventId& eventId, Ipv6Address dst = Ipv6Address::GetAllNodesMulticast (), bool reschedule = false);
-
-  /**
    * \brief Send a packet.
    * \param config interface configuration
    * \param dst destination address (default ff02::1)
@@ -140,9 +149,14 @@
   void HandleRead (Ptr<Socket> socket);
 
   /**
+   * \brief Raw socket to receive RS.
+   */
+  Ptr<Socket> m_recvSocket;
+
+  /**
    * \brief Raw socket to send RA.
    */
-  Ptr<Socket> m_socket;
+  SocketMap m_sendSockets;
 
   /**
    * \brief List of configuration for interface.
@@ -150,9 +164,14 @@
   RadvdInterfaceList m_configurations;
 
   /**
-   * \brief Event ID map.
+   * \brief Event ID map for unsolicited RAs.
    */
-  EventIdMap m_eventIds;
+  EventIdMap m_unsolicitedEventIds;
+
+  /**
+   * \brief Event ID map for solicited RAs.
+   */
+  EventIdMap m_solicitedEventIds;
 
   /**
    * \brief Variable to provide jitter in advertisement interval