void gnrc_ndp_internal_set_state(gnrc_ipv6_nc_t *nc_entry, uint8_t state) { gnrc_ipv6_netif_t *ipv6_iface; uint32_t t = GNRC_NDP_FIRST_PROBE_DELAY * SEC_IN_USEC; nc_entry->flags &= ~GNRC_IPV6_NC_STATE_MASK; nc_entry->flags |= state; DEBUG("ndp internal: set %s state to ", ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str))); switch (state) { case GNRC_IPV6_NC_STATE_REACHABLE: ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface); DEBUG("REACHABLE (reachable time = %" PRIu32 " us)\n", ipv6_iface->reach_time); t = ipv6_iface->reach_time; /* we intentionally fall through here to set the desired timeout t */ case GNRC_IPV6_NC_STATE_DELAY: #if ENABLE_DEBUG if (state == GNRC_IPV6_NC_STATE_DELAY) { DEBUG("DELAY (probe with unicast NS in %u seconds)\n", GNRC_NDP_FIRST_PROBE_DELAY); } #endif gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, t, GNRC_NDP_MSG_NC_STATE_TIMEOUT, gnrc_ipv6_pid); break; case GNRC_IPV6_NC_STATE_PROBE: ipv6_iface = gnrc_ipv6_netif_get(nc_entry->iface); nc_entry->probes_remaining = GNRC_NDP_MAX_UC_NBR_SOL_NUMOF; DEBUG("PROBE (probe with %" PRIu8 " unicast NS every %" PRIu32 " us)\n", nc_entry->probes_remaining, ipv6_iface->retrans_timer); gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr, &nc_entry->ipv6_addr); mutex_lock(&ipv6_iface->mutex); gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, ipv6_iface->retrans_timer, GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid); mutex_unlock(&ipv6_iface->mutex); break; #ifdef ENABLE_DEBUG case GNRC_IPV6_NC_STATE_STALE: DEBUG("STALE (go into DELAY on next packet)\n"); break; #endif default: DEBUG("errorneous or unknown\n"); break; } }
gnrc_ipv6_nc_t *gnrc_ipv6_nc_still_reachable(const ipv6_addr_t *ipv6_addr) { gnrc_ipv6_nc_t *entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, ipv6_addr); if (entry == NULL) { DEBUG("ipv6_nc: No entry found for %s\n", ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str))); return NULL; } if ((gnrc_ipv6_nc_get_state(entry) != GNRC_IPV6_NC_STATE_INCOMPLETE) && (gnrc_ipv6_nc_get_state(entry) != GNRC_IPV6_NC_STATE_UNMANAGED)) { #if defined(MODULE_GNRC_IPV6_NETIF) && defined(MODULE_VTIMER) && defined(MODULE_GNRC_IPV6) gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(entry->iface); timex_t t = iface->reach_time; gnrc_ndp_internal_reset_nbr_sol_timer(entry, (uint32_t) timex_uint64(t), GNRC_NDP_MSG_NC_STATE_TIMEOUT, gnrc_ipv6_pid); #endif DEBUG("ipv6_nc: Marking entry %s as reachable\n", ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str))); entry->flags &= ~(GNRC_IPV6_NC_STATE_MASK >> GNRC_IPV6_NC_STATE_POS); entry->flags |= (GNRC_IPV6_NC_STATE_REACHABLE >> GNRC_IPV6_NC_STATE_POS); }
void gnrc_sixlowpan_nd_wakeup(void) { gnrc_ipv6_nc_t *router = gnrc_ipv6_nc_get_next_router(NULL); while (router) { gnrc_sixlowpan_nd_uc_rtr_sol(router); gnrc_ndp_internal_send_nbr_sol(router->iface, NULL, &router->ipv6_addr, &router->ipv6_addr); gnrc_ndp_internal_reset_nbr_sol_timer(router, GNRC_NDP_RETRANS_TIMER, GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid); } }
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, ipv6_addr_t *addr, sixlowpan_nd_opt_ar_t *ar_opt, uint8_t *sl2a, size_t sl2a_len) { eui64_t eui64; gnrc_ipv6_netif_t *ipv6_iface; gnrc_ipv6_nc_t *nc_entry; uint8_t status = 0; (void)sl2a; (void)sl2a_len; if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } if (gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, &eui64, sizeof(eui64)) < 0) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } ipv6_iface = gnrc_ipv6_netif_get(iface); nc_entry = gnrc_ipv6_nc_get(iface, addr); switch (icmpv6_type) { case ICMPV6_NBR_ADV: if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { DEBUG("6lo nd: interface not a 6LoWPAN interface\n"); return 0; } if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } /* we expect the sender to be already in neighbor cache, if not we * ignore it */ if (nc_entry == NULL) { DEBUG("6lo nd: sending router not in neighbor cache\n"); return 0; } switch (ar_opt->status) { case SIXLOWPAN_ND_STATUS_SUCCESS: DEBUG("6lo nd: address registration successful\n"); mutex_lock(&ipv6_iface->mutex); /* reschedule 1 minute before lifetime expires */ gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, SEC_IN_USEC * 60 * (uint32_t)(byteorder_ntohs(ar_opt->ltime) -1), GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid); mutex_unlock(&ipv6_iface->mutex); break; case SIXLOWPAN_ND_STATUS_DUP: DEBUG("6lo nd: address registration determined duplicated\n"); /* TODO: handle DAD failed case */ gnrc_ipv6_netif_remove_addr(iface, &ipv6->dst); /* address should not be used anymore */ break; case SIXLOWPAN_ND_STATUS_NC_FULL: DEBUG("6lo nd: neighbor cache on router is full\n"); gnrc_ipv6_nc_remove(iface, &ipv6->src); /* try to find another router */ gnrc_sixlowpan_nd_init(ipv6_iface); break; default: DEBUG("6lo nd: unknown status for registration received\n"); break; } break; #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER case ICMPV6_NBR_SOL: if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && !(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { DEBUG("6lo nd: interface not a 6LoWPAN or forwarding interface\n"); return 0; } if ((ar_opt->status != 0) || ipv6_addr_is_unspecified(&ipv6->src)) { /* discard silently */ return 0; } /* TODO multihop DAD */ if ((nc_entry != NULL) && ((gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) && ((nc_entry->eui64.uint64.u64 != 0) && (ar_opt->eui64.uint64.u64 != nc_entry->eui64.uint64.u64))) { /* there is already another node with this address */ DEBUG("6lo nd: duplicate address detected\n"); status = SIXLOWPAN_ND_STATUS_DUP; } else if ((nc_entry != NULL) && (ar_opt->ltime.u16 == 0)) { gnrc_ipv6_nc_remove(iface, &ipv6->src); /* TODO, notify routing protocol */ } else if (ar_opt->ltime.u16 != 0) { /* TODO: multihop DAD behavior */ uint16_t reg_ltime; if (nc_entry == NULL) { if ((nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len, GNRC_IPV6_NC_STATE_STALE)) == NULL) { DEBUG("6lo nd: neighbor cache is full\n"); return SIXLOWPAN_ND_STATUS_NC_FULL; } nc_entry->eui64 = ar_opt->eui64; } nc_entry->flags &= ~GNRC_IPV6_NC_TYPE_MASK; nc_entry->flags |= GNRC_IPV6_NC_TYPE_REGISTERED; reg_ltime = byteorder_ntohs(ar_opt->ltime); /* TODO: notify routing protocol */ xtimer_set_msg(&nc_entry->type_timeout, (reg_ltime * 60 * SEC_IN_USEC), &nc_entry->type_timeout_msg, gnrc_ipv6_pid); } break; #endif default: break; } return status; }