/* * Copyright (c) 2018 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include LOG_MODULE_DECLARE(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #include #include #include #include #include #include "openthread_utils.h" #define ALOC16_MASK 0xfc static bool is_anycast_locator(const otNetifAddress *address) { return address->mAddress.mFields.m16[4] == htons(0x0000) && address->mAddress.mFields.m16[5] == htons(0x00ff) && address->mAddress.mFields.m16[6] == htons(0xfe00) && address->mAddress.mFields.m8[14] == ALOC16_MASK; } static bool is_mesh_local(struct openthread_context *context, const uint8_t *address) { const otMeshLocalPrefix *ml_prefix = otThreadGetMeshLocalPrefix(context->instance); return (memcmp(address, ml_prefix->m8, sizeof(ml_prefix)) == 0); } int pkt_list_add(struct openthread_context *context, struct net_pkt *pkt) { uint16_t i_idx = context->pkt_list_in_idx; if (context->pkt_list_full) { return -ENOMEM; } i_idx++; if (i_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) { i_idx = 0U; } if (i_idx == context->pkt_list_out_idx) { context->pkt_list_full = 1U; } context->pkt_list[context->pkt_list_in_idx].pkt = pkt; context->pkt_list_in_idx = i_idx; return 0; } void pkt_list_remove_first(struct openthread_context *context) { uint16_t idx = context->pkt_list_in_idx; if (idx == 0U) { idx = CONFIG_OPENTHREAD_PKT_LIST_SIZE - 1; } else { idx--; } context->pkt_list_in_idx = idx; if (context->pkt_list_full) { context->pkt_list_full = 0U; } } struct net_pkt *pkt_list_peek(struct openthread_context *context) { if ((context->pkt_list_in_idx == context->pkt_list_out_idx) && (!context->pkt_list_full)) { return NULL; } return context->pkt_list[context->pkt_list_out_idx].pkt; } void pkt_list_remove_last(struct openthread_context *context) { if ((context->pkt_list_in_idx == context->pkt_list_out_idx) && (!context->pkt_list_full)) { return; } context->pkt_list_out_idx++; if (context->pkt_list_out_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) { context->pkt_list_out_idx = 0U; } context->pkt_list_full = 0U; } void add_ipv6_addr_to_zephyr(struct openthread_context *context) { const otNetifAddress *address; struct net_if_addr *if_addr; for (address = otIp6GetUnicastAddresses(context->instance); address; address = address->mNext) { if (address->mRloc || is_anycast_locator(address)) { continue; } if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Adding %s", net_addr_ntop(AF_INET6, (struct in6_addr *)(&address->mAddress), buf, sizeof(buf))); } /* Thread and SLAAC are clearly AUTOCONF, handle * manual/NCP addresses in the same way */ if ((address->mAddressOrigin == OT_ADDRESS_ORIGIN_THREAD) || (address->mAddressOrigin == OT_ADDRESS_ORIGIN_SLAAC)) { if_addr = net_if_ipv6_addr_add( context->iface, (struct in6_addr *)(&address->mAddress), NET_ADDR_AUTOCONF, 0); } else if (address->mAddressOrigin == OT_ADDRESS_ORIGIN_DHCPV6) { if_addr = net_if_ipv6_addr_add( context->iface, (struct in6_addr *)(&address->mAddress), NET_ADDR_DHCP, 0); } else if (address->mAddressOrigin == OT_ADDRESS_ORIGIN_MANUAL) { if_addr = net_if_ipv6_addr_add( context->iface, (struct in6_addr *)(&address->mAddress), NET_ADDR_MANUAL, 0); } else { NET_ERR("Unknown OpenThread address origin ignored."); continue; } if (if_addr == NULL) { NET_ERR("Cannot add OpenThread unicast address"); continue; } if_addr->is_mesh_local = is_mesh_local( context, address->mAddress.mFields.m8); } } void add_ipv6_addr_to_ot(struct openthread_context *context, const struct in6_addr *addr6) { struct otNetifAddress addr = { 0 }; struct net_if_ipv6 *ipv6; struct net_if_addr *if_addr = NULL; int i; /* IPv6 struct should've already been allocated when we get an * address added event. */ ipv6 = context->iface->config.ip.ipv6; if (ipv6 == NULL) { NET_ERR("No IPv6 container allocated"); return; } /* Find the net_if_addr structure containing the newly added address. */ for (i = NET_IF_MAX_IPV6_ADDR - 1; i >= 0; i--) { if (ipv6->unicast[i].is_used && net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr, addr6)) { if_addr = &ipv6->unicast[i]; break; } } if (if_addr == NULL) { NET_ERR("No corresponding net_if_addr found"); return; } memcpy(&addr.mAddress, addr6, sizeof(addr.mAddress)); if_addr->is_mesh_local = is_mesh_local( context, ipv6->unicast[i].address.in6_addr.s6_addr); addr.mValid = true; addr.mPreferred = true; addr.mPrefixLength = 64; if (if_addr->addr_type == NET_ADDR_AUTOCONF) { addr.mAddressOrigin = OT_ADDRESS_ORIGIN_SLAAC; } else if (if_addr->addr_type == NET_ADDR_DHCP) { addr.mAddressOrigin = OT_ADDRESS_ORIGIN_DHCPV6; } else if (if_addr->addr_type == NET_ADDR_MANUAL) { addr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL; } else { NET_ERR("Unknown address type"); return; } openthread_api_mutex_lock(context); otIp6AddUnicastAddress(context->instance, &addr); openthread_api_mutex_unlock(context); if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Added %s", net_addr_ntop(AF_INET6, &addr.mAddress, buf, sizeof(buf))); } } void add_ipv6_maddr_to_ot(struct openthread_context *context, const struct in6_addr *addr6) { struct otIp6Address addr; memcpy(&addr, addr6, sizeof(addr)); openthread_api_mutex_lock(context); otIp6SubscribeMulticastAddress(context->instance, &addr); openthread_api_mutex_unlock(context); if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Added multicast %s", net_addr_ntop(AF_INET6, &addr, buf, sizeof(buf))); } } void add_ipv6_maddr_to_zephyr(struct openthread_context *context) { const otNetifMulticastAddress *maddress; struct net_if_mcast_addr *zmaddr; for (maddress = otIp6GetMulticastAddresses(context->instance); maddress; maddress = maddress->mNext) { if (net_if_ipv6_maddr_lookup( (struct in6_addr *)(&maddress->mAddress), &context->iface) != NULL) { continue; } if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Adding multicast %s", net_addr_ntop(AF_INET6, (struct in6_addr *) (&maddress->mAddress), buf, sizeof(buf))); } zmaddr = net_if_ipv6_maddr_add(context->iface, (struct in6_addr *)(&maddress->mAddress)); if (zmaddr && !(net_if_ipv6_maddr_is_joined(zmaddr) || net_ipv6_is_addr_mcast_iface( (struct in6_addr *)(&maddress->mAddress)) || net_ipv6_is_addr_mcast_link_all_nodes( (struct in6_addr *)(&maddress->mAddress)))) { net_if_ipv6_maddr_join(context->iface, zmaddr); } } } void rm_ipv6_addr_from_zephyr(struct openthread_context *context) { struct in6_addr *ot_addr; struct net_if_addr *zephyr_addr; struct net_if_ipv6 *ipv6; int i; if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) { NET_DBG("Cannot find IPv6 address"); return; } for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { const otNetifAddress *address; bool used = false; zephyr_addr = &ipv6->unicast[i]; if (!zephyr_addr->is_used) { continue; } for (address = otIp6GetUnicastAddresses(context->instance); address; address = address->mNext) { ot_addr = (struct in6_addr *)(&address->mAddress); if (net_ipv6_addr_cmp(ot_addr, &zephyr_addr->address.in6_addr)) { used = true; break; } } if (!used) { if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Removing %s", net_addr_ntop(AF_INET6, &zephyr_addr->address.in6_addr, buf, sizeof(buf))); } net_if_ipv6_addr_rm(context->iface, &zephyr_addr->address.in6_addr); } } } void rm_ipv6_maddr_from_zephyr(struct openthread_context *context) { struct in6_addr *ot_addr; struct net_if_mcast_addr *zephyr_addr; struct net_if_ipv6 *ipv6; int i; if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) { NET_DBG("Cannot find IPv6 address"); return; } for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) { const otNetifMulticastAddress *maddress; bool used = false; zephyr_addr = &ipv6->mcast[i]; if (!zephyr_addr->is_used) { continue; } for (maddress = otIp6GetMulticastAddresses(context->instance); maddress; maddress = maddress->mNext) { ot_addr = (struct in6_addr *)(&maddress->mAddress); if (net_ipv6_addr_cmp(ot_addr, &zephyr_addr->address.in6_addr)) { used = true; break; } } if (!used) { if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) { char buf[NET_IPV6_ADDR_LEN]; NET_DBG("Removing multicast %s", net_addr_ntop(AF_INET6, &zephyr_addr->address.in6_addr, buf, sizeof(buf))); } net_if_ipv6_maddr_rm(context->iface, &zephyr_addr->address.in6_addr); } } }