mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-14 09:03:50 +01:00
gnrc/netapi: add notify message API
The netapi notify API enables protocol-independent, cross-layer notification events. Lower layers in the network stack can use this to inform upper layers of network events.
This commit is contained in:
parent
1d0a275d17
commit
19a4ba04d1
@ -288,6 +288,7 @@
|
||||
|
||||
#include "net/netopt.h"
|
||||
#include "net/gnrc/netapi.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
|
||||
#include "thread.h"
|
||||
#include "net/netopt.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/pkt.h"
|
||||
|
||||
@ -88,10 +89,17 @@ extern "C" {
|
||||
#define GNRC_NETAPI_MSG_TYPE_GET (0x0204)
|
||||
|
||||
/**
|
||||
* @brief @ref core_msg type for replying to get and set option messages
|
||||
* @brief @ref core_msg type for replying to get/set option, and notify messages
|
||||
*/
|
||||
#define GNRC_NETAPI_MSG_TYPE_ACK (0x0205)
|
||||
|
||||
/**
|
||||
* @brief @ref core_msg type for sending a general event notifications to one or more subscribers
|
||||
*
|
||||
* This sends back a @ref GNRC_NETAPI_MSG_TYPE_ACK, so it should be used with `msg_send_receive()`.
|
||||
*/
|
||||
#define GNRC_NETAPI_MSG_TYPE_NOTIFY (0x0207)
|
||||
|
||||
/**
|
||||
* @brief Data structure to be send for setting (@ref GNRC_NETAPI_MSG_TYPE_SET)
|
||||
* and getting (@ref GNRC_NETAPI_MSG_TYPE_GET) options
|
||||
@ -183,6 +191,24 @@ static inline int gnrc_netapi_dispatch_send(gnrc_nettype_t type, uint32_t demux_
|
||||
return gnrc_netapi_dispatch(type, demux_ctx, GNRC_NETAPI_MSG_TYPE_SND, pkt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a @ref GNRC_NETAPI_MSG_TYPE_NOTIFY command to all subscribers to
|
||||
* (@p type, @p demux_ctx).
|
||||
*
|
||||
* @note This blocks the sender until all registered subscribers have ack'ed the notification
|
||||
* or sending has failed. The @p data can be freed after the function returned.
|
||||
*
|
||||
* @param[in] type Type of the targeted network module.
|
||||
* @param[in] demux_ctx Demultiplexing context for @p type.
|
||||
* @param[in] event Notification event type.
|
||||
* @param[in] data Data associated with the event.
|
||||
* @param[in] data_len Size of @p data.
|
||||
*
|
||||
* @return Number of subscribers to (@p type, @p demux_ctx).
|
||||
*/
|
||||
int gnrc_netapi_notify(gnrc_nettype_t type, uint32_t demux_ctx, netapi_notify_t event,
|
||||
void *data, size_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Shortcut function for sending @ref GNRC_NETAPI_MSG_TYPE_RCV messages
|
||||
*
|
||||
|
||||
91
sys/include/net/gnrc/netapi/notify.h
Normal file
91
sys/include/net/gnrc/netapi/notify.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_netapi_notify Notification events for network APIs.
|
||||
* @ingroup net_gnrc_netapi
|
||||
* @brief Network event notification types.
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Network event notification type definitions.
|
||||
*
|
||||
* @details The purpose of this API is to allow lower layers in the network
|
||||
* stack to inform higher layers of general, protocol-independent
|
||||
* network events.
|
||||
* It can be used through the @ref net_gnrc_netapi to notify any
|
||||
* other network interfaces that have registered themselves through
|
||||
* @ref net_gnrc_netreg for the corresponding @ref net_gnrc_nettype.
|
||||
*
|
||||
* @note Notification events are associated with type-dependent event data.
|
||||
* Receivers should not access the data directly, but instead use the
|
||||
* the dedicated API functions to copy the data from the sender's.
|
||||
* If the data is read manually, the receiver is responsible for
|
||||
* calling @ref gnrc_netapi_notify_ack to unblock the sender.
|
||||
*
|
||||
* @author Elena Frank <elena.frank@tu-dresden.de>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "net/gnrc/netif/conf.h"
|
||||
#include "sema_inv.h"
|
||||
|
||||
/**
|
||||
* @brief Definition of notification event types in the network stack.
|
||||
*
|
||||
* @note Expand at will.
|
||||
* If event data is associated with the type, a helper function must also
|
||||
* be added for parsing the data and calling @ref gnrc_netapi_notify_ack.
|
||||
*/
|
||||
typedef enum {
|
||||
PLACEHOLDER
|
||||
} netapi_notify_t;
|
||||
|
||||
/**
|
||||
* @brief Data structure to be sent for netapi notification events.
|
||||
*/
|
||||
typedef struct {
|
||||
netapi_notify_t event; /**< the type of event */
|
||||
void *_data; /**< associated event data. */
|
||||
uint16_t _data_len; /**< size of the event data */
|
||||
sema_inv_t ack; /**< inverse semaphore for collecting ack's */
|
||||
} gnrc_netapi_notify_t;
|
||||
|
||||
/**
|
||||
* @brief Acknowledge that a notify event was received and its data read.
|
||||
*
|
||||
* @param[in] ack Pointer to semaphore that is used to collect ack's.
|
||||
*/
|
||||
static inline void gnrc_netapi_notify_ack(sema_inv_t *ack)
|
||||
{
|
||||
sema_inv_post(ack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy the connection event data associated with a @ref gnrc_netapi_notify_t event.
|
||||
*
|
||||
* @note This will call @ref gnrc_netapi_notify_ack.
|
||||
*
|
||||
* @param[in] notify Pointer to the received notify event.
|
||||
* @param[in] data_len Size of the expected data type.
|
||||
* @param[out] data Connection data received in the @p notify event.
|
||||
*
|
||||
* @retval Size of the data type on success.
|
||||
* @retval -EINVAL if the data in @p notify is invalid or doesn't match the expected
|
||||
* data length.
|
||||
*/
|
||||
int gnrc_netapi_notify_copy_event_data(gnrc_netapi_notify_t *notify, uint8_t data_len, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@ -330,7 +330,8 @@ static inline void gnrc_netreg_entry_init_cb(gnrc_netreg_entry_t *entry,
|
||||
* @brief Registers a thread to the registry.
|
||||
*
|
||||
* @details The semantics are: Thread gnrc_netreg_entry_t::pid is interested in
|
||||
* packets of protocol @p type with context gnrc_netreg_entry_t::demux_ctx.
|
||||
* packets or network events of protocol @p type with context
|
||||
* gnrc_netreg_entry_t::demux_ctx.
|
||||
*
|
||||
* @param[in] type Type of the protocol. Must not be < GNRC_NETTYPE_UNDEF or
|
||||
* >= GNRC_NETTYPE_NUMOF.
|
||||
|
||||
@ -120,6 +120,20 @@ typedef enum {
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Cross-layer network events.
|
||||
*
|
||||
* @brief Subscription types for protocol-independent events.
|
||||
* They are used by lower-layers in the network stack to published
|
||||
* information about the network state.
|
||||
*
|
||||
* @details See @ref net_gnrc_netapi_notify.
|
||||
* }
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Testing
|
||||
|
||||
@ -43,6 +43,9 @@ endif
|
||||
ifneq (,$(filter gnrc_netapi,$(USEMODULE)))
|
||||
DIRS += netapi
|
||||
endif
|
||||
ifneq (,$(filter gnrc_netapi_notify,$(USEMODULE)))
|
||||
DIRS += netapi/notify
|
||||
endif
|
||||
ifneq (,$(filter gnrc_netif gnrc_netif_%,$(USEMODULE)))
|
||||
DIRS += netif
|
||||
endif
|
||||
|
||||
@ -55,7 +55,7 @@ ifneq (,$(filter gnrc_uhcpc,$(USEMODULE)))
|
||||
USEMODULE += fmt
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_%,$(filter-out gnrc_lorawan gnrc_lorawan_1_1 gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pkt%,$(USEMODULE))))
|
||||
ifneq (,$(filter gnrc_%,$(filter-out gnrc_lorawan gnrc_lorawan_1_1 gnrc_netapi gnrc_netapi_notify gnrc_netreg gnrc_netif% gnrc_pkt%,$(USEMODULE))))
|
||||
USEMODULE += gnrc
|
||||
endif
|
||||
|
||||
@ -460,6 +460,10 @@ ifneq (,$(filter gnrc,$(USEMODULE)))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_netapi_notify,$(USEMODULE)))
|
||||
USEMODULE += sema_inv
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_pktbuf, $(USEMODULE)))
|
||||
ifeq (,$(filter gnrc_pktbuf_%, $(USEMODULE)))
|
||||
USEMODULE += gnrc_pktbuf_static
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#include "mbox.h"
|
||||
#include "msg.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
#include "net/gnrc/netapi.h"
|
||||
#include "sema_inv.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
@ -82,6 +84,42 @@ static inline int _snd_rcv_mbox(mbox_t *mbox, uint16_t type, gnrc_pktsnip_t *pkt
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _dispatch_single(gnrc_netreg_entry_t *sendto, uint16_t cmd, void *data)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS)
|
||||
switch (sendto->type) {
|
||||
case GNRC_NETREG_TYPE_DEFAULT:
|
||||
if (_gnrc_netapi_send_recv(sendto->target.pid, data, cmd) < 1) {
|
||||
/* unable to dispatch packet */
|
||||
status = -EIO;
|
||||
}
|
||||
break;
|
||||
# ifdef MODULE_GNRC_NETAPI_MBOX
|
||||
case GNRC_NETREG_TYPE_MBOX:
|
||||
if (_snd_rcv_mbox(sendto->target.mbox, cmd, data) < 1) {
|
||||
/* unable to dispatch packet */
|
||||
status = -EIO;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
# ifdef MODULE_GNRC_NETAPI_CALLBACKS
|
||||
case GNRC_NETREG_TYPE_CB:
|
||||
sendto->target.cbd->cb(cmd, data, sendto->target.cbd->ctx);
|
||||
break;
|
||||
# endif
|
||||
default:
|
||||
/* unknown dispatch type */
|
||||
status = -ECANCELED;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
status = _gnrc_netapi_send_recv(sendto->target.pid, data, cmd);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
|
||||
uint16_t cmd, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
@ -96,43 +134,10 @@ int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
|
||||
gnrc_pktbuf_hold(pkt, numof - 1);
|
||||
|
||||
while (sendto) {
|
||||
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS)
|
||||
uint32_t status = 0;
|
||||
switch (sendto->type) {
|
||||
case GNRC_NETREG_TYPE_DEFAULT:
|
||||
if (_gnrc_netapi_send_recv(sendto->target.pid, pkt,
|
||||
cmd) < 1) {
|
||||
/* unable to dispatch packet */
|
||||
status = EIO;
|
||||
}
|
||||
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 */
|
||||
status = EIO;
|
||||
}
|
||||
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 */
|
||||
status = ECANCELED;
|
||||
break;
|
||||
}
|
||||
if (status != 0) {
|
||||
int status = _dispatch_single(sendto, cmd, pkt);
|
||||
if (status < 0) {
|
||||
gnrc_pktbuf_release_error(pkt, status);
|
||||
}
|
||||
#else
|
||||
if (_gnrc_netapi_send_recv(sendto->target.pid, pkt, cmd) < 1) {
|
||||
/* unable to dispatch packet */
|
||||
gnrc_pktbuf_release_error(pkt, EIO);
|
||||
}
|
||||
#endif
|
||||
sendto = gnrc_netreg_getnext(sendto);
|
||||
}
|
||||
}
|
||||
@ -141,3 +146,48 @@ int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
|
||||
|
||||
return numof;
|
||||
}
|
||||
|
||||
int gnrc_netapi_notify(gnrc_nettype_t type, uint32_t demux_ctx, netapi_notify_t event,
|
||||
void *data, size_t data_len)
|
||||
{
|
||||
gnrc_netreg_acquire_shared();
|
||||
|
||||
int numof = gnrc_netreg_num(type, demux_ctx);
|
||||
if (numof <= 0) {
|
||||
gnrc_netreg_release_shared();
|
||||
return numof;
|
||||
}
|
||||
|
||||
gnrc_netapi_notify_t notify = {
|
||||
.event = event,
|
||||
._data = data,
|
||||
._data_len = data_len,
|
||||
};
|
||||
|
||||
/* Use inverse semaphore to count the acknowledgments from the receivers. */
|
||||
sema_inv_init(¬ify.ack, numof);
|
||||
|
||||
/* Look up the registered threads for this message type. */
|
||||
gnrc_netreg_entry_t *sendto = gnrc_netreg_lookup(type, demux_ctx);
|
||||
|
||||
/* Dispatch to all registered threads. */
|
||||
while (sendto) {
|
||||
int status = _dispatch_single(sendto, GNRC_NETAPI_MSG_TYPE_NOTIFY, ¬ify);
|
||||
if (status < 0) {
|
||||
numof--;
|
||||
/* Decrease semaphore counter manually when sending failed. */
|
||||
sema_inv_post(¬ify.ack);
|
||||
}
|
||||
sendto = gnrc_netreg_getnext(sendto);
|
||||
}
|
||||
|
||||
gnrc_netreg_release_shared();
|
||||
|
||||
if (data != NULL) {
|
||||
/* Wait for ACK from all receivers to ensure that the data was read and
|
||||
* that there won't be any dangling pointers after the function returned. */
|
||||
sema_inv_wait(¬ify.ack);
|
||||
}
|
||||
|
||||
return numof;
|
||||
}
|
||||
|
||||
3
sys/net/gnrc/netapi/notify/Makefile
Normal file
3
sys/net/gnrc/netapi/notify/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_netapi_notify
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
38
sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c
Normal file
38
sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 TU Dresden
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @ingroup net_gnrc_netapi_notify
|
||||
* @file
|
||||
* @brief Helper functions to extract data from netapi notify events.
|
||||
*
|
||||
* @author Elena Frank <elena.frank@tu-dresden.de>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
|
||||
int gnrc_netapi_notify_copy_event_data(gnrc_netapi_notify_t *notify, uint8_t data_len, void *data)
|
||||
{
|
||||
(void) data_len;
|
||||
(void) data;
|
||||
|
||||
int res;
|
||||
|
||||
switch (notify->event) {
|
||||
default:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Acknowledge the read data */
|
||||
gnrc_netapi_notify_ack(¬ify->ack);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
Loading…
x
Reference in New Issue
Block a user