From 15c828cf92d3b872de43d2b95b2ebf299fd3b6de Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 21 Mar 2018 11:49:40 +0000 Subject: [PATCH] gnrc_dhcpv6_client: provide GNRC-specific DHCPv6 parts --- Makefile.dep | 11 ++ makefiles/pseudomodules.inc.mk | 1 + sys/net/gnrc/Makefile | 3 + .../gnrc/application_layer/dhcpv6/Makefile | 5 + .../gnrc/application_layer/dhcpv6/client.c | 144 ++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 sys/net/gnrc/application_layer/dhcpv6/Makefile create mode 100644 sys/net/gnrc/application_layer/dhcpv6/client.c diff --git a/Makefile.dep b/Makefile.dep index 6ec0f59b9a..5c668eb48e 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -86,6 +86,17 @@ ifneq (,$(filter netdev_ieee802154,$(USEMODULE))) USEMODULE += random endif +ifneq (,$(filter gnrc_dhcpv6_%, $(USEMODULE))) + USEMODULE += gnrc_dhcpv6 +endif + +ifneq (,$(filter gnrc_dhcpv6_client,$(USEMODULE))) + USEMODULE += dhcpv6_client + USEMODULE += gnrc_ipv6_nib + USEMODULE += gnrc_netif + USEMODULE += gnrc_sock_udp +endif + ifneq (,$(filter gnrc_uhcpc,$(USEMODULE))) USEMODULE += uhcpc USEMODULE += gnrc_sock_udp diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 2b6b193665..281cdb6822 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -16,6 +16,7 @@ PSEUDOMODULES += ecc_% PSEUDOMODULES += emb6_router PSEUDOMODULES += event_% PSEUDOMODULES += fmt_% +PSEUDOMODULES += gnrc_dhcpv6_% PSEUDOMODULES += gnrc_ipv6_default PSEUDOMODULES += gnrc_ipv6_router PSEUDOMODULES += gnrc_ipv6_router_default diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile index 1a271b384c..991b41069e 100644 --- a/sys/net/gnrc/Makefile +++ b/sys/net/gnrc/Makefile @@ -1,3 +1,6 @@ +ifneq (,$(filter gnrc_dhcpv6,$(USEMODULE))) + DIRS += application_layer/dhcpv6 +endif ifneq (,$(filter gnrc_icmpv6,$(USEMODULE))) DIRS += network_layer/icmpv6 endif diff --git a/sys/net/gnrc/application_layer/dhcpv6/Makefile b/sys/net/gnrc/application_layer/dhcpv6/Makefile new file mode 100644 index 0000000000..c07775b726 --- /dev/null +++ b/sys/net/gnrc/application_layer/dhcpv6/Makefile @@ -0,0 +1,5 @@ +MODULE := gnrc_dhcpv6 + +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/gnrc/application_layer/dhcpv6/client.c b/sys/net/gnrc/application_layer/dhcpv6/client.c new file mode 100644 index 0000000000..c68d3666ef --- /dev/null +++ b/sys/net/gnrc/application_layer/dhcpv6/client.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 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 Lenders + */ + +#include "log.h" +#include "net/arp.h" +#include "net/dhcpv6.h" +#include "net/gnrc/ipv6/nib/pl.h" +#include "net/gnrc/netif.h" +#include "net/gnrc/rpl.h" +#include "net/sock.h" +#include "timex.h" + +#include "net/dhcpv6/client.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static char addr_str[IPV6_ADDR_MAX_STR_LEN]; + +unsigned dhcpv6_client_get_duid_l2(unsigned iface, dhcpv6_duid_l2_t *duid) +{ + gnrc_netif_t *netif; + uint8_t *l2addr = ((uint8_t *)(duid)) + sizeof(dhcpv6_duid_l2_t); + int res; + + duid->type = byteorder_htons(DHCPV6_DUID_TYPE_L2); + /* TODO make GNRC-independent */ + if (iface == SOCK_ADDR_ANY_NETIF) { + netif = gnrc_netif_iter(NULL); + } + else { + netif = gnrc_netif_get_by_pid(iface); + } + assert(netif != NULL); + if ((res = gnrc_netapi_get(netif->pid, NETOPT_ADDRESS_LONG, 0, + l2addr, GNRC_NETIF_L2ADDR_MAXLEN)) > 0) { + duid->l2type = byteorder_htons(ARP_HWTYPE_EUI64); + } + else { + switch (netif->device_type) { + case NETDEV_TYPE_ETHERNET: + case NETDEV_TYPE_BLE: + case NETDEV_TYPE_ESP_NOW: + if ((res = gnrc_netapi_get(netif->pid, + NETOPT_ADDRESS, + 0, l2addr, + GNRC_NETIF_L2ADDR_MAXLEN)) > 0) { + duid->l2type = byteorder_htons(ARP_HWTYPE_ETHERNET); + break; + } + /* intentionally falls through */ + default: + LOG_ERROR("DHCPv6 client: Link-layer type of interface %u not supported " + "for DUID creation\n", netif->pid); + return 0; + } + } + return (uint8_t)res + sizeof(dhcpv6_duid_l2_t); +} + +void dhcpv6_client_conf_prefix(unsigned iface, const ipv6_addr_t *pfx, + unsigned pfx_len, uint32_t valid, + uint32_t pref) +{ + gnrc_netif_t *netif = gnrc_netif_get_by_pid(iface); + eui64_t iid; + ipv6_addr_t addr; + + assert(netif != NULL); + DEBUG("GNRC DHCPv6 client: (re-)configure prefix %s/%d\n", + ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), pfx_len); + if (gnrc_netapi_get(netif->pid, NETOPT_IPV6_IID, 0, &iid, + sizeof(eui64_t)) >= 0) { + ipv6_addr_set_aiid(&addr, iid.uint8); + } + else { + LOG_WARNING("GNRC DHCPv6 client: cannot get IID of netif %u\n", netif->pid); + return; + } + ipv6_addr_init_prefix(&addr, pfx, pfx_len); + /* add address as tentative */ + if (gnrc_netif_ipv6_addr_add(netif, &addr, pfx_len, + GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE & 0x1) > 0) { + /* update lifetime */ + if (valid < UINT32_MAX) { /* UINT32_MAX means infinite lifetime */ + /* the valid lifetime is given in seconds, but the NIB's timers work + * in microseconds, so we have to scale down to the smallest + * possible value (UINT32_MAX - 1). */ + valid = (valid > (UINT32_MAX / MS_PER_SEC)) ? + (UINT32_MAX - 1) : valid * MS_PER_SEC; + } + if (pref < UINT32_MAX) { /* UINT32_MAX means infinite lifetime */ + /* same treatment for pref */ + pref = (pref > (UINT32_MAX / MS_PER_SEC)) ? + (UINT32_MAX - 1) : pref * MS_PER_SEC; + } + gnrc_ipv6_nib_pl_set(netif->pid, pfx, pfx_len, valid, pref); +#if defined(MODULE_GNRC_IPV6_NIB) && GNRC_IPV6_NIB_CONF_6LBR && \ + GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + gnrc_ipv6_nib_abr_add(&addr); +#endif +#ifdef MODULE_GNRC_RPL + gnrc_rpl_init(netif->pid); + gnrc_rpl_instance_t *inst = gnrc_rpl_instance_get(GNRC_RPL_DEFAULT_INSTANCE); + if (inst) { + gnrc_rpl_instance_remove(inst); + } + gnrc_rpl_root_init(GNRC_RPL_DEFAULT_INSTANCE, &addr, false, false); +#endif + } +} + +uint32_t dhcpv6_client_prefix_valid_until(unsigned netif, + const ipv6_addr_t *pfx, + unsigned pfx_len) +{ + gnrc_ipv6_nib_pl_t ple; + void *state = NULL; + uint32_t max_valid = 0; + + while (gnrc_ipv6_nib_pl_iter(netif, &state, &ple)) { + if ((ple.pfx_len == pfx_len) && + ((ple.valid_until / MS_PER_SEC) > max_valid) && + (ipv6_addr_match_prefix(&ple.pfx, + pfx) >= ple.pfx_len)) { + max_valid = ple.valid_until / MS_PER_SEC; + } + } + return max_valid; +} + +/** @} */