From 583545b6627712cd3baa277146421a2d397eadbd Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Mon, 9 Jan 2023 17:57:51 +1100 Subject: [PATCH] net: openthread: Add state change callback list Add a new callback list structure for state change information. These APIs are meant to eventually replace the single callback API provided by openthread_set_state_changed_cb(). This will allow multiple users to gain information about OpenThread stage changes. Note CONFIG_OPENTHREAD_MAX_STATECHANGE_HANDLERS with OpenThread's otSetStateChangedCallback() API can also be used to enable registration of multiple callbacks of this type but this cannot be modified if a certified OpenThread binary is used in the build. Signed-off-by: Nick Ward --- include/zephyr/net/openthread.h | 54 ++++++++++++++++++++++++++ subsys/net/l2/openthread/openthread.c | 55 +++++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/openthread.h b/include/zephyr/net/openthread.h index cc81246d80f..a113dd1638a 100644 --- a/include/zephyr/net/openthread.h +++ b/include/zephyr/net/openthread.h @@ -68,11 +68,65 @@ struct openthread_context { /** Work object for OpenThread internal usage */ struct k_work api_work; + + /** A list for state change callbacks */ + sys_slist_t state_change_cbs; }; /** * INTERNAL_HIDDEN @endcond */ +/** 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. + * Beware such structure should not be allocated on stack. + */ +struct openthread_state_changed_cb { + /** + * @brief Callback for notifying configuration or state changes. + * + * @param flags as per OpenThread otStateChangedCallback() aFlags parameter. + * See https://openthread.io/reference/group/api-instance#otstatechangedcallback + * @param ot_context the OpenThread context the callback is registered with. + * @param user_data Data to pass to the callback. + */ + void (*state_changed_cb)(otChangedFlags flags, struct openthread_context *ot_context, + void *user_data); + + /** User data if required */ + void *user_data; + + /** + * Internally used field for list handling + * - user must not directly modify + */ + sys_snode_t node; +}; + +/** + * @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); + +/** + * @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); + /** * @brief Sets function which will be called when certain configuration or state * changes within OpenThread. diff --git a/subsys/net/l2/openthread/openthread.c b/subsys/net/l2/openthread/openthread.c index 003c3401295..841736d1f40 100644 --- a/subsys/net/l2/openthread/openthread.c +++ b/subsys/net/l2/openthread/openthread.c @@ -15,6 +15,8 @@ LOG_MODULE_REGISTER(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #include #include +#include +#include #include #include #include @@ -174,6 +176,7 @@ void otSysEventSignalPending(void) static void ot_state_changed_handler(uint32_t flags, void *context) { + struct openthread_state_changed_cb *entry, *next; struct openthread_context *ot_context = context; NET_INFO("State changed! Flags: 0x%08" PRIx32 " Current role: %s", @@ -220,6 +223,12 @@ static void ot_state_changed_handler(uint32_t flags, void *context) 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); + } + } } static void ot_receive_handler(otMessage *aMessage, void *context) @@ -491,11 +500,11 @@ int openthread_stop(struct openthread_context *ot_context) 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; NET_DBG("openthread_init"); @@ -524,9 +533,13 @@ static int openthread_init(struct net_if *iface) otIp6SetReceiveFilterEnabled(ot_context->instance, true); otIp6SetReceiveCallback(ot_context->instance, ot_receive_handler, ot_context); - otSetStateChangedCallback(ot_context->instance, - &ot_state_changed_handler, - ot_context); + 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, @@ -612,6 +625,40 @@ struct otInstance *openthread_get_default_instance(void) return ot_context ? ot_context->instance : NULL; } +int openthread_state_changed_cb_register(struct openthread_context *ot_context, + struct openthread_state_changed_cb *cb) +{ + CHECKIF(cb == NULL || cb->state_changed_cb == NULL) { + return -EINVAL; + } + + openthread_api_mutex_lock(ot_context); + sys_slist_append(&ot_context->state_change_cbs, &cb->node); + openthread_api_mutex_unlock(ot_context); + + return 0; +} + +int openthread_state_changed_cb_unregister(struct openthread_context *ot_context, + struct openthread_state_changed_cb *cb) +{ + bool removed; + + CHECKIF(cb == NULL) { + return -EINVAL; + } + + openthread_api_mutex_lock(ot_context); + removed = sys_slist_find_and_remove(&ot_context->state_change_cbs, &cb->node); + openthread_api_mutex_unlock(ot_context); + + if (!removed) { + return -EALREADY; + } + + return 0; +} + void openthread_set_state_changed_cb(otStateChangedCallback cb) { state_changed_cb = cb;