diff --git a/sys/include/net/gnrc/dhcpv6/client/6lbr.h b/sys/include/net/gnrc/dhcpv6/client/6lbr.h index f622d236ab..c35cfd484c 100644 --- a/sys/include/net/gnrc/dhcpv6/client/6lbr.h +++ b/sys/include/net/gnrc/dhcpv6/client/6lbr.h @@ -34,6 +34,18 @@ extern "C" { #define CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM (0) #endif +/** + * @brief 6LoWPAN compression context lifetime for configured prefixes in + * minutes + * + * Must be between 1 and 255 + * + * @see [RFC 6775, section 4.2](https://tools.ietf.org/html/rfc6775#section-4.2) + */ +#ifndef CONFIG_GNRC_DHCPV6_CLIENT_6LBR_6LO_CTX_MIN +#define CONFIG_GNRC_DHCPV6_CLIENT_6LBR_6LO_CTX_MIN (60U) +#endif + /** * @brief Use static routes to upstream router * diff --git a/sys/net/gnrc/application_layer/dhcpv6/Kconfig b/sys/net/gnrc/application_layer/dhcpv6/Kconfig index 2b55f9dc11..c6b15a0916 100644 --- a/sys/net/gnrc/application_layer/dhcpv6/Kconfig +++ b/sys/net/gnrc/application_layer/dhcpv6/Kconfig @@ -13,6 +13,14 @@ config GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM help Leave 0 to let the client pick the first non-6LoWPAN interface it finds +config GNRC_DHCPV6_CLIENT_6LBR_6LO_CTX_MIN + int "6LoWPAN compression context lifetime for configured prefixes in minutes" + default 60 + range 1 255 + help + @see [RFC 6775, section 4.2](https://tools.ietf.org/html/rfc6775#section-4.2) + + config GNRC_DHCPV6_CLIENT_6LBR_STATIC_ROUTE bool "Use static routes to upstream interface" help diff --git a/sys/net/gnrc/application_layer/dhcpv6/client.c b/sys/net/gnrc/application_layer/dhcpv6/client.c index b8443d1796..c0014b1981 100644 --- a/sys/net/gnrc/application_layer/dhcpv6/client.c +++ b/sys/net/gnrc/application_layer/dhcpv6/client.c @@ -16,7 +16,9 @@ #include "log.h" #include "net/arp.h" #include "net/dhcpv6.h" +#include "net/gnrc/dhcpv6/client/6lbr.h" #include "net/gnrc/ipv6/nib/pl.h" +#include "net/gnrc/sixlowpan/ctx.h" #include "net/gnrc/netif.h" #include "net/gnrc/rpl.h" #include "net/sock.h" @@ -70,6 +72,44 @@ unsigned dhcpv6_client_get_duid_l2(unsigned iface, dhcpv6_duid_l2_t *duid) return (uint8_t)res + sizeof(dhcpv6_duid_l2_t); } +static bool _ctx_match(const gnrc_sixlowpan_ctx_t *ctx, + const ipv6_addr_t *prefix, uint8_t prefix_len) +{ + return (ctx != NULL) && + (ctx->prefix_len == prefix_len) && + (ipv6_addr_match_prefix(&ctx->prefix, prefix) >= prefix_len); +} + +static void _update_6ctx(const ipv6_addr_t *prefix, uint8_t prefix_len) +{ + gnrc_sixlowpan_ctx_t *ctx = gnrc_sixlowpan_ctx_lookup_addr(prefix); + uint8_t cid = 0; + + if (!_ctx_match(ctx, prefix, prefix_len)) { + /* While the context is a prefix match, the defined prefix within the + * context does not match => use new context */ + ctx = NULL; + } + else { + cid = ctx->flags_id & GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK; + } + /* find first free context ID */ + if (ctx == NULL) { + while (((ctx = gnrc_sixlowpan_ctx_lookup_id(cid)) != NULL) && + !_ctx_match(ctx, prefix, prefix_len)) { + cid++; + } + } + if (cid < GNRC_SIXLOWPAN_CTX_SIZE) { + DEBUG("DHCP client: add compression context %u for prefix %s/%u\n", cid, + ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str)), + prefix_len); + gnrc_sixlowpan_ctx_update(cid, (ipv6_addr_t *)prefix, prefix_len, + CONFIG_GNRC_DHCPV6_CLIENT_6LBR_6LO_CTX_MIN, + true); + } +} + void dhcpv6_client_conf_prefix(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len, uint32_t valid, uint32_t pref) @@ -110,6 +150,9 @@ void dhcpv6_client_conf_prefix(unsigned iface, const ipv6_addr_t *pfx, if (IS_USED(MODULE_GNRC_IPV6_NIB) && GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C) { + if (IS_USED(MODULE_GNRC_SIXLOWPAN_CTX)) { + _update_6ctx(pfx, pfx_len); + } (void)gnrc_ipv6_nib_abr_add(&addr); } if (IS_USED(MODULE_GNRC_RPL)) {