Bug 2234 - Ipv6L3Protocol should trash multicast packets not interesting for the node
authorTommaso Pecorella <tommaso.pecorella@unifi.it>
Thu, 03 Dec 2015 00:35:35 +0100
changeset 11779 710f305a22c9
parent 11778 a745117e5dff
child 11780 9d4878ae6048
Bug 2234 - Ipv6L3Protocol should trash multicast packets not interesting for the node
RELEASE_NOTES
src/internet/model/ipv6-interface.cc
src/internet/model/ipv6-interface.h
src/internet/model/ipv6-l3-protocol.cc
src/internet/model/ipv6-l3-protocol.h
src/internet/model/ipv6-raw-socket-impl.cc
src/internet/model/ipv6-raw-socket-impl.h
src/internet/model/ripng.cc
src/internet/model/udp-socket-impl.cc
src/internet/model/udp-socket-impl.h
src/internet/test/ipv6-ripng-test.cc
src/network/model/socket.cc
src/network/model/socket.h
--- a/RELEASE_NOTES	Wed Dec 02 23:37:23 2015 +0100
+++ b/RELEASE_NOTES	Thu Dec 03 00:35:35 2015 +0100
@@ -44,6 +44,9 @@
   packets directed to the host.
 - (internet) Ipv6 can now reject packets directed to an address not configured on 
   the interface they are received from (Strong End System Model, RFC 1222).
+- (internet) UDP and Ipv6 RAW sockets can now join Ipv6 multicast groups.
+  Incomin packets will be filtered according to if there's a socket listening to
+  that group. Source filtering is left to the application.
 
 Bugs fixed
 ----------
@@ -67,6 +70,7 @@
 - Bug 2211 - Ipv{4,6}EndPoint can cause memory corruption
 - Bug 2219 - SixLowPanNetDevice hangs trying to decode a IPv6 Fragment extension header
 - Bug 2233 - Implement RFC 1222 - Strong End System Model
+- Bug 2234 - Ipv6L3Protocol should trash multicast packets not interesting for the node
 - Bug 2238 - Ipv6 routing reorganization
 
 Known issues
--- a/src/internet/model/ipv6-interface.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-interface.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -94,16 +94,19 @@
         {
           Ipv6InterfaceAddress ifaddr = Ipv6InterfaceAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac64Address::ConvertFrom (addr)), Ipv6Prefix (64));
           AddAddress (ifaddr);
+          m_linkLocalAddress = ifaddr;
         }
       else if (Mac48Address::IsMatchingType (addr))
         {
           Ipv6InterfaceAddress ifaddr = Ipv6InterfaceAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac48Address::ConvertFrom (addr)), Ipv6Prefix (64));
           AddAddress (ifaddr);
+          m_linkLocalAddress = ifaddr;
         }
       else if (Mac16Address::IsMatchingType (addr))
         {
           Ipv6InterfaceAddress ifaddr = Ipv6InterfaceAddress (Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac16Address::ConvertFrom (addr)), Ipv6Prefix (64));
           AddAddress (ifaddr);
