From 72c65e3a816d91c40104328de3dd1d7ca08816ee Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 9 Dec 2025 14:29:28 +0100 Subject: [PATCH] nimble/netif: notify on BLE connection events --- pkg/nimble/netif/nimble_netif.c | 29 +++++++++++++++++ sys/include/net/gnrc/netapi/notify.h | 13 +++++++- sys/include/net/gnrc/nettype.h | 7 +++++ .../gnrc/netapi/notify/gnrc_netapi_notify.c | 31 +++++++++++++++++-- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/pkg/nimble/netif/nimble_netif.c b/pkg/nimble/netif/nimble_netif.c index e133f6455a..694042b831 100644 --- a/pkg/nimble/netif/nimble_netif.c +++ b/pkg/nimble/netif/nimble_netif.c @@ -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 #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: diff --git a/sys/include/net/gnrc/netapi/notify.h b/sys/include/net/gnrc/netapi/notify.h index c7c6c1e1d0..8e82adedca 100644 --- a/sys/include/net/gnrc/netapi/notify.h +++ b/sys/include/net/gnrc/netapi/notify.h @@ -46,7 +46,8 @@ extern "C" { * be added for parsing the data and calling @ref gnrc_netapi_notify_ack. */ typedef enum { - PLACEHOLDER + NETAPI_NOTIFY_L2_NEIGH_CONNECTED, /**< Connection established on layer 2. */ + NETAPI_NOTIFY_L2_NEIGH_DISCONNECTED, /**< Connection closed on layer 2. */ } netapi_notify_t; /** @@ -59,6 +60,16 @@ typedef struct { 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. * diff --git a/sys/include/net/gnrc/nettype.h b/sys/include/net/gnrc/nettype.h index b054a0dace..8ce21f4633 100644 --- a/sys/include/net/gnrc/nettype.h +++ b/sys/include/net/gnrc/nettype.h @@ -132,6 +132,13 @@ typedef enum { * } */ + /** + * @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, /** @} */ /** diff --git a/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c b/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c index a9a21b9c4d..4f8c4b806a 100644 --- a/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c +++ b/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c @@ -12,18 +12,43 @@ * @author Elena Frank */ +#include #include #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 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) { + 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; default: res = -EINVAL; break;