static inline void _set_reach_time(gnrc_ipv6_netif_t *if_entry, uint32_t mean) { uint32_t reach_time = genrand_uint32_range(GNRC_NDP_MIN_RAND, GNRC_NDP_MAX_RAND); if_entry->reach_time_base = mean; /* to avoid floating point number computation and have higher value entropy, the * boundaries for the random value are multiplied by 10 and we need to account for that */ reach_time = (reach_time * if_entry->reach_time_base) / 10; if_entry->reach_time = reach_time; }
void ng_ndp_netif_add(ng_ipv6_netif_t *iface) { uint32_t reach_time = genrand_uint32_range(NG_NDP_MIN_RAND, NG_NDP_MAX_RAND); /* set default values */ mutex_lock(&iface->mutex); iface->reach_time_base = NG_NDP_REACH_TIME; reach_time = (reach_time * iface->reach_time_base) / 10; iface->reach_time = timex_set(0, reach_time); timex_normalize(&iface->reach_time); iface->retrans_timer = timex_set(0, NG_NDP_RETRANS_TIMER); timex_normalize(&iface->retrans_timer); mutex_unlock(&iface->mutex); }
static void _send_rtr_adv(gnrc_ipv6_netif_t *iface, ipv6_addr_t *dst) { bool fin; uint32_t interval; mutex_lock(&iface->mutex); fin = (iface->adv_ltime == 0); assert((iface->min_adv_int != 0) && (iface->max_adv_int != 0)); interval = genrand_uint32_range(iface->min_adv_int, iface->max_adv_int); if (!fin && !((iface->flags | GNRC_IPV6_NETIF_FLAGS_ROUTER) && (iface->flags | GNRC_IPV6_NETIF_FLAGS_RTR_ADV))) { DEBUG("ndp rtr: interface %" PRIkernel_pid " is not an advertising interface\n", iface->pid); return; } if (iface->rtr_adv_count > 1) { /* regard for off-by-one error */ iface->rtr_adv_count--; if (!fin && (interval > GNRC_NDP_MAX_INIT_RTR_ADV_INT)) { interval = GNRC_NDP_MAX_INIT_RTR_ADV_INT; } } if (!fin || (iface->rtr_adv_count > 1)) { /* regard for off-by-one-error */ /* reset timer for next router advertisement */ xtimer_remove(&iface->rtr_adv_timer); iface->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS; iface->rtr_adv_msg.content.ptr = (char *) iface; xtimer_set_msg(&iface->rtr_adv_timer, interval * SEC_IN_USEC, &iface->rtr_adv_msg, gnrc_ipv6_pid); } mutex_unlock(&iface->mutex); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { ipv6_addr_t *src = &iface->addrs[i].addr; if (!ipv6_addr_is_unspecified(src) && ipv6_addr_is_link_local(src) && !gnrc_ipv6_netif_addr_is_non_unicast(src)) { /* send one for every link local address (ideally there is only one) */ gnrc_ndp_internal_send_rtr_adv(iface->pid, src, dst, fin); } } }
static int _implicit_bind(socket_t *s, void *addr) { ipv6_addr_t unspec; ipv6_addr_t *best_match; int res; /* TODO: ensure that this port hasn't been used yet */ s->src_port = (uint16_t)genrand_uint32_range(1LU << 10U, 1LU << 16U); /* find the best matching source address */ if ((best_match = conn_find_best_source(addr)) == NULL) { ipv6_addr_set_unspecified(&unspec); best_match = &unspec; } switch (s->type) { #ifdef MODULE_CONN_TCP case SOCK_STREAM: res = conn_tcp_create(&s->conn.udp, best_match, sizeof(unspec), s->domain, s->src_port); break; #endif #ifdef MODULE_CONN_UDP case SOCK_DGRAM: res = conn_udp_create(&s->conn.udp, best_match, sizeof(unspec), s->domain, s->src_port); break; #endif default: res = -1; break; } if (res < 0) { errno = -res; } else { s->bound = true; } return res; }
void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst, bool supply_tl2a, gnrc_pktsnip_t *ext_opts) { gnrc_pktsnip_t *hdr, *pkt = ext_opts; uint8_t adv_flags = 0; DEBUG("ndp internal: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s, supply_tl2a: %d)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a); if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) && (gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) { adv_flags |= NDP_NBR_ADV_FLAGS_R; } if (ipv6_addr_is_unspecified(dst)) { ipv6_addr_set_all_nodes_multicast(dst, IPV6_ADDR_MCAST_SCP_LINK_LOCAL); } else { adv_flags |= NDP_NBR_ADV_FLAGS_S; } if (supply_tl2a) { uint8_t l2src[8]; size_t l2src_len; /* we previously checked if we are the target, so we can take our L2src */ l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add target address link-layer address option */ pkt = gnrc_ndp_opt_tl2a_build(l2src, l2src_len, pkt); if (pkt == NULL) { DEBUG("ndp internal: error allocating Target Link-layer address option.\n"); gnrc_pktbuf_release(ext_opts); return; } } } /* TODO: also check if the node provides proxy servies for tgt */ if ((pkt != NULL) && !gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { /* TL2A is not supplied and tgt is not anycast */ adv_flags |= NDP_NBR_ADV_FLAGS_O; } hdr = gnrc_ndp_nbr_adv_build(adv_flags, tgt, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Neighbor advertisement.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, NULL); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } if (gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { /* avoid collision for anycast addresses * (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */ uint32_t delay = genrand_uint32_range(0, GNRC_NDP_MAX_AC_TGT_DELAY * SEC_IN_USEC); gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, dst); DEBUG("ndp internal: delay neighbor advertisement for %" PRIu32 " sec.", (delay / SEC_IN_USEC)); /* nc_entry must be set so no need to check it */ assert(nc_entry); _send_delayed(&nc_entry->nbr_adv_timer, &nc_entry->nbr_adv_msg, delay, hdr); } else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) { DEBUG("ndp internal: unable to send neighbor advertisement\n"); gnrc_pktbuf_release(hdr); } }
static inline uint32_t _binary_exp_backoff(uint32_t base_sec, unsigned int exp) { return genrand_uint32_range(0, (1 << exp)) * base_sec; }
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); #if ENABLE_DEBUG if (sicmpv6_size < 0) { DEBUG("ndp: Option parsing out of sync.\n"); } #endif } _stale_nc(iface, &ipv6->src, l2src, l2src_len); /* send delayed */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) { uint32_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 = genrand_uint32_range(0, ms); xtimer_remove(&if_entry->rtr_adv_timer); #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* in case of a 6LBR we have to check if the interface is actually * the 6lo interface */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); if (nc_entry != NULL) { if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY; if_entry->rtr_adv_msg.content.ptr = (char *) nc_entry; xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg, gnrc_ipv6_pid); } } #elif defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER) if (ipv6_addr_is_unspecified(&ipv6->src)) { /* either multicast, if source unspecified */ if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS; if_entry->rtr_adv_msg.content.ptr = (char *) if_entry; xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg, gnrc_ipv6_pid); } 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); xtimer_set_msg(&nc_entry->rtr_adv_timer, delay, &nc_entry->rtr_adv_msg, gnrc_ipv6_pid); } #endif } } /* otherwise ignore silently */ }
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 = timex_set(0, genrand_uint32_range(0, GNRC_NDP_MAX_RTR_ADV_DELAY)); 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 */ }
void ng_ndp_internal_send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t *dst, bool supply_tl2a) { ng_pktsnip_t *hdr, *pkt = NULL; uint8_t adv_flags = 0; DEBUG("ndp internal: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s, supply_tl2a: %d)\n", ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a); if (ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_ROUTER) { adv_flags |= NG_NDP_NBR_ADV_FLAGS_R; } if (ng_ipv6_addr_is_unspecified(dst)) { ng_ipv6_addr_set_all_nodes_multicast(dst, NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL); } else { adv_flags |= NG_NDP_NBR_ADV_FLAGS_S; } if (supply_tl2a) { uint8_t l2src[8]; uint16_t l2src_len; /* we previously checked if we are the target, so we can take our L2src */ l2src_len = _get_l2src(l2src, sizeof(l2src), iface); if (l2src_len > 0) { /* add target address link-layer address option */ pkt = ng_ndp_opt_tl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp internal: error allocating Target Link-layer address option.\n"); ng_pktbuf_release(pkt); return; } } } /* TODO: also check if the node provides proxy servies for tgt */ if ((pkt != NULL) && !ng_ipv6_netif_addr_is_non_unicast(tgt)) { /* TL2A is not supplied and tgt is not anycast */ adv_flags |= NG_NDP_NBR_ADV_FLAGS_O; } hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Neighbor advertisement.\n"); ng_pktbuf_release(pkt); return; } pkt = hdr; hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst, sizeof(ng_ipv6_addr_t)); if (hdr == NULL) { DEBUG("ndp internal: error allocating IPv6 header.\n"); ng_pktbuf_release(pkt); return; } ((ng_ipv6_hdr_t *)hdr->data)->hl = 255; pkt = hdr; /* add netif header for send interface specification */ hdr = ng_netif_hdr_build(NULL, 0, NULL, 0); if (hdr == NULL) { DEBUG("ndp internal: error allocating netif header.\n"); return; } ((ng_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); if (ng_ipv6_netif_addr_is_non_unicast(tgt)) { /* avoid collision for anycast addresses * (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */ timex_t delay = { 0, genrand_uint32_range(0, NG_NDP_MAX_AC_TGT_DELAY * SEC_IN_USEC) }; timex_normalize(&delay); ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, tgt); DEBUG("ndp internal: delay neighbor advertisement for %" PRIu32 " sec.", delay.seconds); /* nc_entry must be set so no need to check it */ _send_delayed(&nc_entry->nbr_adv_timer, delay, pkt); } else { ng_netapi_send(ng_ipv6_pid, pkt); } }