void _handle_snd_mc_ra(gnrc_netif_t *netif) { gnrc_netif_acquire(netif); assert(netif != NULL); if (!gnrc_netif_is_6ln(netif)) { bool final_ra = (netif->ipv6.ra_sent > (UINT8_MAX - NDP_MAX_FIN_RA_NUMOF)); uint32_t next_ra_time = random_uint32_range(NDP_MIN_RA_INTERVAL_MS, NDP_MAX_RA_INTERVAL_MS); uint32_t next_scheduled = _evtimer_lookup(netif, GNRC_IPV6_NIB_SND_MC_RA); /* router has router advertising interface or the RA is one of the * (now deactivated) routers final one (and there is no next * scheduled within the possible time for next_ra_time) */ if ((final_ra && (next_scheduled > NDP_MAX_RA_INTERVAL_MS)) || gnrc_netif_is_rtr_adv(netif)) { _snd_rtr_advs(netif, NULL, final_ra); netif->ipv6.last_ra = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX; if ((netif->ipv6.ra_sent < NDP_MAX_INIT_RA_NUMOF) || final_ra) { if ((netif->ipv6.ra_sent < NDP_MAX_INIT_RA_NUMOF) && (next_ra_time > NDP_MAX_INIT_RA_INTERVAL)) { next_ra_time = NDP_MAX_INIT_RA_INTERVAL; } netif->ipv6.ra_sent++; } /* netif->ipv6.ra_sent overflowed => this was our last final RA */ if (netif->ipv6.ra_sent != 0) { _evtimer_add(netif, GNRC_IPV6_NIB_SND_MC_RA, &netif->ipv6.snd_mc_ra, next_ra_time); } } } gnrc_netif_release(netif); }
_nib_abr_entry_t *_handle_abro(const sixlowpan_nd_opt_abr_t *abro) { _nib_abr_entry_t *abr = NULL; if (abro->len != SIXLOWPAN_ND_OPT_ABR_LEN) { /* ignore silently */ return NULL; } abr = _nib_abr_add(&abro->braddr); if (abr != NULL) { uint32_t abro_version = sixlowpan_nd_opt_abr_get_version(abro); uint16_t ltime = byteorder_ntohs(abro->ltime); if (abr->version >= abro_version) { abr->version = abro_version; abr->valid_until = _now_min() + ltime; } /* correct for default value */ ltime = (ltime == 0) ? SIXLOWPAN_ND_OPT_ABR_LTIME_DEFAULT : ltime; _evtimer_add(abr, GNRC_IPV6_NIB_ABR_TIMEOUT, &abr->timeout, /* UINT16_MAX min < UINT32_MAX ms so no risk of overflow */ MS_PER_SEC * SEC_PER_MIN * ltime); } return abr; }
void _handle_rereg_address(const ipv6_addr_t *addr) { gnrc_netif_t *netif = gnrc_netif_get_by_ipv6_addr(addr); _nib_dr_entry_t *router = _nib_drl_get_dr(); const bool router_reachable = (router != NULL) && _is_reachable(router->next_hop); if (router_reachable && (netif != NULL)) { assert((unsigned)netif->pid == _nib_onl_get_if(router->next_hop)); DEBUG("nib: Re-registering %s", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); DEBUG(" with upstream router %s\n", ipv6_addr_to_str(addr_str, &router->next_hop->ipv6, sizeof(addr_str))); _snd_ns(&router->next_hop->ipv6, netif, addr, &router->next_hop->ipv6); } else { DEBUG("nib: Couldn't re-register %s, no current router found or address " "wasn't assigned to any interface anymore.\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); } if (netif != NULL) { int idx = gnrc_netif_ipv6_addr_idx(netif, addr); if (router_reachable && (_is_valid(netif, idx) || (_is_tentative(netif, idx) && (gnrc_netif_ipv6_addr_dad_trans(netif, idx) < SIXLOWPAN_ND_REG_TRANSMIT_NUMOF)))) { uint32_t retrans_time; if (_is_valid(netif, idx)) { retrans_time = SIXLOWPAN_ND_MAX_RS_SEC_INTERVAL * MS_PER_SEC; } else { retrans_time = netif->ipv6.retrans_time; /* increment encoded retransmission count */ netif->ipv6.addrs_flags[idx]++; } _evtimer_add(&netif->ipv6.addrs[idx], GNRC_IPV6_NIB_REREG_ADDRESS, &netif->ipv6.addrs_timers[idx], retrans_time); } else { netif->ipv6.rs_sent = 0; _handle_search_rtr(netif); } } }
void _handle_dad(const ipv6_addr_t *addr) { ipv6_addr_t sol_nodes; gnrc_netif_t *netif = NULL; int idx = _get_netif_state(&netif, addr); if (idx >= 0) { ipv6_addr_set_solicited_nodes(&sol_nodes, addr); _snd_ns(addr, netif, &ipv6_addr_unspecified, &sol_nodes); _evtimer_add((void *)addr, GNRC_IPV6_NIB_VALID_ADDR, &netif->ipv6.addrs_timers[idx], netif->ipv6.retrans_time); } if (netif != NULL) { /* was acquired in `_get_netif_state()` */ gnrc_netif_release(netif); } }
uint8_t _handle_aro(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, const icmpv6_hdr_t *icmpv6, const sixlowpan_nd_opt_ar_t *aro, const ndp_opt_t *sl2ao, _nib_onl_entry_t *nce) { assert(netif != NULL); if (gnrc_netif_is_6ln(netif) && (aro->len == SIXLOWPAN_ND_OPT_AR_LEN)) { DEBUG("nib: valid ARO received\n"); DEBUG(" - length: %u\n", aro->len); DEBUG(" - status: %u\n", aro->status); DEBUG(" - registration lifetime: %u\n", byteorder_ntohs(aro->ltime)); DEBUG(" - EUI-64: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", aro->eui64.uint8[0], aro->eui64.uint8[1], aro->eui64.uint8[2], aro->eui64.uint8[3], aro->eui64.uint8[4], aro->eui64.uint8[5], aro->eui64.uint8[6], aro->eui64.uint8[7]); if (icmpv6->type == ICMPV6_NBR_ADV) { if (!_is_iface_eui64(netif, &aro->eui64)) { DEBUG("nib: ARO EUI-64 is not mine, ignoring ARO\n"); return _ADDR_REG_STATUS_IGNORE; } switch (aro->status) { case SIXLOWPAN_ND_STATUS_SUCCESS: { uint16_t ltime = byteorder_ntohs(aro->ltime); uint32_t rereg_time; int idx = gnrc_netif_ipv6_addr_idx(netif, &ipv6->dst); /* if ltime 1min, reschedule NS in 30sec, otherwise 1min * before timeout */ rereg_time = (ltime == 1U) ? (30 * MS_PER_SEC) : (ltime - 1U) * SEC_PER_MIN * MS_PER_SEC; DEBUG("nib: Address registration of %s successful. " "Scheduling re-registration in %" PRIu32 "ms\n", ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)), rereg_time); netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; _evtimer_add(&netif->ipv6.addrs[idx], GNRC_IPV6_NIB_REREG_ADDRESS, &netif->ipv6.addrs_timers[idx], rereg_time); break; } case SIXLOWPAN_ND_STATUS_DUP: DEBUG("nib: Address registration reports duplicate. " "Removing address %s%%%u\n", ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)), netif->pid); gnrc_netif_ipv6_addr_remove_internal(netif, &ipv6->dst); /* TODO: generate new address */ break; case SIXLOWPAN_ND_STATUS_NC_FULL: { DEBUG("nib: Router's neighbor cache is full. " "Searching new router for DAD\n"); _nib_dr_entry_t *dr = _nib_drl_get(&ipv6->src, netif->pid); assert(dr != NULL); /* otherwise we wouldn't be here */ _nib_drl_remove(dr); if (_nib_drl_iter(NULL) == NULL) { /* no DRL left */ netif->ipv6.rs_sent = 0; /* search (hopefully) new router */ _handle_search_rtr(netif); } else { assert(dr->next_hop != NULL); _handle_rereg_address(&ipv6->dst); } } break; } return aro->status; } #if GNRC_IPV6_NIB_CONF_6LR else if (gnrc_netif_is_6lr(netif) && (icmpv6->type == ICMPV6_NBR_SOL)) { return _reg_addr_upstream(netif, ipv6, icmpv6, aro, sl2ao, nce); } #else /* GNRC_IPV6_NIB_CONF_6LR */ (void)sl2ao; (void)nce; #endif /* GNRC_IPV6_NIB_CONF_6LR */ } #if ENABLE_DEBUG else if (aro->len != SIXLOWPAN_ND_OPT_AR_LEN) { DEBUG("nib: ARO of unexpected length %u, ignoring ARO\n", aro->len); } #endif /* ENABLE_DEBUG */ return _ADDR_REG_STATUS_IGNORE; }