Merge pull request #16824 from benpicco/gnrc_netif_ipv6_wait_for_prefix
gnrc/netif: add gnrc_netif_ipv6_wait_for_global_address()
This commit is contained in:
commit
ea80df1780
@ -422,7 +422,7 @@ static inline int gnrc_netif_ipv6_addrs_get(const gnrc_netif_t *netif,
|
|||||||
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
||||||
*/
|
*/
|
||||||
static inline int gnrc_netif_ipv6_addr_add(const gnrc_netif_t *netif,
|
static inline int gnrc_netif_ipv6_addr_add(const gnrc_netif_t *netif,
|
||||||
ipv6_addr_t *addr, unsigned pfx_len,
|
const ipv6_addr_t *addr, unsigned pfx_len,
|
||||||
uint8_t flags)
|
uint8_t flags)
|
||||||
{
|
{
|
||||||
assert(netif != NULL);
|
assert(netif != NULL);
|
||||||
@ -447,7 +447,7 @@ static inline int gnrc_netif_ipv6_addr_add(const gnrc_netif_t *netif,
|
|||||||
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
* @return -ENOTSUP, if @p netif doesn't support IPv6.
|
||||||
*/
|
*/
|
||||||
static inline int gnrc_netif_ipv6_addr_remove(const gnrc_netif_t *netif,
|
static inline int gnrc_netif_ipv6_addr_remove(const gnrc_netif_t *netif,
|
||||||
ipv6_addr_t *addr)
|
const ipv6_addr_t *addr)
|
||||||
{
|
{
|
||||||
assert(netif != NULL);
|
assert(netif != NULL);
|
||||||
assert(addr != NULL);
|
assert(addr != NULL);
|
||||||
@ -656,6 +656,23 @@ static inline msg_bus_t* gnrc_netif_get_bus(gnrc_netif_t *netif,
|
|||||||
assert(type < GNRC_NETIF_BUS_NUMOF);
|
assert(type < GNRC_NETIF_BUS_NUMOF);
|
||||||
return &netif->bus[type];
|
return &netif->bus[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for a global address to become available.
|
||||||
|
* This function blocks until a valid global address has been
|
||||||
|
* configured, e.g. by receiving a router advertisement or via DHCPv6.
|
||||||
|
*
|
||||||
|
* Requires the `gnrc_netif_bus` module.
|
||||||
|
*
|
||||||
|
* @param netif pointer to the interface
|
||||||
|
* May be NULL, then this checks for a global address
|
||||||
|
* on *any* interface.
|
||||||
|
* @param timeout_ms Time to wait for an address to become available, in ms.
|
||||||
|
*
|
||||||
|
* @return true if a global address is configured
|
||||||
|
*/
|
||||||
|
bool gnrc_netif_ipv6_wait_for_global_address(gnrc_netif_t *netif,
|
||||||
|
uint32_t timeout_ms);
|
||||||
#endif /* MODULE_GNRC_NETIF_BUS */
|
#endif /* MODULE_GNRC_NETIF_BUS */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#if (CONFIG_GNRC_NETIF_MIN_WAIT_AFTER_SEND_US > 0U)
|
#if IS_USED(MODULE_XTIMER) || IS_USED(MODULE_ZTIMER_XTIMER_COMPAT)
|
||||||
#include "xtimer.h"
|
#include "xtimer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1298,6 +1298,105 @@ int gnrc_netif_ipv6_add_prefix(gnrc_netif_t *netif,
|
|||||||
out:
|
out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_USED(MODULE_GNRC_NETIF_BUS)
|
||||||
|
static bool _has_global_addr(gnrc_netif_t *netif)
|
||||||
|
{
|
||||||
|
bool has_global = false;
|
||||||
|
|
||||||
|
gnrc_netif_acquire(netif);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) {
|
||||||
|
if (ipv6_addr_is_unspecified(&netif->ipv6.addrs[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ipv6_addr_is_link_local(&netif->ipv6.addrs[i])) {
|
||||||
|
has_global = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gnrc_netif_release(netif);
|
||||||
|
return has_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _netif_bus_attach_and_subscribe_addr_valid(gnrc_netif_t *netif,
|
||||||
|
msg_bus_entry_t *sub)
|
||||||
|
{
|
||||||
|
msg_bus_t *bus = gnrc_netif_get_bus(netif, GNRC_NETIF_BUS_IPV6);
|
||||||
|
msg_bus_attach(bus, sub);
|
||||||
|
msg_bus_subscribe(sub, GNRC_IPV6_EVENT_ADDR_VALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _netif_bus_detach(gnrc_netif_t *netif, msg_bus_entry_t *sub)
|
||||||
|
{
|
||||||
|
msg_bus_t *bus = gnrc_netif_get_bus(netif, GNRC_NETIF_BUS_IPV6);
|
||||||
|
msg_bus_detach(bus, sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gnrc_netif_ipv6_wait_for_global_address(gnrc_netif_t *netif,
|
||||||
|
uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
unsigned netif_numof = gnrc_netif_numof();
|
||||||
|
|
||||||
|
/* no interfaces */
|
||||||
|
if (netif_numof == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_bus_entry_t subs[netif_numof];
|
||||||
|
bool has_global = false;
|
||||||
|
|
||||||
|
if (netif) {
|
||||||
|
if (_has_global_addr(netif)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_netif_bus_attach_and_subscribe_addr_valid(netif, &subs[0]);
|
||||||
|
} else {
|
||||||
|
/* subscribe to all interfaces */
|
||||||
|
for (unsigned count = 0;
|
||||||
|
(netif = gnrc_netif_iter(netif));
|
||||||
|
count++) {
|
||||||
|
if (_has_global_addr(netif)) {
|
||||||
|
has_global = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_netif_bus_attach_and_subscribe_addr_valid(netif, &subs[count]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for global address */
|
||||||
|
msg_t m;
|
||||||
|
while (!has_global) {
|
||||||
|
if (xtimer_msg_receive_timeout(&m, timeout_ms * US_PER_MS) < 0) {
|
||||||
|
DEBUG_PUTS("gnrc_netif: timeout waiting for prefix");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv6_addr_is_link_local(m.content.ptr)) {
|
||||||
|
DEBUG_PUTS("gnrc_netif: got link-local address");
|
||||||
|
} else {
|
||||||
|
DEBUG_PUTS("gnrc_netif: got global address");
|
||||||
|
has_global = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called with a given interface */
|
||||||
|
if (netif != NULL) {
|
||||||
|
_netif_bus_detach(netif, &subs[0]);
|
||||||
|
} else {
|
||||||
|
/* unsubscribe all */
|
||||||
|
for (unsigned count = 0;
|
||||||
|
(netif = gnrc_netif_iter(netif));
|
||||||
|
count++) {
|
||||||
|
_netif_bus_detach(netif, &subs[count]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_global;
|
||||||
|
}
|
||||||
|
#endif /* IS_USED(MODULE_GNRC_NETIF_BUS) */
|
||||||
#endif /* IS_USED(MODULE_GNRC_NETIF_IPV6) */
|
#endif /* IS_USED(MODULE_GNRC_NETIF_IPV6) */
|
||||||
|
|
||||||
static void _update_l2addr_from_dev(gnrc_netif_t *netif)
|
static void _update_l2addr_from_dev(gnrc_netif_t *netif)
|
||||||
|
|||||||
19
tests/gnrc_netif_ipv6_wait_for_global_address/Makefile
Normal file
19
tests/gnrc_netif_ipv6_wait_for_global_address/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
|
USEMODULE += embunit
|
||||||
|
USEMODULE += gnrc_netif
|
||||||
|
USEMODULE += gnrc_netif_bus
|
||||||
|
USEMODULE += gnrc_ipv6
|
||||||
|
USEMODULE += netdev_test
|
||||||
|
USEMODULE += xtimer
|
||||||
|
|
||||||
|
# deactivate automatically emitted packets from IPv6 neighbor discovery
|
||||||
|
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_ARSM=0
|
||||||
|
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_SLAAC=0
|
||||||
|
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_NO_RTR_SOL=1
|
||||||
|
CFLAGS += -DGNRC_NETIF_ADDRS_NUMOF=16
|
||||||
|
CFLAGS += -DGNRC_NETIF_GROUPS_NUMOF=8
|
||||||
|
CFLAGS += -DLOG_LEVEL=LOG_NONE
|
||||||
|
CFLAGS += -DTEST_SUITES
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
28
tests/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci
Normal file
28
tests/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
arduino-duemilanove \
|
||||||
|
arduino-leonardo \
|
||||||
|
arduino-mega2560 \
|
||||||
|
arduino-nano \
|
||||||
|
arduino-uno \
|
||||||
|
atmega328p \
|
||||||
|
atmega328p-xplained-mini \
|
||||||
|
bluepill-stm32f030c8 \
|
||||||
|
i-nucleo-lrwan1 \
|
||||||
|
msb-430 \
|
||||||
|
msb-430h \
|
||||||
|
nucleo-f030r8 \
|
||||||
|
nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 \
|
||||||
|
nucleo-f303k8 \
|
||||||
|
nucleo-f334r8 \
|
||||||
|
nucleo-l011k4 \
|
||||||
|
nucleo-l031k6 \
|
||||||
|
nucleo-l053r8 \
|
||||||
|
samd10-xmini \
|
||||||
|
slstk3400a \
|
||||||
|
stk3200 \
|
||||||
|
stm32f030f4-demo \
|
||||||
|
stm32f0discovery \
|
||||||
|
stm32l0538-disco \
|
||||||
|
waspmote-pro \
|
||||||
|
#
|
||||||
161
tests/gnrc_netif_ipv6_wait_for_global_address/main.c
Normal file
161
tests/gnrc_netif_ipv6_wait_for_global_address/main.c
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 ML!PA Consulting GmbH
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Tests notification for global address
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "embUnit.h"
|
||||||
|
#include "embUnit/embUnit.h"
|
||||||
|
#include "net/ipv6.h"
|
||||||
|
#include "net/gnrc/netif.h"
|
||||||
|
#include "net/gnrc/netif/raw.h"
|
||||||
|
#include "net/netdev_test.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
|
||||||
|
#define TEST_NETIF_NUMOF 2
|
||||||
|
#define TEST_NETIF_PRIO 3
|
||||||
|
|
||||||
|
static netdev_test_t netdev_test[TEST_NETIF_NUMOF];
|
||||||
|
static gnrc_netif_t netif_test[TEST_NETIF_NUMOF];
|
||||||
|
static char netif_stack[TEST_NETIF_NUMOF][THREAD_STACKSIZE_DEFAULT];
|
||||||
|
static char adder_stack[THREAD_STACKSIZE_DEFAULT];
|
||||||
|
|
||||||
|
static gnrc_netif_t *_test_netif;
|
||||||
|
static const ipv6_addr_t _test_addr = {{ 0x20, 0x01, 0x0d, 0xd8,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01 }};
|
||||||
|
static void tear_down(void)
|
||||||
|
{
|
||||||
|
if (_test_netif == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnrc_netif_ipv6_addr_remove(_test_netif, &_test_addr);
|
||||||
|
_test_netif = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_adder_thread(void *netif)
|
||||||
|
{
|
||||||
|
xtimer_msleep(10);
|
||||||
|
gnrc_netif_ipv6_addr_add(netif, &_test_addr, 64,
|
||||||
|
GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _add_delayed_addr(gnrc_netif_t *netif)
|
||||||
|
{
|
||||||
|
_test_netif = netif;
|
||||||
|
memset(adder_stack, 0, sizeof(adder_stack));
|
||||||
|
thread_create(adder_stack, sizeof(adder_stack),
|
||||||
|
THREAD_PRIORITY_MAIN - 1,
|
||||||
|
THREAD_CREATE_STACKTEST,
|
||||||
|
_adder_thread, netif, "add_addr");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _assert_wait_blocks(gnrc_netif_t *add_netif,
|
||||||
|
gnrc_netif_t *wait_netif,
|
||||||
|
bool success)
|
||||||
|
{
|
||||||
|
uint32_t now = xtimer_now_usec();
|
||||||
|
uint32_t timeout = 20;
|
||||||
|
|
||||||
|
_add_delayed_addr(add_netif);
|
||||||
|
TEST_ASSERT(gnrc_netif_ipv6_wait_for_global_address(wait_netif,
|
||||||
|
timeout) == success);
|
||||||
|
if (success) {
|
||||||
|
TEST_ASSERT(((xtimer_now_usec() - now) / US_PER_MS) < timeout);
|
||||||
|
} else {
|
||||||
|
TEST_ASSERT(((xtimer_now_usec() - now) / US_PER_MS) >= timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wait_timeout(void)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_INT(TEST_NETIF_NUMOF, gnrc_netif_numof());
|
||||||
|
TEST_ASSERT(!gnrc_netif_ipv6_wait_for_global_address(NULL, 10));
|
||||||
|
TEST_ASSERT(!gnrc_netif_ipv6_wait_for_global_address(&netif_test[0], 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wait_timeout_other_iface(void)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_INT(TEST_NETIF_NUMOF, gnrc_netif_numof());
|
||||||
|
|
||||||
|
/* no event when adding addr to other interface */
|
||||||
|
_assert_wait_blocks(&netif_test[1], &netif_test[0], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wait_success(void)
|
||||||
|
{
|
||||||
|
/* event when adding addr to specified interface */
|
||||||
|
_assert_wait_blocks(&netif_test[0], &netif_test[0], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wait_success_any_iface(void)
|
||||||
|
{
|
||||||
|
/* event when adding addr to any interface */
|
||||||
|
_assert_wait_blocks(&netif_test[0], NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Test *embunit_tests_gnrc_netif(void)
|
||||||
|
{
|
||||||
|
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||||
|
new_TestFixture(test_wait_timeout),
|
||||||
|
new_TestFixture(test_wait_timeout_other_iface),
|
||||||
|
new_TestFixture(test_wait_success),
|
||||||
|
new_TestFixture(test_wait_success_any_iface),
|
||||||
|
};
|
||||||
|
EMB_UNIT_TESTCALLER(tests, NULL, tear_down, fixtures);
|
||||||
|
|
||||||
|
return (Test *)&tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int netdev_get_device_type(netdev_t *dev, void *value, size_t max_len)
|
||||||
|
{
|
||||||
|
(void)dev;
|
||||||
|
(void)max_len;
|
||||||
|
const uint16_t type = NETDEV_TYPE_SLIP;
|
||||||
|
memcpy(value, &type, sizeof(type));
|
||||||
|
return sizeof(uint16_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _setup_mock_netif(netdev_test_t *dev, gnrc_netif_t *netif,
|
||||||
|
void *stack, size_t stack_size, unsigned prio)
|
||||||
|
{
|
||||||
|
netdev_test_setup(dev, NULL);
|
||||||
|
netdev_test_set_get_cb(dev, NETOPT_DEVICE_TYPE, netdev_get_device_type);
|
||||||
|
gnrc_netif_raw_create(netif, stack, stack_size, prio,
|
||||||
|
"netdev_test", &dev->netdev.netdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < TEST_NETIF_NUMOF; ++i) {
|
||||||
|
_setup_mock_netif(&netdev_test[i], &netif_test[i],
|
||||||
|
netif_stack[i], sizeof(netif_stack[i]),
|
||||||
|
TEST_NETIF_PRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTS_START();
|
||||||
|
TESTS_RUN(embunit_tests_gnrc_netif());
|
||||||
|
TESTS_END();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
tests/gnrc_netif_ipv6_wait_for_global_address/tests/01-run.py
Executable file
18
tests/gnrc_netif_ipv6_wait_for_global_address/tests/01-run.py
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2021 Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
#
|
||||||
|
# This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
# General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
# directory for more details.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from testrunner import run
|
||||||
|
|
||||||
|
|
||||||
|
def testfunc(child):
|
||||||
|
child.expect_exact("OK")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(run(testfunc))
|
||||||
Loading…
x
Reference in New Issue
Block a user