mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-13 16:43:52 +01:00
Merge pull request #21608 from elenaf9/gnrc/netapi/event
gnrc, nimble/ble: notify network layer of BLE connection events
This commit is contained in:
commit
2c01ea02dc
@ -27,6 +27,7 @@
|
||||
|
||||
#include "net/ble.h"
|
||||
#include "net/bluetil/addr.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/util/util.h"
|
||||
#include "mem/mem.h"
|
||||
#include <string.h>
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
@ -331,6 +333,29 @@ end:
|
||||
ble_l2cap_recv_ready(event->receive.chan, rxb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a netapi notification for a connection event.
|
||||
*
|
||||
* @param[in] notify The type of notification event.
|
||||
* @param[in] addr BLE address of the node that (dis-)connected.
|
||||
*/
|
||||
static inline void _dispatch_connection_event(netapi_notify_t notify, const void *addr)
|
||||
{
|
||||
if (!IS_USED(MODULE_GNRC_NETAPI_NOTIFY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
netapi_notify_l2_connection_t event = {
|
||||
.l2addr_len = BLE_ADDR_LEN,
|
||||
.if_pid = _netif.pid,
|
||||
};
|
||||
|
||||
memcpy(event.l2addr, addr, BLE_ADDR_LEN);
|
||||
|
||||
gnrc_netapi_notify(GNRC_NETTYPE_L2_DISCOVERY, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
notify, &event, sizeof(netapi_notify_l2_connection_t));
|
||||
}
|
||||
|
||||
static int _on_l2cap_client_evt(struct ble_l2cap_event *event, void *arg)
|
||||
{
|
||||
int handle = (int)arg;
|
||||
@ -349,6 +374,7 @@ static int _on_l2cap_client_evt(struct ble_l2cap_event *event, void *arg)
|
||||
conn->state |= NIMBLE_NETIF_L2CAP_CLIENT;
|
||||
conn->state &= ~NIMBLE_NETIF_CONNECTING;
|
||||
_notify(handle, NIMBLE_NETIF_CONNECTED_MASTER, conn->addr);
|
||||
_dispatch_connection_event(NETAPI_NOTIFY_L2_NEIGH_CONNECTED, conn->addr);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
assert(conn->state & NIMBLE_NETIF_L2CAP_CLIENT);
|
||||
@ -404,6 +430,7 @@ static int _on_l2cap_server_evt(struct ble_l2cap_event *event, void *arg)
|
||||
}
|
||||
|
||||
_notify(handle, NIMBLE_NETIF_CONNECTED_SLAVE, conn->addr);
|
||||
_dispatch_connection_event(NETAPI_NOTIFY_L2_NEIGH_CONNECTED, conn->addr);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
conn = nimble_netif_conn_from_gaphandle(event->disconnect.conn_handle);
|
||||
@ -498,6 +525,7 @@ static int _on_gap_master_evt(struct ble_gap_event *event, void *arg)
|
||||
nimble_netif_conn_free(handle, addr);
|
||||
thread_flags_set(_netif_thread, FLAG_TX_NOTCONN);
|
||||
_notify(handle, type, addr);
|
||||
_dispatch_connection_event(NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED, addr);
|
||||
break;
|
||||
}
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
@ -542,6 +570,7 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
|
||||
nimble_netif_conn_free(handle, addr);
|
||||
thread_flags_set(_netif_thread, FLAG_TX_NOTCONN);
|
||||
_notify(handle, type, addr);
|
||||
_dispatch_connection_event(NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED, addr);
|
||||
break;
|
||||
}
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
|
||||
@ -222,9 +222,6 @@ static void _on_netif_evt(int handle, nimble_netif_event_t event,
|
||||
case NIMBLE_NETIF_CONNECTED_MASTER:
|
||||
/* parent selected */
|
||||
assert(_current_parent == handle);
|
||||
/* send a DIS once connected to a (new) parent) */
|
||||
gnrc_rpl_send_DIS(NULL, (ipv6_addr_t *) &ipv6_addr_all_rpl_nodes,
|
||||
NULL, 0);
|
||||
break;
|
||||
case NIMBLE_NETIF_CONNECTED_SLAVE:
|
||||
/* child added */
|
||||
|
||||
@ -274,14 +274,14 @@ static inline uint64_t atomic_load_u64(const volatile uint64_t *var);
|
||||
static inline unsigned atomic_load_unsigned(const volatile unsigned *var)
|
||||
{
|
||||
if (sizeof(uint64_t) == sizeof(unsigned)) {
|
||||
return atomic_load_u64((volatile void *)var);
|
||||
return atomic_load_u64((const volatile uint64_t *)(uintptr_t)var);
|
||||
}
|
||||
|
||||
if (sizeof(uint32_t) == sizeof(unsigned)) {
|
||||
return atomic_load_u32((volatile void *)var);
|
||||
return atomic_load_u32((const volatile uint32_t *)(uintptr_t)var);
|
||||
}
|
||||
|
||||
return atomic_load_u16((volatile void *)var);
|
||||
return atomic_load_u16((const volatile uint16_t *)(uintptr_t)var);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -362,13 +362,13 @@ static inline void atomic_store_u64(volatile uint64_t *dest, uint64_t val);
|
||||
static inline void atomic_store_unsigned(volatile unsigned *dest, unsigned val)
|
||||
{
|
||||
if (sizeof(uint64_t) == sizeof(unsigned)) {
|
||||
atomic_store_u64((volatile void *)dest, val);
|
||||
atomic_store_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
else if (sizeof(uint32_t) == sizeof(unsigned)) {
|
||||
atomic_store_u32((volatile void *)dest, val);
|
||||
atomic_store_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
else {
|
||||
atomic_store_u16((volatile void *)dest, val);
|
||||
atomic_store_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,14 +462,14 @@ static inline unsigned atomic_fetch_add_unsigned(volatile unsigned *dest,
|
||||
unsigned summand)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return atomic_fetch_add_u64((volatile void *)dest, summand);
|
||||
return atomic_fetch_add_u64((volatile uint64_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return atomic_fetch_add_u32((volatile void *)dest, summand);
|
||||
return atomic_fetch_add_u32((volatile uint32_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
|
||||
return atomic_fetch_add_u16((volatile void *)dest, summand);
|
||||
return atomic_fetch_add_u16((volatile uint16_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -528,14 +528,14 @@ static inline unsigned atomic_fetch_sub_unsigned(volatile unsigned *dest,
|
||||
unsigned subtrahend)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return atomic_fetch_sub_u64((volatile void *)dest, subtrahend);
|
||||
return atomic_fetch_sub_u64((volatile uint64_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return atomic_fetch_sub_u32((volatile void *)dest, subtrahend);
|
||||
return atomic_fetch_sub_u32((volatile uint32_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
|
||||
return atomic_fetch_sub_u16((volatile void *)dest, subtrahend);
|
||||
return atomic_fetch_sub_u16((volatile uint16_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -593,14 +593,14 @@ static inline unsigned atomic_fetch_or_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return atomic_fetch_or_u64((volatile void *)dest, val);
|
||||
return atomic_fetch_or_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return atomic_fetch_or_u32((volatile void *)dest, val);
|
||||
return atomic_fetch_or_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return atomic_fetch_or_u16((volatile void *)dest, val);
|
||||
return atomic_fetch_or_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -658,14 +658,14 @@ static inline unsigned atomic_fetch_xor_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return atomic_fetch_xor_u64((volatile void *)dest, val);
|
||||
return atomic_fetch_xor_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return atomic_fetch_xor_u32((volatile void *)dest, val);
|
||||
return atomic_fetch_xor_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return atomic_fetch_xor_u16((volatile void *)dest, val);
|
||||
return atomic_fetch_xor_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -723,14 +723,14 @@ static inline unsigned atomic_fetch_and_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return atomic_fetch_and_u64((volatile void *)dest, val);
|
||||
return atomic_fetch_and_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return atomic_fetch_and_u32((volatile void *)dest, val);
|
||||
return atomic_fetch_and_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return atomic_fetch_and_u16((volatile void *)dest, val);
|
||||
return atomic_fetch_and_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -935,14 +935,14 @@ static inline unsigned semi_atomic_fetch_add_unsigned(volatile unsigned *dest,
|
||||
unsigned summand)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return semi_atomic_fetch_add_u64((volatile void *)dest, summand);
|
||||
return semi_atomic_fetch_add_u64((volatile uint64_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return semi_atomic_fetch_add_u32((volatile void *)dest, summand);
|
||||
return semi_atomic_fetch_add_u32((volatile uint32_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
|
||||
return semi_atomic_fetch_add_u16((volatile void *)dest, summand);
|
||||
return semi_atomic_fetch_add_u16((volatile uint16_t *)(uintptr_t)dest, summand);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -1001,14 +1001,14 @@ static inline unsigned semi_atomic_fetch_sub_unsigned(volatile unsigned *dest,
|
||||
unsigned subtrahend)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return semi_atomic_fetch_sub_u64((volatile void *)dest, subtrahend);
|
||||
return semi_atomic_fetch_sub_u64((volatile uint64_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return semi_atomic_fetch_sub_u32((volatile void *)dest, subtrahend);
|
||||
return semi_atomic_fetch_sub_u32((volatile uint32_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
|
||||
return semi_atomic_fetch_sub_u16((volatile void *)dest, subtrahend);
|
||||
return semi_atomic_fetch_sub_u16((volatile uint16_t *)(uintptr_t)dest, subtrahend);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -1066,14 +1066,14 @@ static inline unsigned semi_atomic_fetch_or_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return semi_atomic_fetch_or_u64((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_or_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return semi_atomic_fetch_or_u32((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_or_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return semi_atomic_fetch_or_u16((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_or_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -1132,14 +1132,14 @@ static inline unsigned semi_atomic_fetch_xor_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return semi_atomic_fetch_xor_u64((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_xor_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return semi_atomic_fetch_xor_u32((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_xor_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return semi_atomic_fetch_xor_u16((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_xor_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -1198,14 +1198,14 @@ static inline unsigned semi_atomic_fetch_and_unsigned(volatile unsigned *dest,
|
||||
unsigned val)
|
||||
{
|
||||
if (sizeof(unsigned) == sizeof(uint64_t)) {
|
||||
return semi_atomic_fetch_and_u64((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_and_u64((volatile uint64_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
if (sizeof(unsigned) == sizeof(uint32_t)) {
|
||||
return semi_atomic_fetch_and_u32((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_and_u32((volatile uint32_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
|
||||
return semi_atomic_fetch_and_u16((volatile void *)dest, val);
|
||||
return semi_atomic_fetch_and_u16((volatile uint16_t *)(uintptr_t)dest, val);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -233,6 +233,36 @@ static inline unsigned gnrc_ipv6_nib_nc_get_ar_state(const gnrc_ipv6_nib_nc_t *e
|
||||
int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface,
|
||||
const uint8_t *l2addr, size_t l2addr_len);
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Adds an unmanaged neighbor entry to the NIB if the interface represents a 6LN node
|
||||
* and the IPv6 address can be constructed from the L2 address @p l2addr.
|
||||
*
|
||||
* @param[in] iface The interface to the neighbor.
|
||||
* @param[in] l2addr The neighbor's layer 2 address.
|
||||
* @param[in] l2addr_len Length of @p l2addr.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -ENOTSUP if the interface does not represent a 6LN or when
|
||||
* gnrc_netif_t::device_type of the iface does not support IID conversion.
|
||||
* @retval -EINVAL when @p addr_len is invalid for the
|
||||
* gnrc_netif_t::device_type of @p netif.
|
||||
* @retval -ENOMEM if no space is left in neighbor cache.
|
||||
*/
|
||||
int gnrc_ipv6_nib_nc_set_6ln(unsigned iface, const uint8_t *l2addr,
|
||||
size_t l2addr_len);
|
||||
#else /* CONFIG_GNRC_IPV6_NIB_6LN */
|
||||
static inline int gnrc_ipv6_nib_nc_set_6ln(unsigned iface, const uint8_t *l2addr,
|
||||
size_t l2addr_len)
|
||||
{
|
||||
(void)iface;
|
||||
(void)l2addr;
|
||||
(void)l2addr_len;
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_6LN */
|
||||
|
||||
/**
|
||||
* @brief Deletes neighbor with address @p ipv6 from NIB
|
||||
*
|
||||
@ -245,6 +275,23 @@ int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface,
|
||||
*/
|
||||
void gnrc_ipv6_nib_nc_del(const ipv6_addr_t *ipv6, unsigned iface);
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ARSM) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Deletes neighbor with link-layer address @p l2addr from NIB.
|
||||
*
|
||||
* @param[in] iface The interface to the neighbor.
|
||||
* @param[in] l2addr The neighbor's l2addr address.
|
||||
* @param[in] l2addr_len Length of @p l2addr.
|
||||
*
|
||||
*
|
||||
* If the @p l2addr can't be found for a neighbor in the NIB nothing happens.
|
||||
*
|
||||
* @retval True if a neighbor with @p l2addr existed.
|
||||
* @retval False otherwise.
|
||||
*/
|
||||
bool gnrc_ipv6_nib_nc_del_l2(unsigned iface, const uint8_t *l2addr, size_t l2addr_len);
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_ARSM */
|
||||
|
||||
/**
|
||||
* @brief Mark neighbor with address @p ipv6 as reachable
|
||||
*
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
104
sys/include/net/gnrc/netapi/notify.h
Normal file
104
sys/include/net/gnrc/netapi/notify.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 {
|
||||
NETAPI_NOTIFY_L2_NEIGH_CONNECTED, /**< Connection established on layer 2. */
|
||||
NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED, /**< Connection closed on layer 2. */
|
||||
NETAPI_NOTIFY_L3_DISCOVERED, /**< Discovered node on the network layer. */
|
||||
NETAPI_NOTIFY_L3_UNREACHABLE, /**< Node became unreachable on the network layer. */
|
||||
} 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 L2 connection event data associated with @ref NETAPI_NOTIFY_L2_NEIGH_CONNECTED or
|
||||
* @ref NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED events.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t l2addr[GNRC_NETIF_L2ADDR_MAXLEN]; /**< L2 address of the node */
|
||||
uint8_t l2addr_len; /**< length of L2 address in byte */
|
||||
kernel_pid_t if_pid; /**< PID of network interface */
|
||||
} netapi_notify_l2_connection_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,36 @@ 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.
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reports the reachability of link-layer neighbors.
|
||||
* Connection-oriented links such as BLE can use this to inform
|
||||
* the IPv6-layer, e.g., about new connected or disconnected nodes
|
||||
* and their l2 address.
|
||||
*/
|
||||
GNRC_NETTYPE_L2_DISCOVERY,
|
||||
/**
|
||||
* @brief Reports routing-relevant information, e.g., discovered or
|
||||
* unreachable nodes, from the IPv6-layer to routing protocol like
|
||||
* RPL.
|
||||
*
|
||||
* @note Compared to @ref GNRC_NETTYPE_L2_DISCOVERY, events published to
|
||||
* this type include the IPv6 address of the node.
|
||||
*/
|
||||
GNRC_NETTYPE_L3_ROUTING,
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Testing
|
||||
|
||||
@ -133,6 +133,18 @@ void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag);
|
||||
bool gnrc_rpl_parent_add_by_addr(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *addr,
|
||||
gnrc_rpl_parent_t **parent);
|
||||
|
||||
/**
|
||||
* @brief Iterate over all parents in all DODAGs with @p IPv6 address.
|
||||
*
|
||||
* @param[in] addr IPV6 address of the parent.
|
||||
* @param[out] parent Pointer to the parent if one was found. Otherwise NULL.
|
||||
* @param[in] idx Index to start searching from.
|
||||
*
|
||||
* @retval Index > 0 to continue next search from, if parent was found.
|
||||
* @retval -ENONENT if not found
|
||||
*/
|
||||
int gnrc_rpl_parent_iter_by_addr(const ipv6_addr_t *addr, gnrc_rpl_parent_t **parent, int idx);
|
||||
|
||||
/**
|
||||
* @brief Remove the @p parent from its DODAG.
|
||||
*
|
||||
|
||||
@ -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
|
||||
|
||||
@ -94,6 +94,7 @@ ifneq (,$(filter gnrc_rpl_p2p,$(USEMODULE)))
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_rpl,$(USEMODULE)))
|
||||
USEMODULE += gnrc_ipv6
|
||||
USEMODULE += gnrc_icmpv6
|
||||
USEMODULE += gnrc_ipv6_nib
|
||||
USEMODULE += trickle
|
||||
@ -446,6 +447,11 @@ ifneq (,$(filter gnrc,$(USEMODULE)))
|
||||
USEMODULE += gnrc_netif
|
||||
USEMODULE += gnrc_netif_hdr
|
||||
USEMODULE += gnrc_pktbuf
|
||||
ifneq (,$(filter gnrc_ipv6,$(USEMODULE)))
|
||||
ifneq (,$(filter nimble_netif,$(USEMODULE)))
|
||||
USEMODULE += gnrc_netapi_notify
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(filter sock_async, $(USEMODULE)))
|
||||
USEMODULE += gnrc_sock_async
|
||||
endif
|
||||
@ -460,6 +466,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
|
||||
79
sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c
Normal file
79
sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
|
||||
int _copy_l2_connection_data(gnrc_netapi_notify_t *notify, netapi_notify_l2_connection_t *data)
|
||||
{
|
||||
assert(notify->_data_len == sizeof(netapi_notify_l2_connection_t));
|
||||
|
||||
/* Parse event data */
|
||||
netapi_notify_l2_connection_t *recv_data = notify->_data;
|
||||
|
||||
if (recv_data->l2addr_len > GNRC_NETIF_L2ADDR_MAXLEN) {
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(data->l2addr, recv_data->l2addr, recv_data->l2addr_len);
|
||||
|
||||
data->l2addr_len = recv_data->l2addr_len;
|
||||
data->if_pid = recv_data->if_pid;
|
||||
|
||||
return sizeof(netapi_notify_l2_connection_t);
|
||||
}
|
||||
|
||||
int _copy_l3_address(gnrc_netapi_notify_t *notify, ipv6_addr_t *addr)
|
||||
{
|
||||
assert(notify->_data_len == sizeof(ipv6_addr_t));
|
||||
|
||||
memcpy(addr, notify->_data, sizeof(ipv6_addr_t));
|
||||
return sizeof(ipv6_addr_t);
|
||||
}
|
||||
|
||||
int gnrc_netapi_notify_copy_event_data(gnrc_netapi_notify_t *notify, uint8_t data_len, void *data)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (notify->event) {
|
||||
case NETAPI_NOTIFY_L2_NEIGH_CONNECTED:
|
||||
case NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED:
|
||||
if (data_len != sizeof(netapi_notify_l2_connection_t)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
res = _copy_l2_connection_data(notify, data);
|
||||
break;
|
||||
case NETAPI_NOTIFY_L3_DISCOVERED:
|
||||
case NETAPI_NOTIFY_L3_UNREACHABLE:
|
||||
if (data_len != sizeof(ipv6_addr_t)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
res = _copy_l3_address(notify, data);
|
||||
break;
|
||||
default:
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Acknowledge the read data */
|
||||
gnrc_netapi_notify_ack(¬ify->ack);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@ -29,6 +29,7 @@
|
||||
#include "utlist.h"
|
||||
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/netif/internal.h"
|
||||
#include "net/gnrc/ipv6/whitelist.h"
|
||||
#include "net/gnrc/ipv6/blacklist.h"
|
||||
@ -171,11 +172,125 @@ static void _dispatch_next_header(gnrc_pktsnip_t *pkt, unsigned nh,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find entry in NIB neighbor cache.
|
||||
*
|
||||
* @param[in] l2addr Layer 2 address of the neighbor.
|
||||
* @param[in] l2addr_len Length of @p l2addr.
|
||||
* @param[out] ipv6 IPv6 address of the neighbor or NULL.
|
||||
*
|
||||
* @retval True if a neighbor with @p l2addr was found in the nc.
|
||||
* @retval False otherwise.
|
||||
*/
|
||||
static inline bool _find_entry_in_nc(uint8_t *l2addr, uint8_t l2addr_len, ipv6_addr_t *ipv6)
|
||||
{
|
||||
void *state = NULL;
|
||||
gnrc_ipv6_nib_nc_t nce;
|
||||
|
||||
while (gnrc_ipv6_nib_nc_iter(0, &state, &nce)) {
|
||||
if (l2util_addr_equal(l2addr, l2addr_len, nce.l2addr, nce.l2addr_len)) {
|
||||
*ipv6 = nce.ipv6;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle a link-layer connection-established event.
|
||||
*
|
||||
* @param[in] if_pid Network interface of the connection.
|
||||
* @param[in] l2addr L2 address of the node on the connection.
|
||||
* @param[in] l2addr_len Length of @p l2addr.
|
||||
*/
|
||||
static inline void _on_l2_connected(kernel_pid_t if_pid, uint8_t *l2addr, uint8_t l2addr_len)
|
||||
{
|
||||
(void)if_pid;
|
||||
|
||||
ipv6_addr_t ipv6;
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN)
|
||||
/* Add neighbor to neighbor cache if interface represents a 6LN. */
|
||||
gnrc_ipv6_nib_nc_set_6ln(if_pid, l2addr, l2addr_len);
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_6LN */
|
||||
|
||||
/* Inform routing layer of new reachable neighbor. */
|
||||
if (_find_entry_in_nc(l2addr, l2addr_len, &ipv6)) {
|
||||
gnrc_netapi_notify(GNRC_NETTYPE_L3_ROUTING, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
NETAPI_NOTIFY_L3_DISCOVERED, &ipv6, sizeof(ipv6_addr_t));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle a link-layer connection-closed event.
|
||||
*
|
||||
* @param[in] if_pid Network interface of the connection.
|
||||
* @param[in] l2addr L2 address of the node on the connection.
|
||||
* @param[in] l2addr_len Length of @p l2addr.
|
||||
*/
|
||||
static inline void _on_l2_disconnected(kernel_pid_t if_pid, uint8_t *l2addr, uint8_t l2addr_len)
|
||||
{
|
||||
(void)if_pid;
|
||||
|
||||
ipv6_addr_t ipv6;
|
||||
|
||||
/* Inform routing layer of unreachable neighbor. This must be done *before* removing
|
||||
the neighbor from the neighbor cache. */
|
||||
if (_find_entry_in_nc(l2addr, l2addr_len, &ipv6)) {
|
||||
gnrc_netapi_notify(GNRC_NETTYPE_L3_ROUTING, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
NETAPI_NOTIFY_L3_UNREACHABLE, &ipv6, sizeof(ipv6_addr_t));
|
||||
}
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ARSM)
|
||||
/* Remove from neighbor cache. */
|
||||
gnrc_ipv6_nib_nc_del_l2(if_pid, l2addr, l2addr_len);
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_ARSM */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles a netapi event notification.
|
||||
*
|
||||
* @param[in] notify The type of notification.
|
||||
*/
|
||||
static inline void _netapi_notify_event(gnrc_netapi_notify_t *notify)
|
||||
{
|
||||
if (!IS_USED(MODULE_GNRC_NETAPI_NOTIFY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
netapi_notify_l2_connection_t data;
|
||||
netapi_notify_t type = notify->event;
|
||||
|
||||
if (gnrc_netapi_notify_copy_event_data(notify, sizeof(netapi_notify_l2_connection_t),
|
||||
&data) <= 0) {
|
||||
DEBUG("ipv6: invalid data on netapi notify event.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NETAPI_NOTIFY_L2_NEIGH_CONNECTED:
|
||||
_on_l2_connected(data.if_pid, data.l2addr, data.l2addr_len);
|
||||
break;
|
||||
case NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED:
|
||||
_on_l2_disconnected(data.if_pid, data.l2addr, data.l2addr_len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *_event_loop(void *args)
|
||||
{
|
||||
msg_t msg, reply;
|
||||
gnrc_netreg_entry_t me_reg = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
|
||||
/* Register entry for messages in IPv6 context. */
|
||||
gnrc_netreg_entry_t me_ipv6_reg = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
thread_getpid());
|
||||
#ifdef MODULE_GNRC_NETAPI_NOTIFY
|
||||
/* Register entry for messages in L2 discovery context. */
|
||||
gnrc_netreg_entry_t me_discovery_reg = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
thread_getpid());
|
||||
#endif /* MODULE_GNRC_NETAPI_NOTIFY */
|
||||
|
||||
(void)args;
|
||||
msg_init_queue(_msg_q, GNRC_IPV6_MSG_QUEUE_SIZE);
|
||||
@ -184,8 +299,14 @@ static void *_event_loop(void *args)
|
||||
#ifdef MODULE_GNRC_IPV6_EXT_FRAG
|
||||
gnrc_ipv6_ext_frag_init();
|
||||
#endif /* MODULE_GNRC_IPV6_EXT_FRAG */
|
||||
/* register interest in all IPv6 packets */
|
||||
gnrc_netreg_register(GNRC_NETTYPE_IPV6, &me_reg);
|
||||
|
||||
/* Register interest in all IPv6 packets. */
|
||||
gnrc_netreg_register(GNRC_NETTYPE_IPV6, &me_ipv6_reg);
|
||||
|
||||
#ifdef MODULE_GNRC_NETAPI_NOTIFY
|
||||
/* Register interest in L2 neighbor discovery info. */
|
||||
gnrc_netreg_register(GNRC_NETTYPE_L2_DISCOVERY, &me_discovery_reg);
|
||||
#endif /* MODULE_GNRC_NETAPI_NOTIFY */
|
||||
|
||||
/* preinitialize ACK */
|
||||
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
|
||||
@ -212,7 +333,10 @@ static void *_event_loop(void *args)
|
||||
reply.content.value = -ENOTSUP;
|
||||
msg_reply(&msg, &reply);
|
||||
break;
|
||||
|
||||
case GNRC_NETAPI_MSG_TYPE_NOTIFY:
|
||||
DEBUG("ipv6: GNRC_NETAPI_MSG_TYPE_NOTIFY received\n");
|
||||
_netapi_notify_event(msg.content.ptr);
|
||||
break;
|
||||
#ifdef MODULE_GNRC_IPV6_EXT_FRAG
|
||||
case GNRC_IPV6_EXT_FRAG_RBUF_GC:
|
||||
gnrc_ipv6_ext_frag_rbuf_gc();
|
||||
|
||||
@ -73,6 +73,33 @@ bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif_t *netif,
|
||||
return res;
|
||||
}
|
||||
|
||||
int _build_ll_ipv6_from_addr(gnrc_netif_t *netif, const uint8_t *l2addr, uint8_t l2addr_len,
|
||||
ipv6_addr_t *ipv6addr)
|
||||
{
|
||||
/* Reverse of _resolve_addr_from_ipv6. */
|
||||
|
||||
if (netif == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Only supported for 6LN nodes. */
|
||||
if (!gnrc_netif_is_6ln(netif)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Set IPv6 link-local prefix. */
|
||||
*ipv6addr = ipv6_addr_link_local_prefix;
|
||||
|
||||
/* Build interface identifier based on l2 address. */
|
||||
int res = gnrc_netif_ipv6_iid_from_addr(netif, l2addr, l2addr_len,
|
||||
(eui64_t *)&ipv6addr->u64[1]);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return sizeof(ipv6_addr_t);
|
||||
}
|
||||
|
||||
uint8_t _handle_aro(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
|
||||
const icmpv6_hdr_t *icmpv6,
|
||||
const sixlowpan_nd_opt_ar_t *aro, const ndp_opt_t *sl2ao,
|
||||
|
||||
@ -70,6 +70,27 @@ extern "C" {
|
||||
bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif_t *netif,
|
||||
gnrc_ipv6_nib_nc_t *nce);
|
||||
|
||||
/**
|
||||
* @brief Build a link-local ipv6 address statically from the L2 address by
|
||||
* translating the hardware address to an EUI-64 and adding the link-local
|
||||
* IPv6 prefix.
|
||||
*
|
||||
* @note Reverse of _resolve_addr_from_ipv6.
|
||||
*
|
||||
* @param[in] netif The interface to @p l2addr.
|
||||
* @param[in] l2addr Layer 2 address.
|
||||
* @param[in] l2addr_len Length of the layer 2 address.
|
||||
* @param[out] ipv6addr The resulting IPv6 address.
|
||||
*
|
||||
* @retval sizeof(ipv6_addr_t) on success.
|
||||
* @retval `-ENOTSUP` if the interface does not represent a 6LN or when
|
||||
* gnrc_netif_t::device_type of @p netif does not support IID conversion.
|
||||
* @retval `-EINVAL` when @p addr_len is invalid for the
|
||||
* gnrc_netif_t::device_type of @p netif.
|
||||
*/
|
||||
int _build_ll_ipv6_from_addr(gnrc_netif_t *netif, const uint8_t *l2addr,
|
||||
uint8_t l2addr_len, ipv6_addr_t *ipv6addr);
|
||||
|
||||
/**
|
||||
* @brief Calculates exponential backoff for RS retransmissions
|
||||
*
|
||||
@ -137,6 +158,7 @@ uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C || defined(DOXYGEN) */
|
||||
#else /* CONFIG_GNRC_IPV6_NIB_6LN || defined(DOXYGEN) */
|
||||
#define _resolve_addr_from_ipv6(dst, netif, nce) (false)
|
||||
#define _build_ll_ipv6_from_addr(netif, l2addr, l2addr_len, ipv6addr) (-ENOTSUP)
|
||||
/* _handle_aro() doesn't make sense without 6LR so don't even use it
|
||||
* => throw error in case it is compiled in => don't define it here as NOP macro
|
||||
*/
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
|
||||
#include "_nib-internal.h"
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN)
|
||||
# include "_nib-6ln.h"
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_6LN */
|
||||
|
||||
int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface,
|
||||
const uint8_t *l2addr, size_t l2addr_len)
|
||||
@ -59,6 +62,32 @@ int gnrc_ipv6_nib_nc_set(const ipv6_addr_t *ipv6, unsigned iface,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_6LN)
|
||||
int gnrc_ipv6_nib_nc_set_6ln(unsigned iface, const uint8_t *l2addr, size_t l2addr_len)
|
||||
{
|
||||
int res;
|
||||
ipv6_addr_t ipv6addr;
|
||||
|
||||
gnrc_netif_t *netif = gnrc_netif_get_by_pid(iface);
|
||||
|
||||
if (netif == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
/* Build link-local IPv6 address based on L2-address. */
|
||||
res = _build_ll_ipv6_from_addr(netif, l2addr, l2addr_len, &ipv6addr);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
/* Add as unmanaged entry to neighbor cache. */
|
||||
res = gnrc_ipv6_nib_nc_set(&ipv6addr, netif->pid, l2addr, l2addr_len);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void gnrc_ipv6_nib_nc_del(const ipv6_addr_t *ipv6, unsigned iface)
|
||||
{
|
||||
_nib_onl_entry_t *node = NULL;
|
||||
@ -74,6 +103,29 @@ void gnrc_ipv6_nib_nc_del(const ipv6_addr_t *ipv6, unsigned iface)
|
||||
_nib_release();
|
||||
}
|
||||
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ARSM)
|
||||
bool gnrc_ipv6_nib_nc_del_l2(unsigned iface, const uint8_t *l2addr, size_t l2addr_len)
|
||||
{
|
||||
_nib_onl_entry_t *node = NULL;
|
||||
bool res = false;
|
||||
|
||||
_nib_acquire();
|
||||
|
||||
/* Find and remove entry with matching l2 address.*/
|
||||
while ((node = _nib_onl_iter(node)) != NULL) {
|
||||
if ((_nib_onl_get_if(node) == iface) &&
|
||||
l2util_addr_equal(l2addr, l2addr_len, node->l2addr, node->l2addr_len)) {
|
||||
_nib_nc_remove(node);
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_nib_release();
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_ARSM */
|
||||
|
||||
void gnrc_ipv6_nib_nc_mark_reachable(const ipv6_addr_t *ipv6)
|
||||
{
|
||||
_nib_onl_entry_t *node = NULL;
|
||||
|
||||
@ -15,12 +15,14 @@
|
||||
* @author Cenk Gündoğan <cenk.guendogan@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include "net/ipv6/addr.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "kernel_defines.h"
|
||||
|
||||
#include "net/icmpv6.h"
|
||||
#include "net/ipv6.h"
|
||||
#include "net/gnrc/netapi/notify.h"
|
||||
#include "net/gnrc/netif/internal.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "mutex.h"
|
||||
@ -58,7 +60,12 @@ static xtimer_t _lt_timer;
|
||||
static msg_t _lt_msg = { .type = GNRC_RPL_MSG_TYPE_LIFETIME_UPDATE };
|
||||
#endif
|
||||
static msg_t _msg_q[GNRC_RPL_MSG_QUEUE_SIZE];
|
||||
static gnrc_netreg_entry_t _me_reg;
|
||||
|
||||
static gnrc_netreg_entry_t _me_icmpv6_reg;
|
||||
#ifdef MODULE_GNRC_NETAPI_NOTIFY
|
||||
static gnrc_netreg_entry_t _me_routing_reg;
|
||||
#endif /* MODULE_GNRC_NETAPI_NOTIFY*/
|
||||
|
||||
static mutex_t _inst_id_mutex = MUTEX_INIT;
|
||||
static uint8_t _instance_id;
|
||||
|
||||
@ -100,10 +107,17 @@ kernel_pid_t gnrc_rpl_init(kernel_pid_t if_pid)
|
||||
* queue, and registration with netreg can commence. */
|
||||
mutex_lock(&eventloop_startup);
|
||||
|
||||
_me_reg.demux_ctx = ICMPV6_RPL_CTRL;
|
||||
_me_reg.target.pid = gnrc_rpl_pid;
|
||||
/* register interest in all ICMPv6 packets */
|
||||
gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_reg);
|
||||
/* Register interest in all ICMPv6 packets. */
|
||||
_me_icmpv6_reg.demux_ctx = ICMPV6_RPL_CTRL;
|
||||
_me_icmpv6_reg.target.pid = gnrc_rpl_pid;
|
||||
gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_icmpv6_reg);
|
||||
|
||||
#ifdef MODULE_GNRC_NETAPI_NOTIFY
|
||||
/* Register interest in L3 routing info. */
|
||||
_me_routing_reg.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL;
|
||||
_me_routing_reg.target.pid = gnrc_rpl_pid;
|
||||
gnrc_netreg_register(GNRC_NETTYPE_L3_ROUTING, &_me_routing_reg);
|
||||
#endif /* MODULE_GNRC_NETAPI_NOTIFY*/
|
||||
|
||||
gnrc_rpl_of_manager_init();
|
||||
evtimer_init_msg(&gnrc_rpl_evtimer);
|
||||
@ -273,6 +287,68 @@ static void _parent_timeout(gnrc_rpl_parent_t *parent)
|
||||
evtimer_add_msg(&gnrc_rpl_evtimer, &parent->timeout_event, gnrc_rpl_pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles the event that a new neighbor was discovered and is reachable.
|
||||
*
|
||||
* @param[in] addr The address of the neighbor.
|
||||
*/
|
||||
static inline void _handle_discovered_neighbor(ipv6_addr_t *addr)
|
||||
{
|
||||
/* Send DODAG soliciation message to node. */
|
||||
gnrc_rpl_send_DIS(NULL, addr, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles the event that a neighbor became unreachable.
|
||||
*
|
||||
* @param[in] addr The address of the neighbor.
|
||||
*/
|
||||
static inline void _handle_unreachable_neighbor(ipv6_addr_t *addr)
|
||||
{
|
||||
gnrc_rpl_parent_t *parent;
|
||||
int idx = 0;
|
||||
|
||||
/* Iterate through all parents and timeout the ones with matching address.
|
||||
* There can be multiple parents with the same address because the same node
|
||||
* can be a parent in multiple different DODAGs. */
|
||||
while ((idx = gnrc_rpl_parent_iter_by_addr(addr, &parent, idx)) >= 0) {
|
||||
_parent_timeout(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles a netapi event notification.
|
||||
*
|
||||
* @param[in] notify The type of notification.
|
||||
*/
|
||||
static inline void _netapi_notify_event(gnrc_netapi_notify_t *notify)
|
||||
{
|
||||
if (!IS_USED(MODULE_GNRC_NETAPI_NOTIFY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipv6_addr_t neigh_addr;
|
||||
netapi_notify_t type = notify->event;
|
||||
|
||||
int res = gnrc_netapi_notify_copy_event_data(notify, sizeof(ipv6_addr_t), &neigh_addr);
|
||||
|
||||
if (res != sizeof(ipv6_addr_t)) {
|
||||
DEBUG("RPL: Received invalid data for netapi notify event.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NETAPI_NOTIFY_L3_DISCOVERED:
|
||||
_handle_discovered_neighbor(&neigh_addr);
|
||||
break;
|
||||
case NETAPI_NOTIFY_L3_UNREACHABLE:
|
||||
_handle_unreachable_neighbor(&neigh_addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *_event_loop(void *args)
|
||||
{
|
||||
msg_t msg, reply;
|
||||
@ -342,6 +418,10 @@ static void *_event_loop(void *args)
|
||||
reply.content.value = -ENOTSUP;
|
||||
msg_reply(&msg, &reply);
|
||||
break;
|
||||
case GNRC_NETAPI_MSG_TYPE_NOTIFY:
|
||||
DEBUG("RPL: GNRC_NETAPI_MSG_TYPE_NOTIFY received\n");
|
||||
_netapi_notify_event(msg.content.ptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -201,6 +201,19 @@ void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag)
|
||||
dodag->my_rank = GNRC_RPL_INFINITE_RANK;
|
||||
}
|
||||
|
||||
int gnrc_rpl_parent_iter_by_addr(const ipv6_addr_t *addr, gnrc_rpl_parent_t **parent, int idx)
|
||||
{
|
||||
*parent = NULL;
|
||||
for (uint8_t i = idx; i < GNRC_RPL_PARENTS_NUMOF; ++i) {
|
||||
if ((gnrc_rpl_parents[i].state != 0) && ipv6_addr_equal(&gnrc_rpl_parents[i].addr, addr)) {
|
||||
*parent = &gnrc_rpl_parents[i];
|
||||
/* Index to continue search from. */
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
bool gnrc_rpl_parent_add_by_addr(gnrc_rpl_dodag_t *dodag, ipv6_addr_t *addr,
|
||||
gnrc_rpl_parent_t **parent)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user