From db463a3373b25d3192ed75f83803a48414a0f27b Mon Sep 17 00:00:00 2001 From: "Martine S. Lenders" Date: Thu, 6 Feb 2020 15:09:58 +0100 Subject: [PATCH] gnrc_dhcpv6_client_6lbr: initial import of a 6LBR DHCPv6 client --- Makefile.dep | 4 + sys/auto_init/auto_init.c | 6 + sys/include/net/gnrc/dhcpv6/client/6lbr.h | 62 ++++++++ sys/net/gnrc/Kconfig | 1 + sys/net/gnrc/application_layer/dhcpv6/Kconfig | 26 ++++ .../application_layer/dhcpv6/client_6lbr.c | 139 ++++++++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 sys/include/net/gnrc/dhcpv6/client/6lbr.h create mode 100644 sys/net/gnrc/application_layer/dhcpv6/Kconfig create mode 100644 sys/net/gnrc/application_layer/dhcpv6/client_6lbr.c diff --git a/Makefile.dep b/Makefile.dep index f3cda9959b..93c657c238 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -96,6 +96,10 @@ ifneq (,$(filter gnrc_dhcpv6_client,$(USEMODULE))) USEMODULE += gnrc_sock_udp endif +ifneq (,$(filter gnrc_dhcpv6_client_6lbr,$(USEMODULE))) + USEMODULE += gnrc_dhcpv6_client +endif + ifneq (,$(filter gnrc_uhcpc,$(USEMODULE))) USEMODULE += uhcpc USEMODULE += gnrc_sock_udp diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 10efdf4d16..1127af2265 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -639,4 +639,10 @@ void auto_init(void) extern void dhcpv6_client_auto_init(void); dhcpv6_client_auto_init(); #endif /* MODULE_AUTO_INIT_DHCPV6_CLIENT */ + +#ifdef MODULE_GNRC_DHCPV6_CLIENT_6LBR + DEBUG("auto_init 6LoWPAN border router DHCPv6 client"); + extern void gnrc_dhcpv6_client_6lbr_init(void); + gnrc_dhcpv6_client_6lbr_init(); +#endif /* MODULE_GNRC_DHCPV6_CLIENT_6LBR */ } diff --git a/sys/include/net/gnrc/dhcpv6/client/6lbr.h b/sys/include/net/gnrc/dhcpv6/client/6lbr.h new file mode 100644 index 0000000000..f622d236ab --- /dev/null +++ b/sys/include/net/gnrc/dhcpv6/client/6lbr.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * 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. + */ + +/** + * @defgroup net_dhcpv6_client_6lbr DHCPv6 client for 6LoWPAN border routers + * @ingroup net_dhcpv6_client + * @brief DHCPv6 client bootstrapping for 6LoWPAN border routers + * @{ + * + * @file + * @brief DHCPv6 client on 6LoWPAN border router definitions + * + * @author Martine S. Lenders + */ +#ifndef NET_GNRC_DHCPV6_CLIENT_6LBR_H +#define NET_GNRC_DHCPV6_CLIENT_6LBR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Identifier of the upstream interface + * + * Leave 0 (default) to let the client pick the first non-6LoWPAN interface it + * finds + */ +#ifndef CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM +#define CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM (0) +#endif + +/** + * @brief Use static routes to upstream router + * + * If set the border router will be configured to have a default route via + * `fe80::1`. The link-local address `fe80::2` will be added so that the + * upstream router can set a static route for the delegated prefix via that + * address. It is recommended to increase at least @ref + * CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF to that end. + */ +#ifdef DOXYGEN +#define CONFIG_GNRC_DHCPV6_CLIENT_6LBR_STATIC_ROUTE +#endif + +/** + * @brief Initializes the DHCPv6 client for 6LoWPAN border router + * + * @note Called by `auto_init` when included + */ +void gnrc_dhcpv6_client_6lbr_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_DHCPV6_CLIENT_6LBR_H */ +/** @} */ diff --git a/sys/net/gnrc/Kconfig b/sys/net/gnrc/Kconfig index a940e6d246..eef5446323 100644 --- a/sys/net/gnrc/Kconfig +++ b/sys/net/gnrc/Kconfig @@ -7,6 +7,7 @@ menu "GNRC Network stack" depends on MODULE_GNRC +rsource "application_layer/dhcpv6/Kconfig" rsource "link_layer/lorawan/Kconfig" rsource "netif/Kconfig" rsource "network_layer/ipv6/Kconfig" diff --git a/sys/net/gnrc/application_layer/dhcpv6/Kconfig b/sys/net/gnrc/application_layer/dhcpv6/Kconfig new file mode 100644 index 0000000000..2b55f9dc11 --- /dev/null +++ b/sys/net/gnrc/application_layer/dhcpv6/Kconfig @@ -0,0 +1,26 @@ +menuconfig KCONFIG_MODULE_GNRC_DHCPV6 + bool "Configure GNRC-part of DHCPv6" + depends on MODULE_GNRC_DHCPV6 + help + Configure GNRC-part of DHCPv6 via Kconfig. + +if KCONFIG_MODULE_GNRC_DHCPV6 + +if MODULE_GNRC_DHCPV6_CLIENT_6LBR +config GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM + int "Identifier for the upstream interface of the 6LoWPAN border router" + default 0 + help + Leave 0 to let the client pick the first non-6LoWPAN interface it finds + +config GNRC_DHCPV6_CLIENT_6LBR_STATIC_ROUTE + bool "Use static routes to upstream interface" + help + If set to 1 the border router will be configured to have a default + route via `fe80::1`. The link-local address `fe80::2` will be added so + that the upstream router can set a static route for the delegated + prefix via that address. It is recommended to increase at least @ref + CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF to that end. +endif # MODULE_GNRC_DHCPV6_CLIENT_6LBR + +endif # KCONFIG_MODULE_GNRC_DHCPV6 diff --git a/sys/net/gnrc/application_layer/dhcpv6/client_6lbr.c b/sys/net/gnrc/application_layer/dhcpv6/client_6lbr.c new file mode 100644 index 0000000000..bc4fa28959 --- /dev/null +++ b/sys/net/gnrc/application_layer/dhcpv6/client_6lbr.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018-20 Freie Universität Berlin + * + * 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. + */ + +/** + * @{ + * + * @file + * @author Martine S. Lenders + */ + +#include + +#include "event.h" +#include "log.h" +#include "net/dhcpv6/client.h" +#include "net/ipv6/addr.h" +#include "net/gnrc.h" +#include "net/gnrc/ipv6/nib/ft.h" +#include "net/gnrc/netif/internal.h" + +#include "net/gnrc/dhcpv6/client/6lbr.h" + +#if IS_USED(MODULE_AUTO_INIT_DHCPV6_CLIENT) +#error "Module `gnrc_dhcpv6_client_6lbr` is mutually exclusive to \ +`auto_init_dhcpv6_client`" +#endif + +static char _stack[DHCPV6_CLIENT_STACK_SIZE]; + +/** + * @brief Find upstream network interface + * + * Either the one network interface configured at compile-time with @ref + * CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM is picked or the first network + * interface that is not a 6LoWPAN interfaces if + * `CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM` is 0. + * + * @return The upstream network interface. + */ +static gnrc_netif_t *_find_upstream_netif(void) +{ + gnrc_netif_t *netif = NULL; + + if (CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM) { + return gnrc_netif_get_by_pid(CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM); + } + while ((netif = gnrc_netif_iter(netif))) { + if (!gnrc_netif_is_6lo(netif)) { + LOG_WARNING("DHCPv6: Selecting interface %d as upstream\n", + netif->pid); + return netif; + } + } + return NULL; +} + +/** + * @brief Configure upstream netif to be in line with configuration script + * + * Set route and link-local address in accordance to + * `dist/tools/ethos/setup_network.sh`. + * + * @note This might not be necessary with a properly set-up DHCPv6 server + * (automatically configures a route for the delegated prefix) and + * upstream router (sends periodic router advertisements). + * + * @param[in] upstream_netif The upstream netif The upstream netif + */ +static void _configure_upstream_netif(gnrc_netif_t *upstream_netif) +{ + if (IS_ACTIVE(CONFIG_GNRC_DHCPV6_CLIENT_6LBR_STATIC_ROUTE)) { + ipv6_addr_t addr = { + .u8 = { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } + }; + + /* set default route to host machine (as set-up in setup_network.sh) */ + gnrc_ipv6_nib_ft_add(NULL, 0, &addr, upstream_netif->pid, 0); + /* set additional link-local address to provide a well-known next hop + * for static route configuration on the host machine */ + addr.u8[15] = 2; + gnrc_netif_ipv6_addr_add(upstream_netif, &addr, 64, 0); + } +} + +/** + * @brief Configures all 6LoWPAN interfaces to request a 64-bit prefix + */ +static void _configure_dhcpv6_client(void) +{ + gnrc_netif_t *netif = NULL; + while ((netif = gnrc_netif_iter(netif))) { + if (gnrc_netif_is_6lo(netif)) { + dhcpv6_client_req_ia_pd(netif->pid, 64U); + } + } +} + +/** + * @brief The DHCPv6 client thread + */ +static void *_dhcpv6_cl_6lbr_thread(void *args) +{ + event_queue_t event_queue; + gnrc_netif_t *upstream_netif = _find_upstream_netif(); + + (void)args; + if (upstream_netif == NULL) { + LOG_ERROR("DHCPv6: No upstream interface found!\n"); + return NULL; + } + _configure_upstream_netif(upstream_netif); + /* initialize client event queue */ + event_queue_init(&event_queue); + /* initialize DHCPv6 client on border interface */ + dhcpv6_client_init(&event_queue, upstream_netif->pid); + /* configure client to request prefix delegation for WPAN interfaces */ + _configure_dhcpv6_client(); + /* start DHCPv6 client */ + dhcpv6_client_start(); + /* start event loop of DHCPv6 client */ + event_loop(&event_queue); /* never returns */ + return NULL; +} + +void gnrc_dhcpv6_client_6lbr_init(void) +{ + /* start DHCPv6 client thread to request prefix for WPAN */ + thread_create(_stack, DHCPV6_CLIENT_STACK_SIZE, + DHCPV6_CLIENT_PRIORITY, + THREAD_CREATE_STACKTEST, + _dhcpv6_cl_6lbr_thread, NULL, "dhcpv6-client"); +} + +/** @} */