diff --git a/include/openthread/instance.h b/include/openthread/instance.h index bc60c08a5..2fa848528 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (384) +#define OPENTHREAD_API_VERSION (385) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 8301ff93d..cb4d12491 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -52,12 +52,13 @@ extern "C" { * */ -#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes) -#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits) -#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes) -#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes) -#define OT_IP6_HEADER_SIZE 40 ///< Size of an IPv6 header (bytes) -#define OT_IP6_HEADER_PROTO_OFFSET 6 ///< Offset of the proto field in the IPv6 header (bytes) +#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes) +#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits) +#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes) +#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes) +#define OT_IP6_ADDRESS_BITSIZE (OT_IP6_ADDRESS_SIZE * 8) ///< Size of an IPv6 address (bits) +#define OT_IP6_HEADER_SIZE 40 ///< Size of an IPv6 header (bytes) +#define OT_IP6_HEADER_PROTO_OFFSET 6 ///< Offset of the proto field in the IPv6 header (bytes) /** * @struct otIp6InterfaceIdentifier diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index 406708554..f41d8463d 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -1080,6 +1080,46 @@ exit: } #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +#ifdef __linux__ +/** + * Returns whether the address is a required anycast address (RFC2373, 2.6.1). + * + */ +static bool isRequiredAnycast(const uint8_t *aAddress, uint8_t aPrefixLength) +{ + bool isRequiredAnycast = false; + uint8_t firstBytePos = aPrefixLength / 8; + uint8_t remainingBits = aPrefixLength % 8; + + if (aPrefixLength == OT_IP6_ADDRESS_BITSIZE) + { + ExitNow(); + } + + if (remainingBits != 0) + { + if ((aAddress[firstBytePos] & ((1 << remainingBits) - 1)) != 0) + { + ExitNow(); + } + firstBytePos++; + } + + for (int i = firstBytePos; i < OT_IP6_ADDRESS_SIZE; ++i) + { + if (aAddress[i] != 0) + { + ExitNow(); + } + } + + isRequiredAnycast = true; + +exit: + return isRequiredAnycast; +} +#endif // __linux__ + static void processTransmit(otInstance *aInstance) { otMessage *message = nullptr; @@ -1213,6 +1253,15 @@ static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetli addr6.sin6_family = AF_INET6; memcpy(&addr6.sin6_addr, RTA_DATA(rta), sizeof(addr6.sin6_addr)); + // Linux allows adding an IPv6 required anycast address to an interface, + // which blocks openthread deriving an address by SLAAC and will cause routing issues. + // Ignore the required anycast addresses here to allow OpenThread stack generate one when necessary, + // and Linux will prefer the non-required anycast address on the interface. + if (isRequiredAnycast(addr.GetBytes(), ifaddr->ifa_prefixlen)) + { + continue; + } + if (aNetlinkMessage->nlmsg_type == RTM_NEWADDR) { if (!addr.IsMulticast())