From 6d1f012c9dca91523872e58c9e9660e788edd3e8 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 26 Feb 2018 17:35:39 +0100 Subject: [PATCH] gnrc_ipv6_nib: add support to handle RDNSSO --- sys/include/net/gnrc/ipv6/nib.h | 11 +++ sys/net/gnrc/network_layer/ipv6/nib/nib.c | 91 +++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index facc9e6ccf..a3acfa9066 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -222,6 +222,17 @@ extern "C" { * @note Only handled with @ref GNRC_IPV6_NIB_CONF_SLAAC != 0 */ #define GNRC_IPV6_NIB_VALID_ADDR (0x4fd2U) + +/** + * @brief Recursive DNS server timeout + * + * This message type is for the event of a recursive DNS server timeout. + * The expected message context is the [UDP end point](@ref sock_udp_ep_t) + * representing the DNS server. + * + * @note Only handled with @ref GNRC_IPV6_NIB_CONF_DNS != 0 + */ +#define GNRC_IPV6_NIB_RDNSS_TIMEOUT (0x4fd3U) /** @} */ /** diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib.c b/sys/net/gnrc/network_layer/ipv6/nib/nib.c index 4bc923948a..c726827ddc 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/nib.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib.c @@ -26,6 +26,9 @@ #include "net/gnrc/sixlowpan/nd.h" #include "net/ndp.h" #include "net/sixlowpan/nd.h" +#if GNRC_IPV6_NIB_CONF_DNS +#include "net/sock/dns.h" +#endif #include "_nib-internal.h" #include "_nib-arsm.h" @@ -46,6 +49,10 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; static gnrc_pktqueue_t _queue_pool[GNRC_IPV6_NIB_NUMOF]; #endif /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */ +#if GNRC_IPV6_NIB_CONF_DNS +static evtimer_msg_event_t _rdnss_timeout; +#endif + /** * @internal * @{ @@ -70,6 +77,9 @@ static void _handle_rtr_timeout(_nib_dr_entry_t *router); static void _handle_snd_na(gnrc_pktsnip_t *pkt); /* needs to be exported for 6LN's ARO handling */ void _handle_search_rtr(gnrc_netif_t *netif); +#if GNRC_IPV6_NIB_CONF_DNS +static void _handle_rdnss_timeout(sock_udp_ep_t *dns_server); +#endif /** @} */ void gnrc_ipv6_nib_init(void) @@ -355,6 +365,10 @@ void gnrc_ipv6_nib_handle_timer_event(void *ctx, uint16_t type) case GNRC_IPV6_NIB_VALID_ADDR: _handle_valid_addr(ctx); break; +#if GNRC_IPV6_NIB_CONF_DNS + case GNRC_IPV6_NIB_RDNSS_TIMEOUT: + _handle_rdnss_timeout(ctx); +#endif default: break; } @@ -388,6 +402,10 @@ void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif_t *netif, bool enable) */ static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_mtu_t *mtuo); +#if GNRC_IPV6_NIB_CONF_DNS +static uint32_t _handle_rdnsso(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, + const ndp_opt_rdnss_t *rdnsso); +#endif #if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_pi_t *pio, @@ -696,6 +714,14 @@ static void _handle_rtr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, #endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */ break; #endif /* GNRC_IPV6_NIB_CONF_6LN */ +#if GNRC_IPV6_NIB_CONF_DNS + case NDP_OPT_RDNSS: + next_timeout = _min(_handle_rdnsso(netif, + (icmpv6_hdr_t *)rtr_adv, + (ndp_opt_rdnss_t *)opt), + next_timeout); + break; +#endif default: break; } @@ -1225,6 +1251,13 @@ void _handle_search_rtr(gnrc_netif_t *netif) gnrc_netif_release(netif); } +#if GNRC_IPV6_NIB_CONF_DNS +static void _handle_rdnss_timeout(sock_udp_ep_t *dns_server) +{ + memset(dns_server, 0, sizeof(sock_udp_ep_t)); +} +#endif + static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, const ndp_opt_mtu_t *mtuo) { @@ -1236,6 +1269,64 @@ static void _handle_mtuo(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, } } +#if GNRC_IPV6_NIB_CONF_DNS +static uint32_t _handle_rdnsso(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6, + const ndp_opt_rdnss_t *rdnsso) +{ + uint32_t ltime = UINT32_MAX; + const ipv6_addr_t *addr; + + if ((rdnsso->len < NDP_OPT_RDNSS_MIN_LEN) || + (icmpv6->type != ICMPV6_RTR_ADV)) { + return ltime; + } + /* select first if unassigned, search possible address otherwise */ + addr = (sock_dns_server.port == 0) ? &rdnsso->addrs[0] : NULL; + if (addr == NULL) { + unsigned addrs_num = (rdnsso->len - 1) / 2; + for (unsigned i = 0; i < addrs_num; i++) { + if (memcmp(sock_dns_server.addr.ipv6, + &rdnsso->addrs[i], + sizeof(rdnsso->addrs[i])) == 0) { + addr = &rdnsso->addrs[i]; + break; + } + } + } +#if SOCK_HAS_IPV6 + ltime = byteorder_ntohl(rdnsso->ltime); + if (addr != NULL) { + if (ltime > 0) { + sock_dns_server.port = SOCK_DNS_PORT; + sock_dns_server.family = AF_INET6; + sock_dns_server.netif = netif->pid; + memcpy(sock_dns_server.addr.ipv6, rdnsso->addrs, + sizeof(sock_dns_server.addr.ipv6)); + + if (ltime < UINT32_MAX) { + /* the valid lifetime is given in seconds, but our timers work + * in milliseconds, so we have to scale down to the smallest + * possible value (UINT32_MAX - 1). This is however alright + * since we ask for a new router advertisement before this + * timeout expires */ + ltime = (ltime > (UINT32_MAX / MS_PER_SEC)) ? + (UINT32_MAX - 1) : ltime * MS_PER_SEC; + _evtimer_add(&sock_dns_server, GNRC_IPV6_NIB_RDNSS_TIMEOUT, + &_rdnss_timeout, ltime); + } + } + else { + evtimer_del(&_nib_evtimer, &_rdnss_timeout.event); + _handle_rdnss_timeout(&sock_dns_server); + } + } +#else + (void)addr; +#endif + return ltime; +} +#endif + static void _remove_prefix(const ipv6_addr_t *pfx, unsigned pfx_len) { _nib_offl_entry_t *offl = NULL;