diff --git a/include/zephyr/net/openthread.h b/include/zephyr/net/openthread.h index 0d83109e15b..673a7331d84 100644 --- a/include/zephyr/net/openthread.h +++ b/include/zephyr/net/openthread.h @@ -5,15 +5,15 @@ */ /** @file - * @brief OpenThread L2 stack public header + * @brief OpenThread stack public header */ #ifndef ZEPHYR_INCLUDE_NET_OPENTHREAD_H_ #define ZEPHYR_INCLUDE_NET_OPENTHREAD_H_ /** - * @brief OpenThread Layer 2 abstraction layer - * @defgroup openthread OpenThread L2 abstraction layer + * @brief OpenThread stack public header + * @defgroup openthread OpenThread stack * @since 1.11 * @version 0.8.0 * @ingroup ieee802154 @@ -21,10 +21,11 @@ */ #include - #include +#include #include +#include #ifdef __cplusplus extern "C" { @@ -44,8 +45,10 @@ struct pkt_list_elem { * @brief OpenThread l2 private data. */ struct openthread_context { - /** Pointer to OpenThread stack instance */ - otInstance *instance; + /** @deprecated Pointer to OpenThread stack instance. This is deprecated and will be removed + * in a future release. This field must not be used anymore. + */ + __deprecated otInstance *instance; /** Pointer to OpenThread network interface */ struct net_if *iface; @@ -62,25 +65,74 @@ struct openthread_context { /** Array for storing net_pkt for OpenThread internal usage */ struct pkt_list_elem pkt_list[CONFIG_OPENTHREAD_PKT_LIST_SIZE]; - /** A mutex to protect API calls from being preempted. */ - struct k_mutex api_lock; + /** @deprecated A mutex to protect API calls from being preempted. This is deprecated and + * will be removed in a future release. This field must not be used anymore. + */ + __deprecated struct k_mutex api_lock; - /** A work queue for all OpenThread activity */ - struct k_work_q work_q; + /** @deprecated A work queue for all OpenThread activity. This is deprecated and will be + * removed in a future release. This field must not be used anymore. + */ + __deprecated struct k_work_q work_q; - /** Work object for OpenThread internal usage */ - struct k_work api_work; + /** @deprecated Work object for OpenThread internal usage. This is deprecated and will be + * removed in a future release. This field must not be used anymore. + */ + __deprecated struct k_work api_work; - /** A list for state change callbacks */ + /** @deprecated A list for state change callbacks. This is deprecated and will be removed in + * a future release. + */ sys_slist_t state_change_cbs; }; /** * INTERNAL_HIDDEN @endcond */ +/** + * @brief The common callback type for receiving IPv4 (translated by NAT64) and IPv6 datagrams. + * + * This callback is called when a datagram is received. + * + * @param message The message to receive. + * @param context The context to pass to the callback. + */ +typedef void (*openthread_receive_cb)(otMessage *message, void *context); + /** OpenThread state change callback */ /** + * @brief OpenThread state change callback structure + * + * Used to register a callback in the callback list. As many + * callbacks as needed can be added as long as each of them + * are unique pointers of struct openthread_state_changed_cb. + * + * @note You may destroy the object only after it is unregistered from the callback list. + */ +struct openthread_state_changed_callback { + /** + * @brief Callback for notifying configuration or state changes. + * + * @param otCallback OpenThread callback to register. + * See https://openthread.io/reference/group/api-instance#otstatechangedcallback for + * details. + */ + otStateChangedCallback otCallback; + + /** User data if required */ + void *user_data; + + /** + * Internally used field for list handling + * - user must not directly modify + */ + sys_snode_t node; +}; + +/** + * @deprecated use @ref openthread_state_changed_callback instead. + * * @brief OpenThread state change callback structure * * Used to register a callback in the callback list. As many @@ -111,23 +163,42 @@ struct openthread_state_changed_cb { }; /** + * @brief Register callbacks that will be called when a certain configuration + * or state changes occur within OpenThread. + * + * @param cb Callback struct to register. + */ +int openthread_state_changed_callback_register(struct openthread_state_changed_callback *cb); + +/** + * @brief Unregister OpenThread configuration or state changed callbacks. + * + * @param cb Callback struct to unregister. + */ +int openthread_state_changed_callback_unregister(struct openthread_state_changed_callback *cb); + +/** + * @deprecated use @ref openthread_state_changed_callback_register instead. + * * @brief Registers callbacks which will be called when certain configuration * or state changes occur within OpenThread. * * @param ot_context the OpenThread context to register the callback with. * @param cb callback struct to register. */ -int openthread_state_changed_cb_register(struct openthread_context *ot_context, - struct openthread_state_changed_cb *cb); +__deprecated int openthread_state_changed_cb_register(struct openthread_context *ot_context, + struct openthread_state_changed_cb *cb); /** + * @deprecated use @ref openthread_state_changed_callback_unregister instead. + * * @brief Unregisters OpenThread configuration or state changed callbacks. * * @param ot_context the OpenThread context to unregister the callback from. * @param cb callback struct to unregister. */ -int openthread_state_changed_cb_unregister(struct openthread_context *ot_context, - struct openthread_state_changed_cb *cb); +__deprecated int openthread_state_changed_cb_unregister(struct openthread_context *ot_context, + struct openthread_state_changed_cb *cb); /** * @brief Get OpenThread thread identification. @@ -151,6 +222,44 @@ struct openthread_context *openthread_get_default_context(void); struct otInstance *openthread_get_default_instance(void); /** + * @brief Initialize the OpenThread module. + * + * This function: + * - Initializes the OpenThread module. + * - Creates an OpenThread single instance. + * - Starts the shell. + * - Enables the UART and NCP HDLC for coprocessor purposes. + * - Initializes the NAT64 translator. + * - Creates a work queue for the OpenThread module. + * + * @note This function is automatically called by Zephyr's networking layer. + * If you want to initialize the OpenThread independently, call this function + * in your application init code. + * + * @retval 0 On success. + * @retval -EIO On failure. + */ +int openthread_init(void); + +/** + * @brief Run the OpenThread network. + * + * @details Prepares the OpenThread network and enables it. + * Depends on active settings: it uses the stored network configuration, + * starts the joining procedure or uses the default network configuration. + * Additionally, when the device is MTD, it sets the SED mode to properly + * attach the network. + */ +int openthread_run(void); + +/** + * @brief Disable the OpenThread network. + */ +int openthread_stop(void); + +/** + * @deprecated use @ref openthread_run instead. + * * @brief Starts the OpenThread network. * * @details Depends on active settings: it uses stored network configuration, @@ -159,9 +268,46 @@ struct otInstance *openthread_get_default_instance(void); * * @param ot_context */ -int openthread_start(struct openthread_context *ot_context); +__deprecated int openthread_start(struct openthread_context *ot_context); /** + * @brief Set the additional callback for receiving packets. + * + * @details This callback is called once a packet is received and can be + * used to inject packets into the Zephyr networking stack. + * Setting this callback is optional. + * + * @param cb Callback to set. + * @param context Context to pass to the callback. + */ +void openthread_set_receive_cb(openthread_receive_cb cb, void *context); + +/** + * @brief Lock internal mutex before accessing OpenThread API. + * + * @details OpenThread API is not thread-safe. Therefore, before accessing any + * API function, you need to lock the internal mutex, to prevent the + * OpenThread thread from pre-empting the API call. + */ +void openthread_mutex_lock(void); + +/** + * @brief Try to lock internal mutex before accessing OpenThread API. + * + * @details This function behaves like openthread_mutex_lock(), provided that + * the internal mutex is unlocked. Otherwise, it returns a negative value without + * waiting. + */ +int openthread_mutex_try_lock(void); + +/** + * @brief Unlock internal mutex after accessing OpenThread API. + */ +void openthread_mutex_unlock(void); + +/** + * @deprecated use @ref openthread_mutex_lock. + * * @brief Lock internal mutex before accessing OT API. * * @details OpenThread API is not thread-safe, therefore before accessing any @@ -170,9 +316,11 @@ int openthread_start(struct openthread_context *ot_context); * * @param ot_context Context to lock. */ -void openthread_api_mutex_lock(struct openthread_context *ot_context); +__deprecated void openthread_api_mutex_lock(struct openthread_context *ot_context); /** + * @deprecated use @ref openthread_mutex_try_lock instead. + * * @brief Try to lock internal mutex before accessing OT API. * * @details This function behaves like openthread_api_mutex_lock() provided that @@ -183,14 +331,16 @@ void openthread_api_mutex_lock(struct openthread_context *ot_context); * @retval 0 On success. * @retval <0 On failure. */ -int openthread_api_mutex_try_lock(struct openthread_context *ot_context); +__deprecated int openthread_api_mutex_try_lock(struct openthread_context *ot_context); /** + * @deprecated use @ref openthread_mutex_unlock instead. + * * @brief Unlock internal mutex after accessing OT API. * * @param ot_context Context to unlock. */ -void openthread_api_mutex_unlock(struct openthread_context *ot_context); +__deprecated void openthread_api_mutex_unlock(struct openthread_context *ot_context); /** @cond INTERNAL_HIDDEN */ diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 941c8f1f219..0f3ba2b1550 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -273,6 +273,13 @@ zephyr_link_libraries(${ot_libs}) endif() +# Create a library for the OpenThread Zephyr utils +zephyr_library_named(openthread_utils) +zephyr_library_sources( + openthread.c +) +zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) + add_subdirectory(platform) endif() diff --git a/modules/openthread/Kconfig b/modules/openthread/Kconfig index 27832a581e1..10c8e79aed1 100644 --- a/modules/openthread/Kconfig +++ b/modules/openthread/Kconfig @@ -17,6 +17,22 @@ config OPENTHREAD if OPENTHREAD +config OPENTHREAD_SYS_INIT + bool "Initialize OpenThread stack during system initialization" + default y + depends on !NET_L2_OPENTHREAD + help + This option initializes the OpenThread automatically by calling the openthread_init() + function during system initialization. + +config OPENTHREAD_SYS_INIT_PRIORITY + int "OpenThread system initialization priority" + default 40 + depends on OPENTHREAD_SYS_INIT + help + This option sets the priority of the OpenThread system initialization. + + choice OPENTHREAD_IMPLEMENTATION prompt "OpenThread origin selection" help diff --git a/modules/openthread/openthread.c b/modules/openthread/openthread.c new file mode 100644 index 00000000000..308f42221e2 --- /dev/null +++ b/modules/openthread/openthread.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * This file implements the OpenThread module initialization and state change handling. + * + */ + +#include +LOG_MODULE_REGISTER(net_openthread_platform, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include "platform/platform-zephyr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) +#include +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + +#define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE) + +#if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE) +#define OT_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY) +#else +#define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY) +#endif + +#if defined(CONFIG_OPENTHREAD_NETWORK_NAME) +#define OT_NETWORK_NAME CONFIG_OPENTHREAD_NETWORK_NAME +#else +#define OT_NETWORK_NAME "" +#endif + +#if defined(CONFIG_OPENTHREAD_CHANNEL) +#define OT_CHANNEL CONFIG_OPENTHREAD_CHANNEL +#else +#define OT_CHANNEL 0 +#endif + +#if defined(CONFIG_OPENTHREAD_PANID) +#define OT_PANID CONFIG_OPENTHREAD_PANID +#else +#define OT_PANID 0 +#endif + +#if defined(CONFIG_OPENTHREAD_XPANID) +#define OT_XPANID CONFIG_OPENTHREAD_XPANID +#else +#define OT_XPANID "" +#endif + +#if defined(CONFIG_OPENTHREAD_NETWORKKEY) +#define OT_NETWORKKEY CONFIG_OPENTHREAD_NETWORKKEY +#else +#define OT_NETWORKKEY "" +#endif + +#if defined(CONFIG_OPENTHREAD_JOINER_PSKD) +#define OT_JOINER_PSKD CONFIG_OPENTHREAD_JOINER_PSKD +#else +#define OT_JOINER_PSKD "" +#endif + +#if defined(CONFIG_OPENTHREAD_PLATFORM_INFO) +#define OT_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO +#else +#define OT_PLATFORM_INFO "" +#endif + +#if defined(CONFIG_OPENTHREAD_POLL_PERIOD) +#define OT_POLL_PERIOD CONFIG_OPENTHREAD_POLL_PERIOD +#else +#define OT_POLL_PERIOD 0 +#endif + +#define ZEPHYR_PACKAGE_NAME "Zephyr" +#define PACKAGE_VERSION KERNEL_VERSION_STRING + +static void openthread_process(struct k_work *work); + +/* Global variables to store the OpenThread module context */ +static otInstance *openthread_instance; +static sys_slist_t openthread_state_change_cbs = SYS_SLIST_STATIC_INIT(openthread_state_change_cbs); +static struct k_work_q openthread_work_q; + +static K_WORK_DEFINE(openthread_work, openthread_process); +static K_MUTEX_DEFINE(openthread_lock); +K_KERNEL_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE); + +k_tid_t openthread_thread_id_get(void) +{ + return (k_tid_t)&openthread_work_q.thread; +} + +static int ncp_hdlc_send(const uint8_t *buf, uint16_t len) +{ + otError err = OT_ERROR_NONE; + + err = otPlatUartSend(buf, len); + if (err != OT_ERROR_NONE) { + return 0; + } + + return len; +} + +static void openthread_process(struct k_work *work) +{ + ARG_UNUSED(work); + + openthread_mutex_lock(); + + while (otTaskletsArePending(openthread_instance)) { + otTaskletsProcess(openthread_instance); + } + + otSysProcessDrivers(openthread_instance); + + openthread_mutex_unlock(); +} + +static void ot_joiner_start_handler(otError error, void *context) +{ + ARG_UNUSED(context); + + if (error != OT_ERROR_NONE) { + LOG_ERR("Join failed [%d]", error); + } else { + LOG_INF("Join success"); + error = otThreadSetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start the OpenThread network [%d]", error); + } + } +} + +static bool ot_setup_default_configuration(void) +{ + otExtendedPanId xpanid = {0}; + otNetworkKey networkKey = {0}; + otError error = OT_ERROR_NONE; + + error = otThreadSetNetworkName(openthread_instance, OT_NETWORK_NAME); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "network name", error); + return false; + } + + error = otLinkSetChannel(openthread_instance, OT_CHANNEL); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "channel", error); + return false; + } + + error = otLinkSetPanId(openthread_instance, OT_PANID); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "PAN ID", error); + return false; + } + + net_bytes_from_str(xpanid.m8, 8, (char *)OT_XPANID); + error = otThreadSetExtendedPanId(openthread_instance, &xpanid); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "ext PAN ID", error); + return false; + } + + if (strlen(OT_NETWORKKEY)) { + net_bytes_from_str(networkKey.m8, OT_NETWORK_KEY_SIZE, (char *)OT_NETWORKKEY); + error = otThreadSetNetworkKey(openthread_instance, &networkKey); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "network key", error); + return false; + } + } + + return true; +} + +static void ot_state_changed_handler(uint32_t flags, void *context) +{ + ARG_UNUSED(context); + + struct openthread_state_changed_callback *entry, *next; + + bool is_up = otIp6IsEnabled(openthread_instance); + + LOG_INF("State changed! Flags: 0x%08" PRIx32 " Current role: %s Ip6: %s", flags, + otThreadDeviceRoleToString(otThreadGetDeviceRole(openthread_instance)), + (is_up ? "up" : "down")); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&openthread_state_change_cbs, entry, next, node) { + if (entry->otCallback != NULL) { + entry->otCallback(flags, entry->user_data); + } + } +} + +void otTaskletsSignalPending(otInstance *instance) +{ + ARG_UNUSED(instance); + + int error = k_work_submit_to_queue(&openthread_work_q, &openthread_work); + + if (error < 0) { + LOG_ERR("Failed to submit work to queue, error: %d", error); + } +} + +void otSysEventSignalPending(void) +{ + otTaskletsSignalPending(NULL); +} + +int openthread_state_changed_callback_register(struct openthread_state_changed_callback *cb) +{ + CHECKIF(cb == NULL || cb->otCallback == NULL) { + return -EINVAL; + } + + openthread_mutex_lock(); + sys_slist_append(&openthread_state_change_cbs, &cb->node); + openthread_mutex_unlock(); + + return 0; +} + +int openthread_state_changed_callback_unregister(struct openthread_state_changed_callback *cb) +{ + bool removed = false; + + CHECKIF(cb == NULL) { + return -EINVAL; + } + + openthread_mutex_lock(); + removed = sys_slist_find_and_remove(&openthread_state_change_cbs, &cb->node); + openthread_mutex_unlock(); + + if (!removed) { + return -EALREADY; + } + + return 0; +} + +struct otInstance *openthread_get_default_instance(void) +{ + __ASSERT(openthread_instance, "OT instance is not initialized"); + return openthread_instance; +} + +int openthread_init(void) +{ + struct k_work_queue_config q_cfg = { + .name = "openthread", + .no_yield = true, + }; + otError error = OT_ERROR_NONE; + + /* Prevent multiple initializations */ + if (openthread_instance) { + return 0; + } + + openthread_mutex_lock(); + + otSysInit(0, NULL); + openthread_instance = otInstanceInitSingle(); + + __ASSERT(openthread_instance, "OT instance initialization failed"); + + if (IS_ENABLED(CONFIG_OPENTHREAD_SHELL)) { + platformShellInit(openthread_instance); + } + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + error = otPlatUartEnable(); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to enable UART: [%d]", error); + } + + otNcpHdlcInit(openthread_instance, ncp_hdlc_send); + } else { + otIp6SetReceiveFilterEnabled(openthread_instance, true); + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) + + otIp4Cidr nat64_cidr; + + if (otIp4CidrFromString(CONFIG_OPENTHREAD_NAT64_CIDR, &nat64_cidr) == + OT_ERROR_NONE) { + if (otNat64SetIp4Cidr(openthread_instance, &nat64_cidr) != OT_ERROR_NONE) { + LOG_ERR("Incorrect NAT64 CIDR"); + return -EIO; + } + } else { + LOG_ERR("Failed to parse NAT64 CIDR"); + return -EIO; + } +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + + error = otSetStateChangedCallback(openthread_instance, &ot_state_changed_handler, + NULL); + if (error != OT_ERROR_NONE) { + LOG_ERR("Could not set state changed callback: %d", error); + return -EIO; + } + } + + openthread_mutex_unlock(); + + /* Start work queue for the OpenThread module */ + k_work_queue_start(&openthread_work_q, ot_stack_area, K_KERNEL_STACK_SIZEOF(ot_stack_area), + OT_PRIORITY, &q_cfg); + + (void)k_work_submit_to_queue(&openthread_work_q, &openthread_work); + + return error == OT_ERROR_NONE ? 0 : -EIO; +} + +int openthread_run(void) +{ + openthread_mutex_lock(); + otError error = OT_ERROR_NONE; + + LOG_INF("OpenThread version: %s", otGetVersionString()); + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + LOG_DBG("OpenThread co-processor."); + goto exit; + } + + error = otIp6SetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "IPv6 support", error); + goto exit; + } + + /* Sleepy End Device specific configuration. */ + if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) { + otLinkModeConfig ot_mode = otThreadGetLinkMode(openthread_instance); + + /* A SED should always attach the network as a SED to indicate + * increased buffer requirement to a parent. + */ + ot_mode.mRxOnWhenIdle = false; + + error = otThreadSetLinkMode(openthread_instance, ot_mode); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "link mode", error); + goto exit; + } + + error = otLinkSetPollPeriod(openthread_instance, OT_POLL_PERIOD); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "poll period", error); + goto exit; + } + } + + /* Configure Child Supervision and MLE Child timeouts. */ + otChildSupervisionSetInterval(openthread_instance, + CONFIG_OPENTHREAD_CHILD_SUPERVISION_INTERVAL); + otChildSupervisionSetCheckTimeout(openthread_instance, + CONFIG_OPENTHREAD_CHILD_SUPERVISION_CHECK_TIMEOUT); + otThreadSetChildTimeout(openthread_instance, CONFIG_OPENTHREAD_MLE_CHILD_TIMEOUT); + + if (otDatasetIsCommissioned(openthread_instance)) { + /* OpenThread already has dataset stored - skip the + * configuration. + */ + LOG_DBG("OpenThread already commissioned."); + } else if (IS_ENABLED(CONFIG_OPENTHREAD_JOINER_AUTOSTART)) { + /* No dataset - initiate network join procedure. */ + LOG_DBG("Starting OpenThread join procedure."); + + error = otJoinerStart(openthread_instance, OT_JOINER_PSKD, NULL, + ZEPHYR_PACKAGE_NAME, OT_PLATFORM_INFO, PACKAGE_VERSION, NULL, + &ot_joiner_start_handler, NULL); + + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start joiner [%d]", error); + } + + goto exit; + } else { + /* No dataset - load the default configuration. */ + LOG_DBG("Loading OpenThread default configuration."); + + if (!ot_setup_default_configuration()) { + goto exit; + } + } + + LOG_INF("Network name: %s", otThreadGetNetworkName(openthread_instance)); + + /* Start the network. */ + error = otThreadSetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start the OpenThread network [%d]", error); + } + +exit: + + openthread_mutex_unlock(); + + return error == OT_ERROR_NONE ? 0 : -EIO; +} + +int openthread_stop(void) +{ + otError error = OT_ERROR_NONE; + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + return 0; + } + + openthread_mutex_lock(); + + error = otThreadSetEnabled(openthread_instance, false); + if (error == OT_ERROR_INVALID_STATE) { + LOG_DBG("Openthread interface was not up [%d]", error); + } + + openthread_mutex_unlock(); + + return 0; +} + +void openthread_set_receive_cb(openthread_receive_cb cb, void *context) +{ + __ASSERT(cb != NULL, "Receive callback is not set"); + __ASSERT(openthread_instance != NULL, "OpenThread instance is not initialized"); + + if (!IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + openthread_mutex_lock(); + otIp6SetReceiveCallback(openthread_instance, cb, context); + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) + otNat64SetReceiveIp4Callback(openthread_instance, cb, context); +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + + openthread_mutex_unlock(); + } +} + +void openthread_mutex_lock(void) +{ + (void)k_mutex_lock(&openthread_lock, K_FOREVER); +} + +int openthread_mutex_try_lock(void) +{ + return k_mutex_lock(&openthread_lock, K_NO_WAIT); +} + +void openthread_mutex_unlock(void) +{ + (void)k_mutex_unlock(&openthread_lock); +} + +#ifdef CONFIG_OPENTHREAD_SYS_INIT +SYS_INIT(openthread_init, POST_KERNEL, CONFIG_OPENTHREAD_SYS_INIT_PRIORITY); +#endif /* CONFIG_OPENTHREAD_SYS_INIT */ diff --git a/modules/openthread/platform/CMakeLists.txt b/modules/openthread/platform/CMakeLists.txt index bedd51c84ee..f36ea8ac972 100644 --- a/modules/openthread/platform/CMakeLists.txt +++ b/modules/openthread/platform/CMakeLists.txt @@ -8,10 +8,11 @@ zephyr_library_sources( platform.c ) -zephyr_library_sources_ifndef(CONFIG_HDLC_RCP_IF - radio.c - spi.c - ) +if(NOT CONFIG_HDLC_RCP_IF) + # Radio platform implementation dedicated for L2 Platform adaptation layer + zephyr_library_sources_ifdef(CONFIG_NET_L2_OPENTHREAD radio.c) + zephyr_library_sources(spi.c) +endif() zephyr_library_sources_ifdef(CONFIG_HDLC_RCP_IF radio_spinel.cpp @@ -22,7 +23,6 @@ zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_BLE_TCAT ble.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_COPROCESSOR uart.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_CRYPTO_PSA crypto_psa.c) -zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_EXTERNAL_HEAP memory.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_PLATFORM_MESSAGE_MANAGEMENT messagepool.c) zephyr_library_sources_ifdef(CONFIG_SETTINGS settings.c) diff --git a/modules/openthread/platform/entropy.c b/modules/openthread/platform/entropy.c index a52f885e306..843d6a533d0 100644 --- a/modules/openthread/platform/entropy.c +++ b/modules/openthread/platform/entropy.c @@ -10,7 +10,7 @@ #include -LOG_MODULE_REGISTER(net_otPlat_entropy, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(net_otPlat_entropy, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #if !defined(CONFIG_CSPRNG_ENABLED) #error OpenThread requires an entropy source for a TRNG diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 4a9fc1279cf..ba87f3ec492 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -15,7 +15,7 @@ #define LOG_MODULE_NAME net_otPlat_radio #include -LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #include #include diff --git a/modules/openthread/platform/radio_spinel.cpp b/modules/openthread/platform/radio_spinel.cpp index 95c05e88580..c96297f3bba 100644 --- a/modules/openthread/platform/radio_spinel.cpp +++ b/modules/openthread/platform/radio_spinel.cpp @@ -42,7 +42,7 @@ #include "hdlc_interface.hpp" #include -LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #include #include #include diff --git a/modules/openthread/platform/settings.c b/modules/openthread/platform/settings.c index ce5fefde0c8..4fdb77c6f9f 100644 --- a/modules/openthread/platform/settings.c +++ b/modules/openthread/platform/settings.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #define OT_SETTINGS_ROOT_KEY "ot" #define OT_SETTINGS_MAX_PATH_LEN 32 diff --git a/modules/openthread/platform/shell.c b/modules/openthread/shell.c similarity index 93% rename from modules/openthread/platform/shell.c rename to modules/openthread/shell.c index 22f11d31f3e..00de8d1e0df 100644 --- a/modules/openthread/platform/shell.c +++ b/modules/openthread/shell.c @@ -74,9 +74,9 @@ static int ot_cmd(const struct shell *sh, size_t argc, char *argv[]) shell_p = sh; - openthread_api_mutex_lock(openthread_get_default_context()); + openthread_mutex_lock(); otCliInputLine(rx_buffer); - openthread_api_mutex_unlock(openthread_get_default_context()); + openthread_mutex_unlock(); return 0; } diff --git a/subsys/net/l2/openthread/openthread.c b/subsys/net/l2/openthread/openthread.c index c82dfdea2d2..6ddeadf8dfc 100644 --- a/subsys/net/l2/openthread/openthread.c +++ b/subsys/net/l2/openthread/openthread.c @@ -19,111 +19,23 @@ LOG_MODULE_REGISTER(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #include #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include + #include -#include -#include -#include -#include #include #include "openthread_utils.h" -#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) -#include -#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ - -#define PKT_IS_IPv4(_p) ((NET_IPV6_HDR(_p)->vtc & 0xf0) == 0x40) - -#define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE) - -#if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE) -#define OT_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY) -#else -#define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY) -#endif - -#if defined(CONFIG_OPENTHREAD_NETWORK_NAME) -#define OT_NETWORK_NAME CONFIG_OPENTHREAD_NETWORK_NAME -#else -#define OT_NETWORK_NAME "" -#endif - -#if defined(CONFIG_OPENTHREAD_CHANNEL) -#define OT_CHANNEL CONFIG_OPENTHREAD_CHANNEL -#else -#define OT_CHANNEL 0 -#endif - -#if defined(CONFIG_OPENTHREAD_PANID) -#define OT_PANID CONFIG_OPENTHREAD_PANID -#else -#define OT_PANID 0 -#endif - -#if defined(CONFIG_OPENTHREAD_XPANID) -#define OT_XPANID CONFIG_OPENTHREAD_XPANID -#else -#define OT_XPANID "" -#endif - -#if defined(CONFIG_OPENTHREAD_NETWORKKEY) -#define OT_NETWORKKEY CONFIG_OPENTHREAD_NETWORKKEY -#else -#define OT_NETWORKKEY "" -#endif - -#if defined(CONFIG_OPENTHREAD_JOINER_PSKD) -#define OT_JOINER_PSKD CONFIG_OPENTHREAD_JOINER_PSKD -#else -#define OT_JOINER_PSKD "" -#endif - -#if defined(CONFIG_OPENTHREAD_PLATFORM_INFO) -#define OT_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO -#else -#define OT_PLATFORM_INFO "" -#endif - -#if defined(CONFIG_OPENTHREAD_POLL_PERIOD) -#define OT_POLL_PERIOD CONFIG_OPENTHREAD_POLL_PERIOD -#else -#define OT_POLL_PERIOD 0 -#endif - -#define ZEPHYR_PACKAGE_NAME "Zephyr" -#define PACKAGE_VERSION KERNEL_VERSION_STRING - -extern void platformShellInit(otInstance *aInstance); - -K_KERNEL_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE); - static struct net_linkaddr *ll_addr; -static otStateChangedCallback state_changed_cb; +static struct openthread_state_changed_callback ot_l2_state_changed_cb; -k_tid_t openthread_thread_id_get(void) -{ - struct openthread_context *ot_context = openthread_get_default_context(); - - return ot_context ? (k_tid_t)&ot_context->work_q.thread : 0; -} +#define PKT_IS_IPv4(_p) ((NET_IPV6_HDR(_p)->vtc & 0xf0) == 0x40) #ifdef CONFIG_NET_MGMT_EVENT static struct net_mgmt_event_callback ip6_addr_cb; -static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb, - uint32_t mgmt_event, struct net_if *iface) +static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) { if (net_if_l2(iface) != &NET_L2_GET_NAME(OPENTHREAD)) { return; @@ -148,18 +60,6 @@ static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb, } #endif /* CONFIG_NET_MGMT_EVENT */ -static int ncp_hdlc_send(const uint8_t *buf, uint16_t len) -{ - otError err; - - err = otPlatUartSend(buf, len); - if (err != OT_ERROR_NONE) { - return 0; - } - - return len; -} - #ifndef CONFIG_HDLC_RCP_IF void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) { @@ -169,30 +69,10 @@ void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) } #endif /* CONFIG_HDLC_RCP_IF */ -void otTaskletsSignalPending(otInstance *instance) -{ - struct openthread_context *ot_context = openthread_get_default_context(); - - if (ot_context) { - k_work_submit_to_queue(&ot_context->work_q, &ot_context->api_work); - } -} - -void otSysEventSignalPending(void) +static void ot_l2_state_changed_handler(uint32_t flags, void *context) { - otTaskletsSignalPending(NULL); -} - -static void ot_state_changed_handler(uint32_t flags, void *context) -{ - struct openthread_state_changed_cb *entry, *next; struct openthread_context *ot_context = context; - bool is_up = otIp6IsEnabled(ot_context->instance); - - NET_INFO("State changed! Flags: 0x%08" PRIx32 " Current role: %s Ip6: %s", - flags, - otThreadDeviceRoleToString(otThreadGetDeviceRole(ot_context->instance)), - (is_up ? "up" : "down")); + struct openthread_state_changed_cb *entry, *next; #if defined(CONFIG_OPENTHREAD_INTERFACE_EARLY_UP) if (is_up) { @@ -202,7 +82,7 @@ static void ot_state_changed_handler(uint32_t flags, void *context) } #else if (flags & OT_CHANGED_THREAD_ROLE) { - switch (otThreadGetDeviceRole(ot_context->instance)) { + switch (otThreadGetDeviceRole(openthread_get_default_instance())) { case OT_DEVICE_ROLE_CHILD: case OT_DEVICE_ROLE_ROUTER: case OT_DEVICE_ROLE_LEADER: @@ -219,38 +99,34 @@ static void ot_state_changed_handler(uint32_t flags, void *context) #endif if (flags & OT_CHANGED_IP6_ADDRESS_REMOVED) { - NET_DBG("Ipv6 address removed"); rm_ipv6_addr_from_zephyr(ot_context); + NET_DBG("Ipv6 address removed"); } if (flags & OT_CHANGED_IP6_ADDRESS_ADDED) { - NET_DBG("Ipv6 address added"); add_ipv6_addr_to_zephyr(ot_context); + NET_DBG("Ipv6 address added"); } if (flags & OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED) { - NET_DBG("Ipv6 multicast address removed"); rm_ipv6_maddr_from_zephyr(ot_context); + NET_DBG("Ipv6 multicast address removed"); } if (flags & OT_CHANGED_IP6_MULTICAST_SUBSCRIBED) { - NET_DBG("Ipv6 multicast address added"); add_ipv6_maddr_to_zephyr(ot_context); + NET_DBG("Ipv6 multicast address added"); } #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) if (flags & OT_CHANGED_NAT64_TRANSLATOR_STATE) { NET_DBG("Nat64 translator state changed to %x", - otNat64GetTranslatorState(ot_context->instance)); + otNat64GetTranslatorState(openthread_get_default_instance())); } #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ - if (state_changed_cb) { - state_changed_cb(flags, context); - } - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ot_context->state_change_cbs, entry, next, node) { if (entry->state_changed_cb != NULL) { entry->state_changed_cb(flags, ot_context, entry->user_data); @@ -258,7 +134,7 @@ static void ot_state_changed_handler(uint32_t flags, void *context) } } -static void ot_receive_handler(otMessage *aMessage, void *context) +static void ot_receive_handler(otMessage *message, void *context) { struct openthread_context *ot_context = context; @@ -267,8 +143,7 @@ static void ot_receive_handler(otMessage *aMessage, void *context) struct net_pkt *pkt; struct net_buf *pkt_buf; - pkt = net_pkt_rx_alloc_with_buffer(ot_context->iface, - otMessageGetLength(aMessage), + pkt = net_pkt_rx_alloc_with_buffer(ot_context->iface, otMessageGetLength(message), AF_UNSPEC, 0, K_NO_WAIT); if (!pkt) { NET_ERR("Failed to reserve net pkt"); @@ -278,8 +153,7 @@ static void ot_receive_handler(otMessage *aMessage, void *context) pkt_buf = pkt->buffer; while (1) { - read_len = otMessageRead(aMessage, offset, pkt_buf->data, - net_buf_tailroom(pkt_buf)); + read_len = otMessageRead(message, offset, pkt_buf->data, net_buf_tailroom(pkt_buf)); if (!read_len) { break; } @@ -328,42 +202,7 @@ static void ot_receive_handler(otMessage *aMessage, void *context) net_pkt_unref(pkt); } - otMessageFree(aMessage); -} - -static void ot_joiner_start_handler(otError error, void *context) -{ - struct openthread_context *ot_context = context; - - switch (error) { - case OT_ERROR_NONE: - NET_INFO("Join success"); - error = otThreadSetEnabled(ot_context->instance, true); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to start the OpenThread network [%d]", error); - } - - break; - default: - NET_ERR("Join failed [%d]", error); - break; - } -} - -static void openthread_process(struct k_work *work) -{ - struct openthread_context *ot_context - = CONTAINER_OF(work, struct openthread_context, api_work); - - openthread_api_mutex_lock(ot_context); - - while (otTaskletsArePending(ot_context->instance)) { - otTaskletsProcess(ot_context->instance); - } - - otSysProcessDrivers(ot_context->instance); - - openthread_api_mutex_unlock(ot_context); + otMessageFree(message); } static bool is_ipv6_frag(struct net_pkt *pkt) @@ -429,248 +268,55 @@ int openthread_send(struct net_if *iface, struct net_pkt *pkt) return len; } -int openthread_start(struct openthread_context *ot_context) +static int openthread_l2_init(struct net_if *iface) { - otInstance *ot_instance = ot_context->instance; - otError error = OT_ERROR_NONE; + struct openthread_context *ot_l2_context = net_if_l2_data(iface); + int error = 0; - openthread_api_mutex_lock(ot_context); - - NET_INFO("OpenThread version: %s", otGetVersionString()); - - if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { - NET_DBG("OpenThread co-processor."); - goto exit; - } - - error = otIp6SetEnabled(ot_context->instance, true); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "IPv6 support", error); - goto exit; - } - - /* Sleepy End Device specific configuration. */ - if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) { - otLinkModeConfig ot_mode = otThreadGetLinkMode(ot_instance); - - /* A SED should always attach the network as a SED to indicate - * increased buffer requirement to a parent. - */ - ot_mode.mRxOnWhenIdle = false; - - error = otThreadSetLinkMode(ot_context->instance, ot_mode); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "link mode", error); - goto exit; - } - - error = otLinkSetPollPeriod(ot_context->instance, OT_POLL_PERIOD); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "poll period", error); - goto exit; - } - } - - /* Configure Child Supervision and MLE Child timeouts. */ - otChildSupervisionSetInterval(ot_context->instance, - CONFIG_OPENTHREAD_CHILD_SUPERVISION_INTERVAL); - otChildSupervisionSetCheckTimeout(ot_context->instance, - CONFIG_OPENTHREAD_CHILD_SUPERVISION_CHECK_TIMEOUT); - otThreadSetChildTimeout(ot_context->instance, CONFIG_OPENTHREAD_MLE_CHILD_TIMEOUT); - - if (otDatasetIsCommissioned(ot_instance)) { - /* OpenThread already has dataset stored - skip the - * configuration. - */ - NET_DBG("OpenThread already commissioned."); - } else if (IS_ENABLED(CONFIG_OPENTHREAD_JOINER_AUTOSTART)) { - /* No dataset - initiate network join procedure. */ - NET_DBG("Starting OpenThread join procedure."); - - error = otJoinerStart(ot_instance, OT_JOINER_PSKD, NULL, ZEPHYR_PACKAGE_NAME, - OT_PLATFORM_INFO, PACKAGE_VERSION, NULL, - &ot_joiner_start_handler, ot_context); - - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to start joiner [%d]", error); - } - - goto exit; - } else { - /* No dataset - load the default configuration. */ - NET_DBG("Loading OpenThread default configuration."); - - otExtendedPanId xpanid; - otNetworkKey networkKey; - - error = otThreadSetNetworkName(ot_instance, OT_NETWORK_NAME); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "network name", error); - goto exit; - } - - error = otLinkSetChannel(ot_instance, OT_CHANNEL); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "channel", error); - goto exit; - } - - error = otLinkSetPanId(ot_instance, OT_PANID); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "PAN ID", error); - goto exit; - } - - net_bytes_from_str(xpanid.m8, 8, (char *)OT_XPANID); - error = otThreadSetExtendedPanId(ot_instance, &xpanid); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "ext PAN ID", error); - goto exit; - } - - if (strlen(OT_NETWORKKEY)) { - net_bytes_from_str(networkKey.m8, OT_NETWORK_KEY_SIZE, - (char *)OT_NETWORKKEY); - error = otThreadSetNetworkKey(ot_instance, &networkKey); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to set %s [%d]", "network key", error); - goto exit; - } - } - } - - NET_INFO("Network name: %s", - otThreadGetNetworkName(ot_instance)); - - /* Start the network. */ - error = otThreadSetEnabled(ot_instance, true); - if (error != OT_ERROR_NONE) { - NET_ERR("Failed to start the OpenThread network [%d]", error); - } - -exit: - - openthread_api_mutex_unlock(ot_context); - - return error == OT_ERROR_NONE ? 0 : -EIO; -} - -int openthread_stop(struct openthread_context *ot_context) -{ - otError error; - - if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { - return 0; - } - - openthread_api_mutex_lock(ot_context); - - error = otThreadSetEnabled(ot_context->instance, false); - if (error == OT_ERROR_INVALID_STATE) { - NET_DBG("Openthread interface was not up [%d]", error); - } - - openthread_api_mutex_unlock(ot_context); - - return 0; -} - -static int openthread_init(struct net_if *iface) -{ - struct openthread_context *ot_context = net_if_l2_data(iface); - struct k_work_queue_config q_cfg = { - .name = "openthread", - .no_yield = true, - }; - otError err = OT_ERROR_NONE; - - NET_DBG("openthread_init"); - - k_mutex_init(&ot_context->api_lock); - k_work_init(&ot_context->api_work, openthread_process); + ot_l2_state_changed_cb.otCallback = ot_l2_state_changed_handler; + ot_l2_state_changed_cb.user_data = (void *)ot_l2_context; ll_addr = net_if_get_link_addr(iface); - openthread_api_mutex_lock(ot_context); - - otSysInit(0, NULL); - - ot_context->instance = otInstanceInitSingle(); - ot_context->iface = iface; - - __ASSERT(ot_context->instance, "OT instance is NULL"); - - if (IS_ENABLED(CONFIG_OPENTHREAD_SHELL)) { - platformShellInit(ot_context->instance); + error = openthread_init(); + if (error) { + return error; } - if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { - err = otPlatUartEnable(); - if (err != OT_ERROR_NONE) { - NET_ERR("Failed to enable UART: [%d]", err); - } - - otNcpHdlcInit(ot_context->instance, ncp_hdlc_send); - } else { - otIp6SetReceiveFilterEnabled(ot_context->instance, true); - otIp6SetReceiveCallback(ot_context->instance, - ot_receive_handler, ot_context); - -#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) - - otIp4Cidr nat64_cidr; + ot_l2_context->iface = iface; - if (otIp4CidrFromString(CONFIG_OPENTHREAD_NAT64_CIDR, &nat64_cidr) == - OT_ERROR_NONE) { - if (otNat64SetIp4Cidr(openthread_get_default_instance(), &nat64_cidr) != - OT_ERROR_NONE) { - NET_ERR("Incorrect NAT64 CIDR"); - } - } else { - NET_ERR("Failed to parse NAT64 CIDR"); - } - otNat64SetReceiveIp4Callback(ot_context->instance, ot_receive_handler, ot_context); - -#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ - - sys_slist_init(&ot_context->state_change_cbs); - err = otSetStateChangedCallback(ot_context->instance, - &ot_state_changed_handler, - ot_context); - if (err != OT_ERROR_NONE) { - NET_ERR("Could not set state changed callback: %d", err); - } - - net_mgmt_init_event_callback( - &ip6_addr_cb, ipv6_addr_event_handler, - NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_MADDR_ADD); + if (!IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + net_mgmt_init_event_callback(&ip6_addr_cb, ipv6_addr_event_handler, + NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_MADDR_ADD); net_mgmt_add_event_callback(&ip6_addr_cb); - net_if_dormant_on(iface); - } - - openthread_api_mutex_unlock(ot_context); - k_work_queue_start(&ot_context->work_q, ot_stack_area, - K_KERNEL_STACK_SIZEOF(ot_stack_area), - OT_PRIORITY, &q_cfg); + openthread_set_receive_cb(ot_receive_handler, (void *)ot_l2_context); - (void)k_work_submit_to_queue(&ot_context->work_q, &ot_context->api_work); + /* To keep backward compatibility use the additional state change callback list from + * the ot l2 context and register the callback to the openthread module. + */ + sys_slist_init(&ot_l2_context->state_change_cbs); + openthread_state_changed_callback_register(&ot_l2_state_changed_cb); + } - return (err == OT_ERROR_NONE) ? 0 : -EIO; + return error; } void ieee802154_init(struct net_if *iface) { if (IS_ENABLED(CONFIG_IEEE802154_NET_IF_NO_AUTO_START)) { - LOG_DBG("Interface auto start disabled."); net_if_flag_set(iface, NET_IF_NO_AUTO_START); } net_if_flag_set(iface, NET_IF_IPV6_NO_ND); net_if_flag_set(iface, NET_IF_IPV6_NO_MLD); - openthread_init(iface); + int error = openthread_l2_init(iface); + + if (error) { + NET_ERR("Failed to initialize OpenThread L2"); + } } static enum net_l2_flags openthread_flags(struct net_if *iface) @@ -683,20 +329,17 @@ static enum net_l2_flags openthread_flags(struct net_if *iface) static int openthread_enable(struct net_if *iface, bool state) { - struct openthread_context *ot_context = net_if_l2_data(iface); - - NET_DBG("iface %p %s", iface, state ? "up" : "down"); + LOG_DBG("iface %p %s", iface, state ? "up" : "down"); if (state) { if (IS_ENABLED(CONFIG_OPENTHREAD_MANUAL_START)) { - NET_DBG("OpenThread manual start."); return 0; } - return openthread_start(ot_context); + return openthread_run(); } - return openthread_stop(ot_context); + return openthread_stop(); } struct openthread_context *openthread_get_default_context(void) @@ -720,14 +363,44 @@ struct openthread_context *openthread_get_default_context(void) return ot_context; } -struct otInstance *openthread_get_default_instance(void) +/* Keep deprecated functions and forward them to the OpenThread platform module */ +int openthread_start(struct openthread_context *ot_context) { - struct openthread_context *ot_context = - openthread_get_default_context(); + ARG_UNUSED(ot_context); - return ot_context ? ot_context->instance : NULL; + return openthread_run(); } +void openthread_api_mutex_lock(struct openthread_context *ot_context) +{ + /* The mutex is managed internally by the OpenThread module */ + ARG_UNUSED(ot_context); + + openthread_mutex_lock(); +} + +int openthread_api_mutex_try_lock(struct openthread_context *ot_context) +{ + /* The mutex is managed internally by the OpenThread module */ + ARG_UNUSED(ot_context); + + return openthread_mutex_try_lock(); +} + +void openthread_api_mutex_unlock(struct openthread_context *ot_context) +{ + /* The mutex is managed internally by the OpenThread module */ + ARG_UNUSED(ot_context); + + openthread_mutex_unlock(); +} + +/* Keep deprecated state change callback registration functions to keep backward compatibility. + * The callbacks that are registered using these functions are run by the OpenThread module + * as one of the platform callback. However, they will be not supported in the future after + * deprecation period, so it is recommended to switch to + * openthread_state_change_callback_register() instead. + */ int openthread_state_changed_cb_register(struct openthread_context *ot_context, struct openthread_state_changed_cb *cb) { @@ -735,9 +408,9 @@ int openthread_state_changed_cb_register(struct openthread_context *ot_context, return -EINVAL; } - openthread_api_mutex_lock(ot_context); + openthread_mutex_lock(); sys_slist_append(&ot_context->state_change_cbs, &cb->node); - openthread_api_mutex_unlock(ot_context); + openthread_mutex_unlock(); return 0; } @@ -751,9 +424,9 @@ int openthread_state_changed_cb_unregister(struct openthread_context *ot_context return -EINVAL; } - openthread_api_mutex_lock(ot_context); + openthread_mutex_lock(); removed = sys_slist_find_and_remove(&ot_context->state_change_cbs, &cb->node); - openthread_api_mutex_unlock(ot_context); + openthread_mutex_unlock(); if (!removed) { return -EALREADY; @@ -762,25 +435,4 @@ int openthread_state_changed_cb_unregister(struct openthread_context *ot_context return 0; } -void openthread_set_state_changed_cb(otStateChangedCallback cb) -{ - state_changed_cb = cb; -} - -void openthread_api_mutex_lock(struct openthread_context *ot_context) -{ - (void)k_mutex_lock(&ot_context->api_lock, K_FOREVER); -} - -int openthread_api_mutex_try_lock(struct openthread_context *ot_context) -{ - return k_mutex_lock(&ot_context->api_lock, K_NO_WAIT); -} - -void openthread_api_mutex_unlock(struct openthread_context *ot_context) -{ - (void)k_mutex_unlock(&ot_context->api_lock); -} - -NET_L2_INIT(OPENTHREAD_L2, openthread_recv, openthread_send, openthread_enable, - openthread_flags); +NET_L2_INIT(OPENTHREAD_L2, openthread_recv, openthread_send, openthread_enable, openthread_flags); diff --git a/subsys/net/l2/openthread/openthread_utils.c b/subsys/net/l2/openthread/openthread_utils.c index f9b518725b7..28b8f9f7fe6 100644 --- a/subsys/net/l2/openthread/openthread_utils.c +++ b/subsys/net/l2/openthread/openthread_utils.c @@ -31,7 +31,7 @@ static bool is_mesh_local(struct openthread_context *context, const uint8_t *address) { const otMeshLocalPrefix *ml_prefix = - otThreadGetMeshLocalPrefix(context->instance); + otThreadGetMeshLocalPrefix(openthread_get_default_instance()); return (memcmp(address, ml_prefix->m8, sizeof(ml_prefix->m8)) == 0); } @@ -106,7 +106,7 @@ void add_ipv6_addr_to_zephyr(struct openthread_context *context) const otNetifAddress *address; struct net_if_addr *if_addr; - for (address = otIp6GetUnicastAddresses(context->instance); + for (address = otIp6GetUnicastAddresses(openthread_get_default_instance()); address; address = address->mNext) { if (address->mRloc || is_anycast_locator(address)) { @@ -215,9 +215,9 @@ void add_ipv6_addr_to_ot(struct openthread_context *context, return; } - openthread_api_mutex_lock(context); - error = otIp6AddUnicastAddress(context->instance, &addr); - openthread_api_mutex_unlock(context); + openthread_mutex_lock(); + error = otIp6AddUnicastAddress(openthread_get_default_instance(), &addr); + openthread_mutex_unlock(); if (error != OT_ERROR_NONE) { NET_ERR("Failed to add IPv6 unicast address %s [%d]", @@ -235,9 +235,9 @@ void add_ipv6_maddr_to_ot(struct openthread_context *context, memcpy(&addr, addr6, sizeof(addr)); - openthread_api_mutex_lock(context); - error = otIp6SubscribeMulticastAddress(context->instance, &addr); - openthread_api_mutex_unlock(context); + openthread_mutex_lock(); + error = otIp6SubscribeMulticastAddress(openthread_get_default_instance(), &addr); + openthread_mutex_unlock(); if (error != OT_ERROR_NONE) { NET_ERR("Failed to add IPv6 multicast address %s [%d]", @@ -252,7 +252,7 @@ void add_ipv6_maddr_to_zephyr(struct openthread_context *context) const otNetifMulticastAddress *maddress; struct net_if_mcast_addr *zmaddr; - for (maddress = otIp6GetMulticastAddresses(context->instance); + for (maddress = otIp6GetMulticastAddresses(openthread_get_default_instance()); maddress; maddress = maddress->mNext) { if (net_if_ipv6_maddr_lookup( (struct in6_addr *)(&maddress->mAddress), @@ -306,7 +306,7 @@ void rm_ipv6_addr_from_zephyr(struct openthread_context *context) continue; } - for (address = otIp6GetUnicastAddresses(context->instance); + for (address = otIp6GetUnicastAddresses(openthread_get_default_instance()); address; address = address->mNext) { ot_addr = (struct in6_addr *)(&address->mAddress); @@ -354,7 +354,7 @@ void rm_ipv6_maddr_from_zephyr(struct openthread_context *context) continue; } - for (maddress = otIp6GetMulticastAddresses(context->instance); + for (maddress = otIp6GetMulticastAddresses(openthread_get_default_instance()); maddress; maddress = maddress->mNext) { ot_addr = (struct in6_addr *)(&maddress->mAddress); diff --git a/tests/subsys/openthread/radio_stub.c b/tests/subsys/openthread/radio_stub.c index eca072730cb..40e766970a8 100644 --- a/tests/subsys/openthread/radio_stub.c +++ b/tests/subsys/openthread/radio_stub.c @@ -14,7 +14,7 @@ #include /* OpenThread not enabled here */ -#define CONFIG_OPENTHREAD_L2_LOG_LEVEL LOG_LEVEL_DBG +#define CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL LOG_LEVEL_DBG #define CONFIG_OPENTHREAD_THREAD_PRIORITY 5 #define OT_WORKER_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY)