void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, uint8_t pfx_len) { ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; int idx; uint8_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; if (!(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR)) { DEBUG("nib: interface %i has no link-layer addresses\n", netif->pid); return; } DEBUG("nib: add address based on %s/%u automatically to interface %u\n", ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), pfx_len, netif->pid); #if GNRC_IPV6_NIB_CONF_6LN bool new_address = false; #endif /* GNRC_IPV6_NIB_CONF_6LN */ gnrc_netif_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]); ipv6_addr_init_prefix(&addr, pfx, pfx_len); if ((idx = gnrc_netif_ipv6_addr_idx(netif, &addr)) < 0) { if ((idx = gnrc_netif_ipv6_addr_add_internal(netif, &addr, pfx_len, flags)) < 0) { DEBUG("nib: Can't add link-local address on interface %u\n", netif->pid); return; } #if GNRC_IPV6_NIB_CONF_6LN new_address = true; #endif /* GNRC_IPV6_NIB_CONF_6LN */ } #if GNRC_IPV6_NIB_CONF_6LN /* mark link-local addresses as valid on 6LN */ if (gnrc_netif_is_6ln(netif) && ipv6_addr_is_link_local(pfx)) { /* don't do this beforehand or risk a deadlock: * - gnrc_netif_ipv6_addr_add_internal() adds VALID (i.e. manually configured * addresses to the prefix list locking the NIB's mutex which is already * locked here) */ netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; } #endif /* GNRC_IPV6_NIB_CONF_6LN */ #if GNRC_IPV6_NIB_CONF_6LN if (new_address && gnrc_netif_is_6ln(netif) && !gnrc_netif_is_6lbr(netif)) { _handle_rereg_address(&netif->ipv6.addrs[idx]); } #else /* GNRC_IPV6_NIB_CONF_6LN */ (void)idx; #endif /* GNRC_IPV6_NIB_CONF_6LN */ }
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; }