diff --git a/sys/include/net/gnrc/netapi/notify.h b/sys/include/net/gnrc/netapi/notify.h index 8e82adedca..d495727270 100644 --- a/sys/include/net/gnrc/netapi/notify.h +++ b/sys/include/net/gnrc/netapi/notify.h @@ -48,6 +48,8 @@ extern "C" { 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; /** diff --git a/sys/include/net/gnrc/nettype.h b/sys/include/net/gnrc/nettype.h index 8ce21f4633..342ea57164 100644 --- a/sys/include/net/gnrc/nettype.h +++ b/sys/include/net/gnrc/nettype.h @@ -139,6 +139,15 @@ typedef enum { * 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, /** @} */ /** diff --git a/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c b/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c index 4f8c4b806a..2e1fe08b94 100644 --- a/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c +++ b/sys/net/gnrc/netapi/notify/gnrc_netapi_notify.c @@ -36,6 +36,14 @@ int _copy_l2_connection_data(gnrc_netapi_notify_t *notify, netapi_notify_l2_conn 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; @@ -49,6 +57,14 @@ int gnrc_netapi_notify_copy_event_data(gnrc_netapi_notify_t *notify, uint8_t dat } 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; diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index b53cbb7e59..33517d80dd 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -207,10 +207,18 @@ static inline void _on_l2_connected(kernel_pid_t if_pid, uint8_t *l2addr, uint8_ { (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)); + } } /** @@ -224,6 +232,15 @@ static inline void _on_l2_disconnected(kernel_pid_t if_pid, uint8_t *l2addr, uin { (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);