int vtimer_usleep(uint32_t usecs) { timex_t offset = timex_set(0, usecs); return vtimer_sleep(offset); }
timex_t timex_from_uint64(const uint64_t timestamp) { return timex_set(timestamp / SEC_IN_USEC, timestamp % SEC_IN_USEC); }
timex_t vtimer_now() { timex_t t = timex_set(seconds, hwtimer_now()-longterm_tick_start); return t; }
unsigned int sleep(unsigned int seconds) { timex_t time = timex_set(seconds, 0); vtimer_sleep(time); return 0; }
static inline void _rtr_sol_reschedule(gnrc_ipv6_netif_t *iface, uint32_t sec_delay) { vtimer_remove(&iface->rtr_sol_timer); vtimer_set_msg(&iface->rtr_sol_timer, timex_set(sec_delay, 0), gnrc_ipv6_pid, GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL, iface); }
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, 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, &ipv6->src); 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; } switch (ar_opt->status) { case SIXLOWPAN_ND_STATUS_SUCCESS: DEBUG("6lo nd: address registration successful\n"); mutex_lock(&ipv6_iface->mutex); vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer, gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS, nc_entry); 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; } #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)) && (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 */ vtimer_remove(&nc_entry->type_timeout); vtimer_set_msg(&nc_entry->type_timeout, timex_set(reg_ltime * 60, 0), gnrc_ipv6_pid, GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT, nc_entry); } #endif default: break; } return status; }
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size) { uint8_t *buf = (uint8_t *)(rtr_adv + 1); gnrc_ipv6_nc_t *nc_entry = NULL; gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; #ifdef MODULE_GNRC_SIXLOWPAN_ND uint32_t next_rtr_sol = 0; #endif int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; uint16_t opt_offset = 0; if (!ipv6_addr_is_link_local(&ipv6->src) || ipv6_addr_is_multicast(&ipv6->src) || (ipv6->hl != 255) || (rtr_adv->code != 0) || (icmpv6_size < sizeof(ndp_rtr_adv_t))) { DEBUG("ndp: router advertisement was invalid\n"); /* ipv6 releases */ return; } /* get source from default router list */ nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); if (nc_entry == NULL) { /* not in default router list */ /* create default router list entry */ nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0, GNRC_IPV6_NC_IS_ROUTER); if (nc_entry == NULL) { DEBUG("ndp: error on default router list entry creation\n"); return; } } else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } /* set router life timer */ if (rtr_adv->ltime.u16 != 0) { uint16_t ltime = byteorder_ntohs(rtr_adv->ltime); #ifdef MODULE_GNRC_SIXLOWPAN_ND next_rtr_sol = ltime; #endif vtimer_remove(&nc_entry->rtr_timeout); vtimer_set_msg(&nc_entry->rtr_timeout, timex_set(ltime, 0), thread_getpid(), GNRC_NDP_MSG_RTR_TIMEOUT, nc_entry); } /* set current hop limit from message if available */ if (rtr_adv->cur_hl != 0) { if_entry->cur_hl = rtr_adv->cur_hl; } /* set flags from message */ if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) & GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; /* set reachable time from message if it is not the same as the random base * value */ if ((rtr_adv->reach_time.u32 != 0) && (if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) { _set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time)); } /* set retransmission timer from message */ if (rtr_adv->retrans_timer.u32 != 0) { if_entry->retrans_timer = timex_set(0, byteorder_ntohl(rtr_adv->retrans_timer)); timex_normalize(&if_entry->retrans_timer); } mutex_unlock(&if_entry->mutex); sicmpv6_size -= sizeof(ndp_rtr_adv_t); /* parse options */ while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_SL2A: if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt, l2src)) < 0) { /* -ENOTSUP can not happen */ /* invalid source link-layer address option */ return; } break; case NDP_OPT_MTU: if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) { /* invalid MTU option */ return; } break; case NDP_OPT_PI: if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) { /* invalid prefix information option */ return; } #ifdef MODULE_GNRC_SIXLOWPAN_ND if (byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime) < next_rtr_sol) { next_rtr_sol = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime); } #endif break; #ifdef MODULE_GNRC_SIXLOWPAN_ND case NDP_OPT_6CTX: if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type, (sixlowpan_nd_opt_6ctx_t *)opt)) { /* invalid 6LoWPAN context option */ return; } if (byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime) < (next_rtr_sol / 60)) { next_rtr_sol = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime) * 60; } break; #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER case NDP_OPT_ABR: gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size, (sixlowpan_nd_opt_abr_t *)opt); break; #endif } sicmpv6_size -= (opt->len * 8); } #if ENABLE_DEBUG && defined(MODULE_NG_SIXLOWPAN_ND) if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) { DEBUG("ndp: Router advertisement did not contain any source address information\n"); } #endif _stale_nc(iface, &ipv6->src, l2src, l2src_len); #ifdef MODULE_NG_SIXLOWPAN_ND if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { timex_t t = { 0, GNRC_NDP_RETRANS_TIMER }; /* stop multicast router solicitation retransmission timer */ vtimer_remove(&if_entry->rtr_sol_timer); /* 3/4 of the time should be "well before" enough the respective timeout * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */ next_rtr_sol *= 3; next_rtr_sol >>= 2; /* according to https://tools.ietf.org/html/rfc6775#section-5.3: * "In all cases, the RS retransmissions are terminated when an RA is * received." * Hence, reset router solicitation counter and reset timer. */ &nc_entry->rtr_sol_count = 0; gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol); gnrc_ndp_internal_send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &nc_entry->ipv6_addr); vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, t, gnrc_ipv6_pid, GNRC_NDP_MSG_NBR_SOL_RETRANS, nc_entry); }
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol, size_t icmpv6_size) { gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; uint16_t opt_offset = 0; uint8_t *buf = (uint8_t *)(rtr_sol + 1); /* check validity */ if ((ipv6->hl != 255) || (rtr_sol->code != 0) || (icmpv6_size < sizeof(ndp_rtr_sol_t))) { DEBUG("ndp: router solicitation was invalid\n"); return; } sicmpv6_size -= sizeof(ndp_rtr_sol_t); while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_SL2A: if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_sol->type, opt, l2src)) < 0) { /* -ENOTSUP can not happen */ /* invalid source link-layer address option */ return; } break; default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } _stale_nc(iface, &ipv6->src, l2src, l2src_len); /* send delayed */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) { timex_t delay; uint32_t ms = GNRC_NDP_MAX_RTR_ADV_DELAY; #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { ms = GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY; } #endif delay = timex_set(0, genrand_uint32_range(0, ms)); vtimer_remove(&if_entry->rtr_adv_timer); if (ipv6_addr_is_unspecified(&ipv6->src)) { /* either multicast, if source unspecified */ vtimer_set_msg(&if_entry->rtr_adv_timer, delay, gnrc_ipv6_pid, GNRC_NDP_MSG_RTR_ADV_RETRANS, if_entry); } else { /* or unicast, if source is known */ /* XXX: can't just use GNRC_NETAPI_MSG_TYPE_SND, since the next retransmission * must also be set. */ gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); vtimer_set_msg(&if_entry->rtr_adv_timer, delay, gnrc_ipv6_pid, GNRC_NDP_MSG_RTR_ADV_DELAY, nc_entry); } } } /* otherwise ignore silently */ }