diff --git a/Makefile.dep b/Makefile.dep index f596f883f685..802f98b2aa5c 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -57,6 +57,10 @@ ifneq (,$(filter gnrc_conn_udp,$(USEMODULE))) USEMODULE += gnrc_udp endif +ifneq (,$(filter gnrc_netapi_mbox,$(USEMODULE))) + USEMODULE += core_mbox +endif + ifneq (,$(filter netdev2_tap,$(USEMODULE))) USEMODULE += netif USEMODULE += netdev2_eth diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index 9e02789345f0..27976a1dab9b 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -12,6 +12,8 @@ PSEUDOMODULES += gnrc_ipv6_router PSEUDOMODULES += gnrc_ipv6_router_default PSEUDOMODULES += gnrc_netdev_default PSEUDOMODULES += gnrc_neterr +PSEUDOMODULES += gnrc_netapi_callbacks +PSEUDOMODULES += gnrc_netapi_mbox PSEUDOMODULES += gnrc_pktbuf PSEUDOMODULES += gnrc_sixlowpan_border_router_default PSEUDOMODULES += gnrc_sixlowpan_default diff --git a/examples/gnrc_networking/udp.c b/examples/gnrc_networking/udp.c index a422934e48a0..f7619a8fc3fa 100644 --- a/examples/gnrc_networking/udp.c +++ b/examples/gnrc_networking/udp.c @@ -94,7 +94,7 @@ static void start_server(char *port_str) uint16_t port; /* check if server is already running */ - if (server.pid != KERNEL_PID_UNDEF) { + if (server.target.pid != KERNEL_PID_UNDEF) { printf("Error: server already running on port %" PRIu32 "\n", server.demux_ctx); return; @@ -106,7 +106,7 @@ static void start_server(char *port_str) return; } /* start server (which means registering pktdump for the chosen port) */ - server.pid = gnrc_pktdump_pid; + server.target.pid = gnrc_pktdump_pid; server.demux_ctx = (uint32_t)port; gnrc_netreg_register(GNRC_NETTYPE_UDP, &server); printf("Success: started UDP server on port %" PRIu16 "\n", port); @@ -115,13 +115,13 @@ static void start_server(char *port_str) static void stop_server(void) { /* check if server is running at all */ - if (server.pid == KERNEL_PID_UNDEF) { + if (server.target.pid == KERNEL_PID_UNDEF) { printf("Error: server was not running\n"); return; } /* stop server */ gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &server); - server.pid = KERNEL_PID_UNDEF; + server.target.pid = KERNEL_PID_UNDEF; puts("Success: stopped UDP server"); } diff --git a/sys/include/net/gnrc/netapi.h b/sys/include/net/gnrc/netapi.h index 52ce4ae7a945..25dc2a41dd73 100644 --- a/sys/include/net/gnrc/netapi.h +++ b/sys/include/net/gnrc/netapi.h @@ -21,6 +21,36 @@ * @file * @brief Generic interface to communicate with GNRC modules * + * @defgroup net_gnrc_netapi_mbox Mailbox IPC extension + * @ingroup net_gnrc_netapi + * @brief @ref core_mbox "Mailbox IPC" extension for @ref net_gnrc_netapi + * @{ + * + * @details The submodule `gnrc_netapi_mbox` provides an extension for + * @ref core_mbox "Mailbox IPC". + * + * To use, add the module `gnrc_netapi_mbox` to the `USEMODULE` macro in your + * application's Makefile: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk} + * USEMODULE += gnrc_netapi_mbox + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * @} + * + * @defgroup net_gnrc_netapi_callbacks Callback extension + * @ingroup net_gnrc_netapi + * @brief Callback extension for @ref net_gnrc_netapi + * @{ + * @details The submodule `gnrc_netapi_callbacks` provides an extension for + * callbacks to run GNRC thread-less. + * + * To use, add the module `gnrc_netapi_callbacks` to the `USEMODULE` macro in + * your application's Makefile: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk} + * USEMODULE += gnrc_netapi_callbacks + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * @} * @author Martine Lenders * @author Hauke Petersen */ diff --git a/sys/include/net/gnrc/netreg.h b/sys/include/net/gnrc/netreg.h index 0b7b48a86f30..e078a51d9c2d 100644 --- a/sys/include/net/gnrc/netreg.h +++ b/sys/include/net/gnrc/netreg.h @@ -27,10 +27,27 @@ #include "net/gnrc/nettype.h" #include "net/gnrc/pkt.h" +#ifdef MODULE_GNRC_NETAPI_MBOX +#include "mbox.h" +#endif + #ifdef __cplusplus extern "C" { #endif +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) || \ + defined(DOXYGEN) +typedef enum { + GNRC_NETREG_TYPE_DEFAULT = 0, +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN) + GNRC_NETREG_TYPE_MBOX, +#endif +#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN) + GNRC_NETREG_TYPE_CB, +#endif +} gnrc_netreg_type_t; +#endif + /** * @brief Demux context value to get all packets of a certain type. * @@ -47,7 +64,72 @@ extern "C" { * * @return An initialized netreg entry */ -#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, pid } +#ifdef MODULE_GNRC_NETAPI_MBOX +#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, \ + GNRC_NETREG_TYPE_DEFAULT, \ + { pid } } +#else +#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, { pid } } +#endif + +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN) +/** + * @brief Initializes a netreg entry statically with mbox + * + * @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context" + * for the netreg entry + * @param[in] mbox Target @ref core_mbox "mailbox" for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_mbox. + * + * @return An initialized netreg entry + */ +#define GNRC_NETREG_ENTRY_INIT_MBOX(demux_ctx, mbox) { NULL, demux_ctx, \ + GNRC_NETREG_TYPE_MBOX, \ + { .mbox = mbox } } +#endif + +#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN) +/** + * @brief Initializes a netreg entry statically with callback + * + * @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context" + * for the netreg entry + * @param[in] cb Target callback for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_callbacks. + * + * @return An initialized netreg entry + */ +#define GNRC_NETREG_ENTRY_INIT_CB(demux_ctx, cbd) { NULL, demux_ctx, \ + GNRC_NETREG_TYPE_CB, \ + { .cbd = cbd } } + +/** + * @brief Packet handler callback for netreg entries with callback. + * + * @pre `cmd` $\in$ { @ref GNRC_NETAPI_MSG_TYPE_RCV, @ref GNRC_NETAPI_MSG_TYPE_SND } + * + * @note Only available with @ref net_gnrc_netapi_callbacks. + * + * @param[in] cmd @ref net_gnrc_netapi command type. Must be either + * @ref GNRC_NETAPI_MSG_TYPE_SND or + * @ref GNRC_NETAPI_MSG_TYPE_RCV + * @param[in] pkt The packet to handle. + * @param[in] ctx Application context. + */ +typedef void (*gnrc_netreg_entry_cb_t)(uint16_t cmd, gnrc_pktsnip_t *pkt, + void *ctx); + +/** + * @brief Callback + Context descriptor + * @note Only available with @ref net_gnrc_netapi_callbacks. + */ +typedef struct { + gnrc_netreg_entry_cb_t cb; /**< the callback */ + void *ctx; /**< application context for the callback */ +} gnrc_netreg_entry_cbd_t; +#endif /** * @brief Entry to the @ref net_gnrc_netreg @@ -68,7 +150,36 @@ typedef struct gnrc_netreg_entry { * ports in UDP/TCP, or similar. */ uint32_t demux_ctx; - kernel_pid_t pid; /**< The PID of the registering thread */ +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) || \ + defined(DOXYGEN) + /** + * @brief Type of the registry entry + * + * @note Only available with @ref net_gnrc_netapi_mbox or + * @ref net_gnrc_netapi_callbacks. + */ + gnrc_netreg_type_t type; +#endif + union { + kernel_pid_t pid; /**< The PID of the registering thread */ +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN) + /** + * @brief Target @ref core_mbox "mailbox" for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_mbox. + */ + mbox_t *mbox; +#endif + +#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN) + /** + * @brief Target callback for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_callbacks. + */ + gnrc_netreg_entry_cbd_t *cbd; +#endif + } target; /**< Target for the registry entry */ } gnrc_netreg_entry_t; /** @@ -91,9 +202,56 @@ static inline void gnrc_netreg_entry_init_pid(gnrc_netreg_entry_t *entry, { entry->next = NULL; entry->demux_ctx = demux_ctx; - entry->pid = pid; +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) + entry->type = GNRC_NETREG_TYPE_DEFAULT; +#endif + entry->target.pid = pid; } +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN) +/** + * @brief Initializes a netreg entry dynamically with mbox + * + * @param[out] entry A netreg entry + * @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context" + * for the netreg entry + * @param[in] mbox Target @ref core_mbox "mailbox" for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_mbox. + */ +static inline void gnrc_netreg_entry_init_mbox(gnrc_netreg_entry_t *entry, + uint32_t demux_ctx, + mbox_t *mbox) +{ + entry->next = NULL; + entry->demux_ctx = demux_ctx; + entry->type = GNRC_NETREG_TYPE_MBOX; + entry->target.mbox = mbox; +} +#endif + +#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN) +/** + * @brief Initializes a netreg entry dynamically with callback + * + * @param[out] entry A netreg entry + * @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context" + * for the netreg entry + * @param[in] mbox Target callback for the registry entry + * + * @note Only available with @ref net_gnrc_netapi_callbacks. + */ +static inline void gnrc_netreg_entry_init_cb(gnrc_netreg_entry_t *entry, + uint32_t demux_ctx, + gnrc_netreg_entry_cbd_t *cbd) +{ + entry->next = NULL; + entry->demux_ctx = demux_ctx; + entry->type = GNRC_NETREG_TYPE_CB; + entry->target.cbd = cbd; +} +#endif + /** * @brief Registers a thread to the registry. * diff --git a/sys/net/gnrc/conn/ip/gnrc_conn_ip.c b/sys/net/gnrc/conn/ip/gnrc_conn_ip.c index b2311b7b2e09..d616f3b01375 100644 --- a/sys/net/gnrc/conn/ip/gnrc_conn_ip.c +++ b/sys/net/gnrc/conn/ip/gnrc_conn_ip.c @@ -52,7 +52,7 @@ int conn_ip_create(conn_ip_t *conn, const void *addr, size_t addr_len, int famil void conn_ip_close(conn_ip_t *conn) { assert(conn->l4_type == GNRC_NETTYPE_UNDEF); - if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) { + if (conn->netreg_entry.target.pid != KERNEL_PID_UNDEF) { gnrc_netreg_unregister(conn->l3_type, &conn->netreg_entry); } } diff --git a/sys/net/gnrc/conn/udp/gnrc_conn_udp.c b/sys/net/gnrc/conn/udp/gnrc_conn_udp.c index fc18a950ced8..89ee02443bba 100644 --- a/sys/net/gnrc/conn/udp/gnrc_conn_udp.c +++ b/sys/net/gnrc/conn/udp/gnrc_conn_udp.c @@ -56,9 +56,9 @@ int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len, void conn_udp_close(conn_udp_t *conn) { assert(conn->l4_type == GNRC_NETTYPE_UDP); - if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) { + if (conn->netreg_entry.target.pid != KERNEL_PID_UNDEF) { gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &conn->netreg_entry); - conn->netreg_entry.pid = KERNEL_PID_UNDEF; + conn->netreg_entry.target.pid = KERNEL_PID_UNDEF; } } diff --git a/sys/net/gnrc/netapi/gnrc_netapi.c b/sys/net/gnrc/netapi/gnrc_netapi.c index a6294cbcabb8..d110ebf34af4 100644 --- a/sys/net/gnrc/netapi/gnrc_netapi.c +++ b/sys/net/gnrc/netapi/gnrc_netapi.c @@ -18,6 +18,7 @@ * @} */ +#include "mbox.h" #include "msg.h" #include "net/gnrc/netreg.h" #include "net/gnrc/pktbuf.h" @@ -74,6 +75,22 @@ static inline int _snd_rcv(kernel_pid_t pid, uint16_t type, gnrc_pktsnip_t *pkt) return ret; } +#ifdef MODULE_GNRC_NETAPI_MBOX +static inline int _snd_rcv_mbox(mbox_t *mbox, uint16_t type, gnrc_pktsnip_t *pkt) +{ + msg_t msg; + /* set the outgoing message's fields */ + msg.type = type; + msg.content.ptr = (void *)pkt; + /* send message */ + int ret = mbox_try_put(mbox, &msg); + if (ret < 1) { + DEBUG("gnrc_netapi: dropped message to %p (was full)\n", mbox); + } + return ret; +} +#endif + int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx, uint16_t cmd, gnrc_pktsnip_t *pkt) { @@ -85,10 +102,42 @@ int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx, gnrc_pktbuf_hold(pkt, numof - 1); while (sendto) { - if (_snd_rcv(sendto->pid, cmd, pkt) < 1) { +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) + int release = 0; + switch (sendto->type) { + case GNRC_NETREG_TYPE_DEFAULT: + if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) { + /* unable to dispatch packet */ + release = 1; + } + break; +#ifdef MODULE_GNRC_NETAPI_MBOX + case GNRC_NETREG_TYPE_MBOX: + if (_snd_rcv_mbox(sendto->target.mbox, cmd, pkt) < 1) { + /* unable to dispatch packet */ + release = 1; + } + break; +#endif +#ifdef MODULE_GNRC_NETAPI_CALLBACKS + case GNRC_NETREG_TYPE_CB: + sendto->target.cbd->cb(cmd, pkt, sendto->target.cbd->ctx); + break; +#endif + default: + /* unknown dispatch type */ + release = 1; + break; + } + if (release) { + gnrc_pktbuf_release(pkt); + } +#else + if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) { /* unable to dispatch packet */ gnrc_pktbuf_release(pkt); } +#endif sendto = gnrc_netreg_getnext(sendto); } } diff --git a/sys/net/gnrc/netreg/gnrc_netreg.c b/sys/net/gnrc/netreg/gnrc_netreg.c index 7effd16f120e..a01c557c7290 100644 --- a/sys/net/gnrc/netreg/gnrc_netreg.c +++ b/sys/net/gnrc/netreg/gnrc_netreg.c @@ -37,8 +37,16 @@ void gnrc_netreg_init(void) int gnrc_netreg_register(gnrc_nettype_t type, gnrc_netreg_entry_t *entry) { +#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) +#ifdef DEVELHELP /* only threads with a message queue are allowed to register at gnrc */ - assert(sched_threads[entry->pid]->msg_array); + assert((entry->type != GNRC_NETREG_TYPE_DEFAULT) || + sched_threads[entry->target.pid]->msg_array); +#endif +#else + /* only threads with a message queue are allowed to register at gnrc */ + assert(sched_threads[entry->target.pid]->msg_array); +#endif if (_INVALID_TYPE(type)) { return -EINVAL; diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index df4e5ab89a7b..29fffd03b5be 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -68,7 +68,7 @@ kernel_pid_t gnrc_rpl_init(kernel_pid_t if_pid) } _me_reg.demux_ctx = ICMPV6_RPL_CTRL; - _me_reg.pid = gnrc_rpl_pid; + _me_reg.target.pid = gnrc_rpl_pid; /* register interest in all ICMPv6 packets */ gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_reg); diff --git a/tests/slip/main.c b/tests/slip/main.c index 6d7299ef9943..89fbaf88c0d4 100644 --- a/tests/slip/main.c +++ b/tests/slip/main.c @@ -36,7 +36,7 @@ int main(void) puts("SLIP test"); /* register pktdump */ - if (dump.pid <= KERNEL_PID_UNDEF) { + if (dump.target.pid <= KERNEL_PID_UNDEF) { puts("Error starting pktdump thread"); return -1; } diff --git a/tests/unittests/tests-netreg/tests-netreg.c b/tests/unittests/tests-netreg/tests-netreg.c index d6b2d8a9a470..b56a68861f9f 100644 --- a/tests/unittests/tests-netreg/tests-netreg.c +++ b/tests/unittests/tests-netreg/tests-netreg.c @@ -45,7 +45,7 @@ static void test_netreg_register__success(void) TEST_ASSERT_EQUAL_INT(0, gnrc_netreg_register(GNRC_NETTYPE_TEST, &entries[0])); TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16))); TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx); - TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->pid); + TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->target.pid); TEST_ASSERT_NULL((gnrc_netreg_getnext(res))); } @@ -66,7 +66,7 @@ void test_netreg_unregister__success2(void) gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[0]); TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16))); TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx); - TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, res->pid); + TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, res->target.pid); gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[1]); TEST_ASSERT_NULL(gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16)); } @@ -80,7 +80,7 @@ void test_netreg_unregister__success3(void) gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[1]); TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16))); TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx); - TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->pid); + TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->target.pid); gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[0]); TEST_ASSERT_NULL(gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16)); }