+          m_linkLocalAddress = ifaddr;
         }
       else
         {
@@ -213,13 +216,14 @@
     {
       for (Ipv6InterfaceAddressListCI it = m_addresses.begin (); it != m_addresses.end (); ++it)
         {
-          if ((*it).GetAddress () == addr)
+          if (it->first.GetAddress () == addr)
             {
               return false;
             }
         }
 
-      m_addresses.push_back (iface);
+      Ipv6Address solicited = Ipv6Address::MakeSolicitedAddress (iface.GetAddress ());
+      m_addresses.push_back (std::make_pair (iface, solicited));
 
       if (!addr.IsAny () || !addr.IsLocalhost ())
         {
@@ -249,16 +253,23 @@
   /* IPv6 interface has always at least one IPv6 link-local address */
   NS_LOG_FUNCTION_NOARGS ();
 
+  return m_linkLocalAddress;
+}
+
+bool Ipv6Interface::IsSolicitedMulticastAddress (Ipv6Address address) const
+{
+  /* IPv6 interface has always at least one IPv6 Solicited Multicast address */
+  NS_LOG_FUNCTION (this << address);
+
   for (Ipv6InterfaceAddressListCI it = m_addresses.begin (); it != m_addresses.end (); ++it)
-    {
-      if ((*it).GetAddress ().IsLinkLocal ())
-        {
-          return (*it);
-        }
-    }
-  NS_ASSERT_MSG (false, "No link-local address on interface " << this);
-  Ipv6InterfaceAddress addr;
-  return addr; /* quiet compiler */
+     {
+       if (it->second == address)
+         {
+           return true;
+         }
+     }
+
+  return false;
 }
 
 Ipv6InterfaceAddress Ipv6Interface::GetAddress (uint32_t index) const
@@ -272,7 +283,7 @@
         {
           if (i == index)
             {
-              return (*it);
+              return it->first;
             }
           i++;
         }
@@ -303,7 +314,7 @@
     {
       if (i == index)
         {
-          Ipv6InterfaceAddress iface = (*it);
+          Ipv6InterfaceAddress iface = it->first;
           m_addresses.erase (it);
           return iface;
         }
@@ -329,9 +340,9 @@
 
   for (Ipv6InterfaceAddressListI it = m_addresses.begin (); it != m_addresses.end (); ++it)
     {
-      if((*it).GetAddress() == address)
+      if(it->first.GetAddress () == address)
         {
-          Ipv6InterfaceAddress iface = (*it);
+          Ipv6InterfaceAddress iface = it->first;
           m_addresses.erase(it);
           return iface;
         }
@@ -345,7 +356,7 @@
 
   for (Ipv6InterfaceAddressList::const_iterator it = m_addresses.begin (); it != m_addresses.end (); ++it)
     {
-      Ipv6InterfaceAddress ifaddr = (*it);
+      Ipv6InterfaceAddress ifaddr = it->first;
 
       if (ifaddr.GetPrefix ().IsMatch (ifaddr.GetAddress (), dst))
         {
@@ -381,7 +392,7 @@
   /* check if destination is for one of our interface */
   for (Ipv6InterfaceAddressListCI it = m_addresses.begin (); it != m_addresses.end (); ++it)
     {
-      if (dest == (*it).GetAddress ())
+      if (dest == it->first.GetAddress ())
         {
           ipv6->Receive (m_device, p, Ipv6L3Protocol::PROT_NUMBER,
                          m_device->GetBroadcast (),
@@ -483,9 +494,9 @@
 
   for (Ipv6InterfaceAddressListI it = m_addresses.begin (); it != m_addresses.end (); ++it)
     {
-      if ((*it).GetAddress () == address)
+      if (it->first.GetAddress () == address)
         {
-          (*it).SetState (state);
+          it->first.SetState (state);
           return;
         }
     }
@@ -498,9 +509,9 @@
 
   for (Ipv6InterfaceAddressListI it = m_addresses.begin (); it != m_addresses.end (); ++it)
     {
-      if ((*it).GetAddress () == address)
+      if (it->first.GetAddress () == address)
         {
-          (*it).SetNsDadUid (uid);
+          it->first.SetNsDadUid (uid);
           return;
         }
     }
--- a/src/internet/model/ipv6-interface.h	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-interface.h	Thu Dec 03 00:35:35 2015 +0100
@@ -201,6 +201,13 @@
   Ipv6InterfaceAddress GetLinkLocalAddress () const;
 
   /**
+   * \brief Checks if the address is a Solicited Multicast address for this interface.
+   * \param address the address to check.
+   * \return true if it is a solicited multicast address.
+   */
+  bool IsSolicitedMulticastAddress (Ipv6Address address) const;
+
+  /**
    * \brief Get an address from IPv6 interface.
    * \param index index
    * \return Ipv6InterfaceAddress address whose index is i
@@ -266,17 +273,17 @@
   /**
    * \brief Container for the Ipv6InterfaceAddresses.
    */
-  typedef std::list<Ipv6InterfaceAddress> Ipv6InterfaceAddressList;
+  typedef std::list<std::pair<Ipv6InterfaceAddress, Ipv6Address> > Ipv6InterfaceAddressList;
 
   /**
    * \brief Container Iterator for the Ipv6InterfaceAddresses.
    */
-  typedef std::list<Ipv6InterfaceAddress>::iterator Ipv6InterfaceAddressListI;
+  typedef std::list<std::pair<Ipv6InterfaceAddress, Ipv6Address> >::iterator Ipv6InterfaceAddressListI;
 
   /**
    * \brief Const Container Iterator for the Ipv6InterfaceAddresses.
    */
-  typedef std::list<Ipv6InterfaceAddress>::const_iterator Ipv6InterfaceAddressListCI;
+  typedef std::list<std::pair<Ipv6InterfaceAddress, Ipv6Address> >::const_iterator Ipv6InterfaceAddressListCI;
 
   /**
    * \brief Initialize interface.
@@ -289,6 +296,11 @@
   Ipv6InterfaceAddressList m_addresses;
 
   /**
+   * \brief The link-local addresses assigned to this interface.
+   */
+  Ipv6InterfaceAddress m_linkLocalAddress;
+
+  /**
    * \brief The state of this interface.
    */
   bool m_ifup;
--- a/src/internet/model/ipv6-l3-protocol.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-l3-protocol.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -534,7 +534,7 @@
     }
   else
     {
-      NS_LOG_LOGIC ("Interface " << int(i) << " is set to be down for IPv6. Reason: not respecting minimum IPv6 MTU (1280 octects)");
+      NS_LOG_LOGIC ("Interface " << int(i) << " is set to be down for IPv6. Reason: not respecting minimum IPv6 MTU (1280 octets)");
     }
 }
 
@@ -1006,14 +1006,28 @@
         }
     }
 
-  // \todo At the moment, forward up any multicast packet.
-  // This is wrong. We should only forward up what the node is interested into
-  // and try to route anything other than ff01 or ff02.
-  if (hdr.GetDestinationAddress ().IsLinkLocalMulticast ())
+  if (hdr.GetDestinationAddress ().IsAllNodesMulticast ())
+    {
+      LocalDeliver (packet, hdr, interface);
+      return;
+    }
+  else if (hdr.GetDestinationAddress ().IsAllRoutersMulticast() && ipv6Interface->IsForwarding ())
     {
       LocalDeliver (packet, hdr, interface);
       return;
     }
+  else if (hdr.GetDestinationAddress ().IsMulticast ())
+    {
+      bool isSolicited = ipv6Interface->IsSolicitedMulticastAddress (hdr.GetDestinationAddress ());
+      bool isRegisteredOnInterface = IsRegisteredMulticastAddress (hdr.GetDestinationAddress (), interface);
+      bool isRegisteredGlobally = IsRegisteredMulticastAddress (hdr.GetDestinationAddress ());
+      if (isSolicited || isRegisteredGlobally || isRegisteredOnInterface)
+        {
+          LocalDeliver (packet, hdr, interface);
+          // do not return, the packet could be handled by a routing protocol
+        }
+    }
+
 
   for (uint32_t j = 0; j < GetNInterfaces (); j++)
     {
@@ -1494,5 +1508,83 @@
   m_dropTrace (ipHeader, p, dropReason, m_node->GetObject<Ipv6> (), 0);
 }
 
+void Ipv6L3Protocol::AddMulticastAddress (Ipv6Address address, uint32_t interface)
+{
+  NS_LOG_FUNCTION (address << interface);
+
+  if (!address.IsMulticast ())
+    {
+      NS_LOG_WARN ("Not adding a non-multicast address " << address);
+      return;
+    }
+
+  Ipv6RegisteredMulticastAddressKey_t key = std::make_pair (address, interface);
+  m_multicastAddresses[key]++;
+}
+
+void Ipv6L3Protocol::AddMulticastAddress (Ipv6Address address)
+{
+  NS_LOG_FUNCTION (address);
+
+  if (!address.IsMulticast ())
+    {
+      NS_LOG_WARN ("Not adding a non-multicast address " << address);
+      return;
+    }
+
+  m_multicastAddressesNoInterface[address]++;
+}
+
+void Ipv6L3Protocol::RemoveMulticastAddress (Ipv6Address address, uint32_t interface)
+{
+  NS_LOG_FUNCTION (address << interface);
+
+  Ipv6RegisteredMulticastAddressKey_t key = std::make_pair (address, interface);
+
+  m_multicastAddresses[key]--;
+  if (m_multicastAddresses[key] == 0)
+    {
+      m_multicastAddresses.erase (key);
+    }
+}
+
+void Ipv6L3Protocol::RemoveMulticastAddress (Ipv6Address address)
+{
+  NS_LOG_FUNCTION (address);
+
+  m_multicastAddressesNoInterface[address]--;
+  if (m_multicastAddressesNoInterface[address] == 0)
+    {
+      m_multicastAddressesNoInterface.erase (address);
+    }
+}
+
+bool Ipv6L3Protocol::IsRegisteredMulticastAddress (Ipv6Address address, uint32_t interface) const
+{
+  NS_LOG_FUNCTION (address << interface);
+
+  Ipv6RegisteredMulticastAddressKey_t key = std::make_pair (address, interface);
+  Ipv6RegisteredMulticastAddressCIter_t iter = m_multicastAddresses.find (key);
+
+  if (iter == m_multicastAddresses.end ())
+    {
+      return false;
+    }
+  return true;
+}
+
+bool Ipv6L3Protocol::IsRegisteredMulticastAddress (Ipv6Address address) const
+{
+  NS_LOG_FUNCTION (address);
+
+  Ipv6RegisteredMulticastAddressNoInterfaceCIter_t iter = m_multicastAddressesNoInterface.find (address);
+
+  if (iter == m_multicastAddressesNoInterface.end ())
+    {
+      return false;
+    }
+  return true;
+}
+
 } /* namespace ns3 */
 
--- a/src/internet/model/ipv6-l3-protocol.h	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-l3-protocol.h	Thu Dec 03 00:35:35 2015 +0100
@@ -454,7 +454,48 @@
     (const Ipv6Header & header, Ptr<const Packet> packet,
      DropReason reason, Ptr<Ipv6> ipv6,
      uint32_t interface);
-   
+
+  /**
+   * Adds a multicast address to the list of addresses to pass to local deliver.
+   * \param address the address.
+   */
+  void AddMulticastAddress (Ipv6Address address);
+
+  /**
+   * Adds a multicast address to the list of addresses to pass to local deliver.
+   * \param address the address.
+   * \param interface the incoming interface.
+   */
+  void AddMulticastAddress (Ipv6Address address, uint32_t interface);
+
+  /**
+   * Removes a multicast address from the list of addresses to pass to local deliver.
+   * \param address the address.
+   */
+  void RemoveMulticastAddress (Ipv6Address address);
+
+  /**
+   * Removes a multicast address from the list of addresses to pass to local deliver.
+   * \param address the address.
+   * \param interface the incoming interface.
+   */
+  void RemoveMulticastAddress (Ipv6Address address, uint32_t interface);
+
+  /**
+   * Checks if the address has been registered.
+   * \param address the address.
+   * \return true if the address is registered.
+   */
+  bool IsRegisteredMulticastAddress (Ipv6Address address) const;
+
+  /**
+   * Checks if the address has been registered for a specific interface.
+   * \param address the address.
+   * \param interface the incoming interface.
+   * \return true if the address is registered.
+   */
+  bool IsRegisteredMulticastAddress (Ipv6Address address, uint32_t interface) const;
+
 protected:
   /**
    * \brief Dispose object.
@@ -718,6 +759,51 @@
    * \brief Allow ICMPv6 Redirect sending state
    */
   bool m_sendIcmpv6Redirect;
+
+  /**
+   * \brief IPv6 multicast addresses / interface key.
+   */
+  typedef std::pair<Ipv6Address, uint64_t> Ipv6RegisteredMulticastAddressKey_t;
+
+  /**
+   * \brief Container of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6RegisteredMulticastAddressKey_t, uint32_t> Ipv6RegisteredMulticastAddress_t;
+
+  /**
+   * \brief Container Iterator of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6RegisteredMulticastAddressKey_t, uint32_t>::iterator Ipv6RegisteredMulticastAddressIter_t;
+
+  /**
+   * \brief Container Const Iterator of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6RegisteredMulticastAddressKey_t, uint32_t>::const_iterator Ipv6RegisteredMulticastAddressCIter_t;
+
+  /**
+   * \brief Container of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6Address, uint32_t> Ipv6RegisteredMulticastAddressNoInterface_t;
+
+  /**
+   * \brief Container Iterator of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6Address, uint32_t>::iterator Ipv6RegisteredMulticastAddressNoInterfaceIter_t;
+
+  /**
+   * \brief Container Const Iterator of the IPv6 multicast addresses.
+   */
+  typedef std::map<Ipv6Address, uint32_t>::const_iterator Ipv6RegisteredMulticastAddressNoInterfaceCIter_t;
+
+  /**
+   * \brief List of multicast IP addresses of interest, divided per interface.
+   */
+  Ipv6RegisteredMulticastAddress_t m_multicastAddresses;
+
+  /**
+   * \brief List of multicast IP addresses of interest for all the interfaces.
+   */
+  Ipv6RegisteredMulticastAddressNoInterface_t m_multicastAddressesNoInterface;
 };
 
 } /* namespace ns3 */
--- a/src/internet/model/ipv6-raw-socket-impl.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-raw-socket-impl.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -139,6 +139,7 @@
   NS_LOG_FUNCTION_NOARGS ();
   Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
 
+  Ipv6LeaveGroup ();
   if (ipv6)
     {
       ipv6->DeleteRawSocket (this);
@@ -297,6 +298,54 @@
   return data.packet;
 }
 
+void
+Ipv6RawSocketImpl::Ipv6JoinGroup (Ipv6Address address, Socket::Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses)
+{
+  NS_LOG_FUNCTION (this << address << &filterMode << &sourceAddresses);
+
+  // We can join only one multicast group (or change its params)
+  NS_ASSERT_MSG ((m_ipv6MulticastGroupAddress == address || m_ipv6MulticastGroupAddress.IsAny ()), "Can join only one IPv6 multicast group.");
+
+  if (!m_ipv6MulticastGroupAddress.IsAny ())
+    {
+      Ipv6LeaveGroup ();
+    }
+  m_ipv6MulticastGroupAddress = address;
+
+  Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
+  if (ipv6l3)
+    {
+      if (filterMode == INCLUDE && sourceAddresses.empty ())
+        {
+          // it is a leave
+          if (m_boundnetdevice)
+            {
+              int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
+              NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
+              ipv6l3->RemoveMulticastAddress (address, index);
+            }
+          else
+            {
+              ipv6l3->RemoveMulticastAddress (address);
+            }
+        }
+      else
+        {
+          // it is a join or a modification
+          if (m_boundnetdevice)
+            {
+              int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
+              NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
+              ipv6l3->AddMulticastAddress (address, index);
+            }
+          else
+            {
+              ipv6l3->AddMulticastAddress (address);
+            }
+        }
+    }
+}
+
 uint32_t Ipv6RawSocketImpl::GetTxAvailable () const
 {
   NS_LOG_FUNCTION_NOARGS ();
--- a/src/internet/model/ipv6-raw-socket-impl.h	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ipv6-raw-socket-impl.h	Thu Dec 03 00:35:35 2015 +0100
@@ -107,6 +107,7 @@
   virtual int SendTo (Ptr<Packet> p, uint32_t flags, const Address& toAddress);
   virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
   virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags, Address& fromAddress);
+  virtual void Ipv6JoinGroup (Ipv6Address address, Socket::Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses);
 
   /**
    * \brief Set protocol field.
--- a/src/internet/model/ripng.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/ripng.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -119,6 +119,7 @@
       if (m_interfaceExclusions.find (i) == m_interfaceExclusions.end ())
         {
           activeInterface = true;
+          m_ipv6->SetForwarding (i, true);
         }
 
       for (uint32_t j = 0; j < m_ipv6->GetNAddresses (i); j++)
@@ -290,6 +291,7 @@
   if (m_interfaceExclusions.find (i) == m_interfaceExclusions.end ())
     {
       activeInterface = true;
+      m_ipv6->SetForwarding (i, true);
     }
 
   for (uint32_t j = 0; j < m_ipv6->GetNAddresses (i); j++)
--- a/src/internet/model/udp-socket-impl.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/udp-socket-impl.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -26,6 +26,7 @@
 #include "ns3/ipv6-route.h"
 #include "ns3/ipv4.h"
 #include "ns3/ipv6.h"
+#include "ns3/ipv6-l3-protocol.h"
 #include "ns3/ipv4-header.h"
 #include "ns3/ipv4-routing-protocol.h"
 #include "ns3/ipv6-routing-protocol.h"
@@ -305,6 +306,14 @@
           m_errno = port ? ERROR_ADDRINUSE : ERROR_ADDRNOTAVAIL;
           return -1;
         }
+      if (ipv6.IsMulticast ())
+        {
+          Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
+          if (ipv6l3)
+            {
+              ipv6l3->AddMulticastAddress (ipv6);
+            }
+        }
     }
   else
     {
@@ -349,6 +358,7 @@
       m_errno = Socket::ERROR_BADF;
       return -1;
     }
+  Ipv6LeaveGroup ();
   m_shutdownRecv = true;
   m_shutdownSend = true;
   DeallocateEndPoint ();
@@ -955,6 +965,18 @@
       NS_ASSERT (m_endPoint6 != 0);
     }
   m_endPoint6->BindToNetDevice (netdevice);
+
+  if (m_endPoint6->GetLocalAddress ().IsMulticast ())
+    {
+      Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
+      if (ipv6l3)
+        {
+          uint32_t index = ipv6l3->GetInterfaceForDevice (netdevice);
+          ipv6l3->RemoveMulticastAddress (m_endPoint6->GetLocalAddress ());
+          ipv6l3->AddMulticastAddress (m_endPoint6->GetLocalAddress (), index);
+        }
+    }
+
   return;
 }
 
@@ -1169,5 +1191,52 @@
   return m_allowBroadcast;
 }
 
+void
+UdpSocketImpl::Ipv6JoinGroup (Ipv6Address address, Socket::Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses)
+{
+  NS_LOG_FUNCTION (this << address << &filterMode << &sourceAddresses);
+
+  // We can join only one multicast group (or change its params)
+  NS_ASSERT_MSG ((m_ipv6MulticastGroupAddress == address || m_ipv6MulticastGroupAddress.IsAny ()), "Can join only one IPv6 multicast group.");
+
+  if (!m_ipv6MulticastGroupAddress.IsAny ())
+    {
+      Ipv6LeaveGroup ();
+    }
+  m_ipv6MulticastGroupAddress = address;
+
+  Ptr<Ipv6L3Protocol> ipv6l3 = m_node->GetObject <Ipv6L3Protocol> ();
+  if (ipv6l3)
+    {
+      if (filterMode == INCLUDE && sourceAddresses.empty ())
+        {
+          // it is a leave
+          if (m_boundnetdevice)
+            {
+              int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
+              NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
+              ipv6l3->RemoveMulticastAddress (address, index);
+            }
+          else
+            {
+              ipv6l3->RemoveMulticastAddress (address);
+            }
+        }
+      else
+        {
+          // it is a join or a modification
+          if (m_boundnetdevice)
+            {
+              int32_t index = ipv6l3->GetInterfaceForDevice (m_boundnetdevice);
+              NS_ASSERT_MSG (index >= 0, "Interface without a valid index");
+              ipv6l3->AddMulticastAddress (address, index);
+            }
+          else
+            {
+              ipv6l3->AddMulticastAddress (address);
+            }
+        }
+    }
+}
 
 } // namespace ns3
--- a/src/internet/model/udp-socket-impl.h	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/model/udp-socket-impl.h	Thu Dec 03 00:35:35 2015 +0100
@@ -98,6 +98,7 @@
   virtual void BindToNetDevice (Ptr<NetDevice> netdevice);
   virtual bool SetAllowBroadcast (bool allowBroadcast);
   virtual bool GetAllowBroadcast () const;
+  virtual void Ipv6JoinGroup (Ipv6Address address, Socket::Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses);
 
 private:
   // Attributes set through UdpSocket base class 
--- a/src/internet/test/ipv6-ripng-test.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/internet/test/ipv6-ripng-test.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -613,6 +613,7 @@
   Ptr<SocketFactory> rxSocketFactory = listener->GetObject<UdpSocketFactory> ();
   Ptr<Socket> rxSocket = rxSocketFactory->CreateSocket ();
   NS_TEST_EXPECT_MSG_EQ (rxSocket->Bind (Inet6SocketAddress (Ipv6Address ("ff02::9"), 521)), 0, "trivial");
+  rxSocket->BindToNetDevice (listenerDev);
   rxSocket->SetRecvCallback (MakeCallback (&Ipv6RipngSplitHorizonStrategyTest::ReceivePktProbe, this));
 
   // ------ Now the tests ------------
--- a/src/network/model/socket.cc	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/network/model/socket.cc	Thu Dec 03 00:35:35 2015 +0100
@@ -510,6 +510,38 @@
   return m_ipv6RecvHopLimit;
 }
 
+void
+Socket::Ipv6JoinGroup (Ipv6Address address, Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses)
+{
+  NS_LOG_FUNCTION (this<<address<<&filterMode<<&sourceAddresses);
+  NS_ASSERT_MSG (false,"Ipv6JoinGroup not implemented on this socket");
+}
+
+void
+Socket::Ipv6JoinGroup (Ipv6Address address)
+{
+  NS_LOG_FUNCTION (this<<address);
+
+  // Join Group. Note that joining a group with no sources means joining without source restrictions.
+  std::vector<Ipv6Address> sourceAddresses;
+  Ipv6JoinGroup (address, EXCLUDE, sourceAddresses);
+}
+
+void
+Socket::Ipv6LeaveGroup (void)
+{
+  NS_LOG_FUNCTION (this);
+  if(m_ipv6MulticastGroupAddress.IsAny () )
+    {
+      NS_LOG_INFO (" The socket was not bound to any group.");
+      return;
+    }
+  // Leave Group. Note that joining a group with no sources means leaving it.
+  std::vector<Ipv6Address> sourceAddresses;
+  Ipv6JoinGroup (m_ipv6MulticastGroupAddress, INCLUDE, sourceAddresses);
+  m_ipv6MulticastGroupAddress = Ipv6Address::GetAny ();
+}
+
 /***************************************************************
  *           Socket Tags
  ***************************************************************/
--- a/src/network/model/socket.h	Wed Dec 02 23:37:23 2015 +0100
+++ b/src/network/model/socket.h	Thu Dec 03 00:35:35 2015 +0100
@@ -109,6 +109,23 @@
   };
 
   /**
+   * \enum Ipv6MulticastFilterMode
+   * \brief Enumeration of the possible filter of a socket.
+   *
+   * A socket can have filters on specific sources to include only
+   * packets incoming from them, or to exclude packets incoming
+   * from specific sources.
+   * Moreover, inclusion and exclusion also works as a leave,
+   * since "joining" a group without allowed sources is equivalent
+   * to leaving it.
+   */
+  enum Ipv6MulticastFilterMode
+  {
+    INCLUDE=1,
+    EXCLUDE
+  };
+
+  /**
    * This method wraps the creation of sockets that is performed
    * on a given node by a SocketFactory specified by TypeId.
    * 
@@ -817,6 +834,35 @@
    */
   bool IsIpv6RecvHopLimit (void) const;
  
+  /**
+   * \brief Joins a IPv6 multicast group.
+   *
+   * Based on the filter mode and source addresses this can be interpreted as a
+   * join, leave, or modification to source filtering on a multicast group.
+   *
+   * Mind that a socket can join only one multicast group. Any attempt to join another group will remove the old one.
+   *
+   *
+   * \param address Requested multicast address.
+   * \param filterMode Socket filtering mode (INCLUDE | EXCLUDE).
+   * \param sourceAddresses All the source addresses on which socket is interested or not interested.
+   */
+  virtual void Ipv6JoinGroup (Ipv6Address address, Ipv6MulticastFilterMode filterMode, std::vector<Ipv6Address> sourceAddresses);
+
+  /**
+   * \brief Joins a IPv6 multicast group without filters.
+   *
+   * A socket can join only one multicast group. Any attempt to join another group will remove the old one.
+   *
+   * \param address Group address on which socket wants to join.
+   */
+  virtual void Ipv6JoinGroup (Ipv6Address address);
+
+  /**
+   * \brief Leaves IPv6 multicast group this socket is joined to.
+   */
+  virtual void Ipv6LeaveGroup (void);
+
 protected:
   /**
    * \brief Notify through the callback (if set) that the connection has been
@@ -913,6 +959,7 @@
 
   Ptr<NetDevice> m_boundnetdevice; //!< the device this socket is bound to (might be null).
   bool m_recvPktInfo; //!< if the socket should add packet info tags to the packet forwarded to L4.
+  Ipv6Address m_ipv6MulticastGroupAddress; //!< IPv6 multicast group address.
 
 private:
   Callback<void, Ptr<Socket> >                   m_connectionSucceeded;  //!< connection succeeded callback