From 35e5aa88655423c71f94914bfa8b7471776ef9f7 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 13 Mar 2017 11:54:37 +0100 Subject: [PATCH] net/mgmt: Add a function to wait on a event synchronously Instead of creating a handler and a related callback structure on an event_mask: net_mgmt_event_wait() can be used to wait synchronously on such event_mask. The core mgmt part will seamlessly reuse the struct net_mgmt_event_callback so the whole internal notification mechanism is using the same code. Change-Id: I426d782c770e75e5222aa3c5b703172b1f1f2e5e Signed-off-by: Tomasz Bursztyka --- .known-issues/doc/networking.conf | 12 ++++++ include/net/net_mgmt.h | 63 +++++++++++++++++++++++++--- subsys/net/ip/net_mgmt.c | 68 +++++++++++++++++++++++++++++-- tests/net/mgmt/src/mgmt.c | 6 +-- 4 files changed, 138 insertions(+), 11 deletions(-) diff --git a/.known-issues/doc/networking.conf b/.known-issues/doc/networking.conf index b1983411ec..2ed5799d8d 100644 --- a/.known-issues/doc/networking.conf +++ b/.known-issues/doc/networking.conf @@ -47,3 +47,15 @@ ^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+] ^.*dns_context.address ^[- \t]*\^ +# +# include/net/net_mgmt.h +# +^(?P[-._/\w]+/doc/api/networking.rst):(?P[0-9]+): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+] +^[ \t]* +^[ \t]*\^ +^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+] +^[ \t]* +^[ \t]*\^ +^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+] +^.*net_mgmt_event_callback.__unnamed__ +^[- \t]*\^ diff --git a/include/net/net_mgmt.h b/include/net/net_mgmt.h index 78788ec776..b7e59bef76 100644 --- a/include/net/net_mgmt.h +++ b/include/net/net_mgmt.h @@ -29,11 +29,13 @@ struct net_if; #define NET_MGMT_EVENT_MASK 0x80000000 #define NET_MGMT_ON_IFACE_MASK 0x40000000 #define NET_MGMT_LAYER_MASK 0x30000000 -#define NET_MGMT_LAYER_CODE_MASK 0x0FFF0000 +#define NET_MGMT_SYNC_EVENT_MASK 0x08000000 +#define NET_MGMT_LAYER_CODE_MASK 0x07FF0000 #define NET_MGMT_COMMAND_MASK 0x0000FFFF #define NET_MGMT_EVENT_BIT BIT(31) #define NET_MGMT_IFACE_BIT BIT(30) +#define NET_MGMT_SYNC_EVENT_BIT BIT(27) #define NET_MGMT_LAYER(_layer) (_layer << 28) #define NET_MGMT_LAYER_CODE(_code) (_code << 16) @@ -44,6 +46,9 @@ struct net_if; #define NET_MGMT_ON_IFACE(mgmt_request) \ (mgmt_request & NET_MGMT_ON_IFACE_MASK) +#define NET_MGMT_EVENT_SYNCHRONOUS(mgmt_request) \ + (mgmt_request & NET_MGMT_SYNC_EVENT_MASK) + #define NET_MGMT_GET_LAYER(mgmt_request) \ ((mgmt_request & NET_MGMT_LAYER_MASK) >> 28) @@ -115,16 +120,33 @@ struct net_mgmt_event_callback { */ sys_snode_t node; - /** Actual callback function being used to notify the owner - */ - net_mgmt_event_handler_t handler; + union { + /** Actual callback function being used to notify the owner + */ + net_mgmt_event_handler_t handler; + /** Semaphore meant to be used internaly for the synchronous + * net_mgmt_event_wait() function. + */ + struct k_sem *sync_call; + }; /** A mask of network events on which the above handler should be * called in case those events come. Such mask can be modified * whenever necessary by the owner, and thus will affect the handler * being called or not. */ - uint32_t event_mask; + union { + /** A mask of network events on which the above handler should + * be called in case those events come. Such mask can be + * modified whenever necessary by the owner, and thus will + * affect the handler being called or not. + */ + uint32_t event_mask; + /** Internal place holder when a synchronous event wait is + * successfully unlocked on a event. + */ + uint32_t raised_event; + }; }; #ifdef CONFIG_NET_MGMT_EVENT @@ -166,6 +188,28 @@ void net_mgmt_del_event_callback(struct net_mgmt_event_callback *cb); */ void net_mgmt_event_notify(uint32_t mgmt_event, struct net_if *iface); +/** + * @brief Used to wait synchronously on an event mask + * @param mgmt_event_mask A mask of relevant events to wait on. + * @param raised_event a pointer on a uint32_t to get which event from + * the mask generated the event. Can be NULL if the caller is not + * interested in that information. + * @param iface a pointer on a place holder for the iface on which the + * event has originated from. This is valid if only the event mask + * has bit NET_MGMT_IFACE_BIT set relevantly, depending on events + * the caller wants to listen to. + * @param timeout a delay in milliseconds. K_FOREVER can be used to wait + * undefinitely. + * + * @return 0 on success, a negative error code otherwise. -ETIMEDOUT will + * be specifically returned if the timeout kick-in instead of an + * actual event. + */ +int net_mgmt_event_wait(uint32_t mgmt_event_mask, + uint32_t *raised_event, + struct net_if **iface, + int timeout); + /** * @brief Used by the core of the network stack to initialize the network * event processing. @@ -176,6 +220,15 @@ void net_mgmt_event_init(void); #define net_mgmt_add_event_callback(...) #define net_mgmt_event_notify(...) #define net_mgmt_event_init(...) + +static inline int net_mgmt_event_wait(uint32_t mgmt_event_mask, + uint32_t *raised_event, + struct net_if **iface, + int timeout) +{ + return 0; +} + #endif /* CONFIG_NET_MGMT_EVENT */ /** diff --git a/subsys/net/ip/net_mgmt.c b/subsys/net/ip/net_mgmt.c index 8962f2537b..a967feeb91 100644 --- a/subsys/net/ip/net_mgmt.c +++ b/subsys/net/ip/net_mgmt.c @@ -22,6 +22,11 @@ struct mgmt_event_entry { struct net_if *iface; }; +struct mgmt_event_wait { + struct k_sem sync_call; + struct net_if *iface; +}; + static struct k_sem network_event; NET_STACK_DEFINE(MGMT, mgmt_stack, CONFIG_NET_MGMT_EVENT_STACK_SIZE, CONFIG_NET_MGMT_EVENT_STACK_SIZE); @@ -102,6 +107,7 @@ static inline bool mgmt_is_event_handled(uint32_t mgmt_event) static inline void mgmt_run_callbacks(struct mgmt_event_entry *mgmt_event) { + sys_snode_t *prev = NULL; struct net_mgmt_event_callback *cb, *tmp; NET_DBG("Event layer %u code %u type %u", @@ -110,10 +116,30 @@ static inline void mgmt_run_callbacks(struct mgmt_event_entry *mgmt_event) NET_MGMT_GET_COMMAND(mgmt_event->event)); SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&event_callbacks, cb, tmp, node) { - NET_DBG("Running callback %p : %p", cb, cb->handler); - if ((mgmt_event->event & cb->event_mask) == mgmt_event->event) { - cb->handler(cb, mgmt_event->event, mgmt_event->iface); + if (NET_MGMT_EVENT_SYNCHRONOUS(cb->event_mask)) { + struct mgmt_event_wait *sync_data = + CONTAINER_OF(cb->sync_call, + struct mgmt_event_wait, + sync_call); + + NET_DBG("Unlocking %p synchronous call", cb); + + cb->raised_event = mgmt_event->event; + sync_data->iface = mgmt_event->iface; + + k_sem_give(cb->sync_call); + + sys_slist_remove(&event_callbacks, + prev, &cb->node); + } else { + NET_DBG("Running callback %p : %p", + cb, cb->handler); + + cb->handler(cb, mgmt_event->event, + mgmt_event->iface); + prev = &cb->node; + } } #ifdef CONFIG_NET_DEBUG_MGMT_EVENT_STACK @@ -186,6 +212,42 @@ void net_mgmt_event_notify(uint32_t mgmt_event, struct net_if *iface) } } +int net_mgmt_event_wait(uint32_t mgmt_event_mask, + uint32_t *raised_event, + struct net_if **iface, + int timeout) +{ + struct mgmt_event_wait sync_data = { + .sync_call = K_SEM_INITIALIZER(sync_data.sync_call, 0, 1), + }; + struct net_mgmt_event_callback sync = { + .sync_call = &sync_data.sync_call, + .event_mask = mgmt_event_mask | NET_MGMT_SYNC_EVENT_BIT, + }; + int ret; + + NET_DBG("Synchronous event wait %p", &cb); + + net_mgmt_add_event_callback(&sync); + + ret = k_sem_take(sync.sync_call, timeout); + if (ret == -EAGAIN) { + ret = -ETIMEDOUT; + } else { + if (!ret) { + if (raised_event) { + *raised_event = sync.raised_event; + } + + if (iface) { + *iface = sync_data.iface; + } + } + } + + return ret; +} + void net_mgmt_event_init(void) { sys_slist_init(&event_callbacks); diff --git a/tests/net/mgmt/src/mgmt.c b/tests/net/mgmt/src/mgmt.c index 0440f2893c..bc6ddcf50f 100644 --- a/tests/net/mgmt/src/mgmt.c +++ b/tests/net/mgmt/src/mgmt.c @@ -13,9 +13,9 @@ #include #include -#define TEST_MGMT_REQUEST 0x0ABC1234 -#define TEST_MGMT_EVENT 0x8ABC1234 -#define TEST_MGMT_EVENT_UNHANDLED 0x8ABC4321 +#define TEST_MGMT_REQUEST 0x07AB1234 +#define TEST_MGMT_EVENT 0x87AB1234 +#define TEST_MGMT_EVENT_UNHANDLED 0x87AB4321 /* Notifier infra */ static uint32_t event2throw;