void gnrc_ipv6_netif_init_by_dev(void) { kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = gnrc_netif_get(ifs); #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER bool abr_init = false; #endif for (size_t i = 0; i < ifnum; i++) { ipv6_addr_t addr; eui64_t iid; uint16_t tmp; gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]); if (ipv6_if == NULL) { continue; } mutex_lock(&ipv6_if->mutex); #ifdef MODULE_GNRC_SIXLOWPAN gnrc_nettype_t if_type = GNRC_NETTYPE_UNDEF; if ((gnrc_netapi_get(ifs[i], NETOPT_PROTO, 0, &if_type, sizeof(if_type)) != -ENOTSUP) && (if_type == GNRC_NETTYPE_SIXLOWPAN)) { uint16_t src_len = 8; uint16_t max_frag_size = UINT16_MAX; DEBUG("ipv6 netif: Set 6LoWPAN flag\n"); ipv6_ifs[i].flags |= GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN; /* the router flag must be set early here, because otherwise * _add_addr_to_entry() wouldn't set the solicited node address. * However, addresses have to be configured before calling * gnrc_ipv6_netif_set_router(). */ #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER DEBUG("ipv6 netif: Set router flag\n"); ipv6_ifs[i].flags |= GNRC_IPV6_NETIF_FLAGS_ROUTER; #endif /* use EUI-64 (8-byte address) for IID generation and for sending * packets */ gnrc_netapi_set(ifs[i], NETOPT_SRC_LEN, 0, &src_len, sizeof(src_len)); /* don't care for result */ if (gnrc_netapi_get(ifs[i], NETOPT_MAX_PACKET_SIZE, 0, &max_frag_size, sizeof(max_frag_size)) < 0) { /* if error we assume it works */ DEBUG("ipv6 netif: Can not get max packet size from interface %" PRIkernel_pid "\n", ifs[i]); } gnrc_sixlowpan_netif_add(ifs[i], max_frag_size); } #endif /* set link-local address */ if ((gnrc_netapi_get(ifs[i], NETOPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) < 0)) { mutex_unlock(&ipv6_if->mutex); continue; } ipv6_addr_set_aiid(&addr, iid.uint8); ipv6_addr_set_link_local_prefix(&addr); _add_addr_to_entry(ipv6_if, &addr, 64, 0); /* set link MTU */ if ((gnrc_netapi_get(ifs[i], NETOPT_MAX_PACKET_SIZE, 0, &tmp, sizeof(uint16_t)) >= 0)) { if (tmp >= IPV6_MIN_MTU) { ipv6_if->mtu = tmp; } /* otherwise leave at GNRC_IPV6_NETIF_DEFAULT_MTU as initialized in * gnrc_ipv6_netif_add() */ } if (gnrc_netapi_get(ifs[i], NETOPT_IS_WIRED, 0, &tmp, sizeof(int)) > 0) { ipv6_if->flags |= GNRC_IPV6_NETIF_FLAGS_IS_WIRED; } else { ipv6_if->flags &= ~GNRC_IPV6_NETIF_FLAGS_IS_WIRED; } mutex_unlock(&ipv6_if->mutex); #if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)) gnrc_ipv6_netif_set_router(ipv6_if, true); #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND if (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER /* first interface wins */ if (!abr_init) { gnrc_sixlowpan_nd_router_abr_create(&addr, 0); gnrc_ipv6_netif_set_rtr_adv(ipv6_if, true); abr_init = true; } #endif gnrc_sixlowpan_nd_init(ipv6_if); continue; /* skip gnrc_ndp_host_init() */ } #endif #ifdef MODULE_GNRC_NDP_HOST /* start periodic router solicitations */ gnrc_ndp_host_init(ipv6_if); #endif } }
static int _netif_flag(char *cmd, kernel_pid_t dev, char *flag) { netopt_enable_t set = NETOPT_ENABLE; if (flag[0] == '-') { set = NETOPT_DISABLE; flag++; } if (strcmp(flag, "promisc") == 0) { return _netif_set_flag(dev, NETOPT_PROMISCUOUSMODE, set); } else if (strcmp(flag, "preload") == 0) { return _netif_set_flag(dev, NETOPT_PRELOADING, set); } else if (strcmp(flag, "autoack") == 0) { return _netif_set_flag(dev, NETOPT_AUTOACK, set); } else if (strcmp(flag, "raw") == 0) { return _netif_set_flag(dev, NETOPT_RAWMODE, set); } else if (strcmp(flag, "csma") == 0) { return _netif_set_flag(dev, NETOPT_CSMA, set); } else if (strcmp(flag, "autocca") == 0) { return _netif_set_flag(dev, NETOPT_AUTOCCA, set); } else if (strcmp(flag, "iphc") == 0) { #if defined(MODULE_GNRC_SIXLOWPAN_NETIF) && defined(MODULE_GNRC_SIXLOWPAN_IPHC) gnrc_sixlowpan_netif_t *entry = gnrc_sixlowpan_netif_get(dev); if (entry == NULL) { puts("error: unable to (un)set IPHC"); return 1; } if (set) { entry->iphc_enabled = true; printf("success: enable IPHC on interface %" PRIkernel_pid "\n", dev); } else { entry->iphc_enabled = false; printf("success: disable IPHC on interface %" PRIkernel_pid "\n", dev); } return 0; #else puts("error: unable to (un)set IPHC."); return 1; #endif } else if (strcmp(flag, "rtr_adv") == 0) { #if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(dev); if (entry == NULL) { puts("error: unable to (un)set router advertisement flag."); return 1; } if (set) { gnrc_ipv6_netif_set_rtr_adv(entry, true); printf("success: enable router advertisements on interface %" PRIkernel_pid "\n", dev); } else { gnrc_ipv6_netif_set_rtr_adv(entry, false); printf("success: disable router advertisements on interface %" PRIkernel_pid "\n", dev); } return 0; #else puts("error: unable to (un)set router advertisement flag."); return 1; #endif } _flag_usage(cmd); return 1; }
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 xtimer_set_msg(&nc_entry->rtr_timeout, (ltime * SEC_IN_USEC), &nc_entry->rtr_timeout_msg, thread_getpid()); } /* 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 uint32_t valid_ltime = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime); if ((valid_ltime != 0) && (valid_ltime < next_rtr_sol)) { next_rtr_sol = 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; } uint16_t ltime = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime); if ((ltime != 0) && (ltime < (next_rtr_sol / 60))) { next_rtr_sol = 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 } 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 } #if ENABLE_DEBUG && defined(MODULE_GNRC_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); /* stop multicast router solicitation retransmission timer */ xtimer_remove(&if_entry->rtr_sol_timer); #ifdef MODULE_GNRC_SIXLOWPAN_ND if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { /* 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 = (next_rtr_sol > 4) ? (next_rtr_sol >> 2) : 1; /* 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. */ if_entry->rtr_sol_count = 0; gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol); gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr, &nc_entry->ipv6_addr); if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { gnrc_ipv6_netif_set_rtr_adv(if_entry, true); } }
static ipv6_addr_t *_add_addr_to_entry(gnrc_ipv6_netif_t *entry, const ipv6_addr_t *addr, uint8_t prefix_len, uint8_t flags) { gnrc_ipv6_netif_addr_t *tmp_addr = NULL; for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if (ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { return &(entry->addrs[i].addr); } if (ipv6_addr_is_unspecified(&(entry->addrs[i].addr)) && !tmp_addr) { tmp_addr = &(entry->addrs[i]); } } if (!tmp_addr) { DEBUG("ipv6 netif: couldn't add %s/%" PRIu8 " to interface %" PRIkernel_pid "\n: No space left.\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), prefix_len, entry->pid); return NULL; } memcpy(&(tmp_addr->addr), addr, sizeof(ipv6_addr_t)); DEBUG("ipv6 netif: Added %s/%" PRIu8 " to interface %" PRIkernel_pid "\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), prefix_len, entry->pid); tmp_addr->prefix_len = prefix_len; tmp_addr->flags = flags; #ifdef MODULE_GNRC_SIXLOWPAN_ND if (!ipv6_addr_is_multicast(&(tmp_addr->addr)) && (entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { ipv6_addr_t *router = gnrc_ndp_internal_default_router(); if (router != NULL) { mutex_unlock(&entry->mutex); /* function below relocks mutex */ gnrc_ndp_internal_send_nbr_sol(entry->pid, &tmp_addr->addr, router, router); mutex_lock(&entry->mutex); /* relock mutex */ } /* otherwise there is no default router to register to */ } #endif if (ipv6_addr_is_multicast(addr)) { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { if (!ipv6_addr_is_link_local(addr)) { #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER tmp_addr->valid = UINT32_MAX; tmp_addr->preferred = UINT32_MAX; gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get(); mutex_unlock(&entry->mutex); gnrc_ipv6_netif_set_rtr_adv(entry, true); mutex_lock(&entry->mutex); if (gnrc_sixlowpan_nd_router_abr_add_prf(abr, entry, tmp_addr) < 0) { DEBUG("ipv6_netif: error adding prefix to 6LoWPAN-ND management\n"); } #endif #if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) if ((entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) && (entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) { mutex_unlock(&entry->mutex); /* function below relocks mutex */ #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER if (entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { gnrc_ndp_internal_send_rtr_adv(entry->pid, NULL, NULL, false); } #endif #ifdef MODULE_GNRC_NDP_ROUTER /* New prefixes MAY allow the router to retransmit up to * GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF unsolicited RA * (see https://tools.ietf.org/html/rfc4861#section-6.2.4) */ if (!(entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { entry->rtr_adv_count = GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF; gnrc_ndp_router_retrans_rtr_adv(entry); } #endif mutex_lock(&entry->mutex); /* relock mutex */ } #endif } else { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK; } #if defined(MODULE_GNRC_NDP_NODE) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER) /* add solicited-nodes multicast address for new address if interface is not a * 6LoWPAN host interface (see: https://tools.ietf.org/html/rfc6775#section-5.2) */ if (!(entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) || (entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { ipv6_addr_t sol_node; ipv6_addr_set_solicited_nodes(&sol_node, addr); _add_addr_to_entry(entry, &sol_node, IPV6_ADDR_BIT_LEN, 0); } #endif /* TODO: send NS with ARO on 6LoWPAN interfaces, but not so many and only for the new * source address. */ } tmp_addr->valid_timeout_msg.type = GNRC_NDP_MSG_ADDR_TIMEOUT; tmp_addr->valid_timeout_msg.content.ptr = &tmp_addr->addr; return &(tmp_addr->addr); }