openweave/openweave-core

Multicast ipv6 addresses for sleepy end devices not properly supported

pierredelisle opened this issue · 0 comments

While implementing a mechanism where two devices can be associated with each other using the Weave DeviceDescription profile, we ran into the following issue.

The two devices are Thread Sleepy End Devices (SED). One device sends an IdentifyRequest message using a multicast address. Since the multicast must reach Sleepy End Devices, the multicast address is constructed following these guidelines:

  • Sleep End Devices subscribe to the mesh local prefix-based multicast addresses (link local and realm local) by default.
  • To reach the SED in the realm local, you can use the Realm-Local mesh local prefix-based multicast address which follows these rules according to RFC3306.
    • flags: 3
    • scope: 3
    • plen: mesh local prefix length
    • network prefix: mesh local prefix
    • group id: 1
  • For the thread mesh local prefix, it is by default 8 bytes (64bits), and OT provides otThreadGetMeshLocalPrefix() to retrieve the mesh local prefix.
  • In weave, IPAddress::MakeIPv6PrefixMulticast() method can be used to construct such prefix based multicast addresses.

The issue is that lwip recognizes that “mesh local prefix-based multicast address” as a “general” multicast address ((ip6_addr_ismulticast) but then fails to allow it through as the address does not satisfy any of the multicast specific tests (alnodes_iflocal, allnodes_linklocal, allnodes_networklocal, allrouters_linklocal).
More specifically, in ip6.c, function ip6_input(), the multicast packet eventually ends up here:

if (netif == NULL) {
 /* packet not for us, route or discard */
 LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n"));

and the packet is discarded.

As a workaround to test that these multicast messages worked fine, we made the following modifications to allow multicast messages for SED devices to be properly let through:

/* match packet against an interface, i.e. is this packet for us? */
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
 /* Always joined to multicast if-local and link-local all-nodes group. */
 if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) ||
     ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) ||
     ip6_addr_isallnodes_networklocal(ip6_current_dest_addr()) ||
     ip6_addr_isallrouters_linklocal(ip6_current_dest_addr()) ||
     ip6_addr_ismulticast_thread_sed(ip6_current_dest_addr())) {
   netif = inp;
 }

and then have the following in ip6_addr.h

#define ip6_addr_ismulticast_thread_sed(ip6addr) (/* fixme: true if multicast address for Thread SEDs */)

Since this workaround is within lwip, this is probably not the right fix. We’ll leave it up to the OpenWeave experts to see where a proper fix should be applied to make sure multicast addresses that target Sleepy End Devices are properly let through by lwip.