void uhcp_handle_prefix(uint8_t *prefix, uint8_t prefix_len, uint16_t lifetime, uint8_t *src, uhcp_iface_t iface) { (void)prefix_len; (void)lifetime; (void)src; eui64_t iid; if (!gnrc_wireless_interface) { LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): received prefix, but don't know any wireless interface\n"); return; } if ((kernel_pid_t)iface != gnrc_border_interface) { LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): received prefix from unexpected interface\n"); return; } if (gnrc_netapi_get(gnrc_wireless_interface, NETOPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) >= 0) { ipv6_addr_set_aiid((ipv6_addr_t*)prefix, iid.uint8); } else { LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): cannot get IID of wireless interface\n"); return; } if (ipv6_addr_equal(&_prefix, (ipv6_addr_t*)prefix)) { LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): got same prefix again\n"); return; } gnrc_ipv6_netif_add_addr(gnrc_wireless_interface, (ipv6_addr_t*)prefix, 64, GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST | GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO); gnrc_ipv6_netif_remove_addr(gnrc_wireless_interface, &_prefix); print_str("gnrc_uhcpc: uhcp_handle_prefix(): configured new prefix "); ipv6_addr_print((ipv6_addr_t*)prefix); puts("/64"); if (!ipv6_addr_is_unspecified(&_prefix)) { gnrc_ipv6_netif_remove_addr(gnrc_wireless_interface, &_prefix); print_str("gnrc_uhcpc: uhcp_handle_prefix(): removed old prefix "); ipv6_addr_print(&_prefix); puts("/64"); } memcpy(&_prefix, prefix, 16); }
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, ndp_opt_pi_t *pi_opt) { ipv6_addr_t *prefix; gnrc_ipv6_netif_addr_t *netif_addr; if ((pi_opt->len != NDP_OPT_MTU_LEN)) { DEBUG("ndp: invalid MTU option received\n"); return false; } if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) { /* else discard silently */ return true; } prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix); if (((prefix == NULL) || (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) && (pi_opt->valid_ltime.u32 != 0)) { prefix = gnrc_ipv6_netif_add_addr(iface, &pi_opt->prefix, pi_opt->prefix_len, pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); if (prefix == NULL) { DEBUG("ndp: could not add prefix to interface %d\n", iface); return false; } } netif_addr = gnrc_ipv6_netif_addr_get(prefix); if (pi_opt->valid_ltime.u32 == 0) { if (prefix != NULL) { gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr); } return true; } netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime); netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime); vtimer_remove(&netif_addr->valid_timeout); if (netif_addr->valid != UINT32_MAX) { vtimer_set_msg(&netif_addr->valid_timeout, timex_set(byteorder_ntohl(pi_opt->valid_ltime), 0), thread_getpid(), GNRC_NDP_MSG_ADDR_TIMEOUT, &netif_addr->addr); } /* TODO: preferred lifetime for address auto configuration */ /* on-link flag MUST stay set if it was */ netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A; netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); return true; }
void gnrc_ndp_router_set_router(gnrc_ipv6_netif_t *iface, bool enable) { if (enable && !(iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { gnrc_ipv6_netif_add_addr(iface->pid, &ipv6_addr_all_routers_link_local, 128, GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST); mutex_lock(&iface->mutex); iface->flags |= GNRC_IPV6_NETIF_FLAGS_ROUTER; iface->max_adv_int = GNRC_IPV6_NETIF_DEFAULT_MAX_ADV_INT; iface->min_adv_int = GNRC_IPV6_NETIF_DEFAULT_MIN_ADV_INT; iface->adv_ltime = GNRC_IPV6_NETIF_DEFAULT_ROUTER_LTIME; mutex_unlock(&iface->mutex); gnrc_ndp_router_set_rtr_adv(iface, enable); } else if (!enable && (iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { gnrc_ipv6_netif_remove_addr(iface->pid, (ipv6_addr_t *)&ipv6_addr_all_routers_link_local); gnrc_ndp_router_set_rtr_adv(iface, enable); } }
void gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_t *netif, bool enable) { if (enable && (gnrc_ipv6_netif_add_addr(netif->pid, &ipv6_addr_all_routers_link_local, 128, GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) != NULL)) { mutex_lock(&netif->mutex); netif->flags |= GNRC_IPV6_NETIF_FLAGS_RTR_ADV; netif->adv_ltime = GNRC_IPV6_NETIF_DEFAULT_ROUTER_LTIME; #ifdef MODULE_GNRC_NDP_ROUTER /* for border router these values have to be initialized, too */ netif->max_adv_int = GNRC_IPV6_NETIF_DEFAULT_MAX_ADV_INT; netif->min_adv_int = GNRC_IPV6_NETIF_DEFAULT_MIN_ADV_INT; #endif mutex_unlock(&netif->mutex); } else { netif->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV; gnrc_ipv6_netif_remove_addr(netif->pid, (ipv6_addr_t *)&ipv6_addr_all_routers_link_local); } }
void gnrc_sixlowpan_nd_router_abr_remove(gnrc_sixlowpan_nd_router_abr_t *abr) { for (int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) { if (bf_isset(abr->ctxs, i)) { gnrc_sixlowpan_ctx_remove(i); bf_unset(abr->ctxs, i); } } while (abr->prfs != NULL) { gnrc_sixlowpan_nd_router_prf_t *prefix = abr->prfs; LL_DELETE(abr->prfs, prefix); gnrc_ipv6_netif_remove_addr(prefix->iface->pid, &prefix->prefix->addr); prefix->next = NULL; prefix->iface = NULL; prefix->prefix = NULL; } ipv6_addr_set_unspecified(&abr->addr); abr->version = 0; }
static int _netif_del(kernel_pid_t dev, char *addr_str) { #ifdef MODULE_GNRC_IPV6_NETIF ipv6_addr_t addr; if (ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("error: unable to parse IPv6 address."); return 1; } gnrc_ipv6_netif_remove_addr(dev, &addr); printf("success: removed %s to interface %" PRIkernel_pid "\n", addr_str, dev); return 0; #else (void)dev; (void)addr_str; puts("error: unable to delete IPv6 address."); return 1; #endif }
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, ndp_opt_pi_t *pi_opt) { ipv6_addr_t *prefix; gnrc_ipv6_netif_addr_t *netif_addr; if ((pi_opt->len != NDP_OPT_PI_LEN)) { DEBUG("ndp: invalid PI option received\n"); return false; } if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) { /* else discard silently */ return true; } #ifdef MODULE_GNRC_SIXLOWPAN_ND if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (pi_opt->flags & NDP_OPT_PI_FLAGS_L)) { /* ignore: see https://tools.ietf.org/html/rfc6775#section-5.4 */ return true; } #endif prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix); if (((prefix == NULL) || (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) && (pi_opt->valid_ltime.u32 != 0)) { ipv6_addr_t pref_addr; if ((gnrc_netapi_get(iface, NETOPT_IPV6_IID, 0, &pref_addr.u64[1], sizeof(eui64_t)) < 0)) { DEBUG("ndp: could not get IID from interface %d\n", iface); return false; } ipv6_addr_init_prefix(&pref_addr, &pi_opt->prefix, pi_opt->prefix_len); prefix = gnrc_ipv6_netif_add_addr(iface, &pref_addr, pi_opt->prefix_len, pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); if (prefix == NULL) { DEBUG("ndp: could not add prefix to interface %d\n", iface); return false; } #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_get(iface), true); #endif } netif_addr = gnrc_ipv6_netif_addr_get(prefix); if (pi_opt->valid_ltime.u32 == 0) { if (prefix != NULL) { gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr); } return true; } netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime); netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime); if (netif_addr->valid != UINT32_MAX) { xtimer_set_msg(&netif_addr->valid_timeout, (byteorder_ntohl(pi_opt->valid_ltime) * SEC_IN_USEC), &netif_addr->valid_timeout_msg, thread_getpid()); } /* TODO: preferred lifetime for address auto configuration */ /* on-link flag MUST stay set if it was */ netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A; netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); return true; }
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); /* reschedule 1 minute before lifetime expires */ timex_t t = { (uint32_t)(byteorder_ntohs(ar_opt->ltime) - 1) * 60, 0 }; 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); 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 */ 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); } break; #endif default: break; } return status; }
/* internal functions */ static void *_event_loop(void *args) { msg_t msg, reply, msg_q[GNRC_IPV6_MSG_QUEUE_SIZE]; gnrc_netreg_entry_t me_reg; (void)args; msg_init_queue(msg_q, GNRC_IPV6_MSG_QUEUE_SIZE); me_reg.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL; me_reg.pid = thread_getpid(); /* register interest in all IPv6 packets */ gnrc_netreg_register(GNRC_NETTYPE_IPV6, &me_reg); /* preinitialize ACK */ reply.type = GNRC_NETAPI_MSG_TYPE_ACK; /* start event loop */ while (1) { DEBUG("ipv6: waiting for incoming message.\n"); msg_receive(&msg); switch (msg.type) { case GNRC_NETAPI_MSG_TYPE_RCV: DEBUG("ipv6: GNRC_NETAPI_MSG_TYPE_RCV received\n"); _receive((gnrc_pktsnip_t *)msg.content.ptr); break; case GNRC_NETAPI_MSG_TYPE_SND: DEBUG("ipv6: GNRC_NETAPI_MSG_TYPE_SND received\n"); _send((gnrc_pktsnip_t *)msg.content.ptr, true); break; case GNRC_NETAPI_MSG_TYPE_GET: case GNRC_NETAPI_MSG_TYPE_SET: DEBUG("ipv6: reply to unsupported get/set\n"); reply.content.value = -ENOTSUP; msg_reply(&msg, &reply); break; #ifdef MODULE_GNRC_NDP case GNRC_NDP_MSG_RTR_TIMEOUT: DEBUG("ipv6: Router timeout received\n"); ((gnrc_ipv6_nc_t *)msg.content.ptr)->flags &= ~GNRC_IPV6_NC_IS_ROUTER; break; case GNRC_NDP_MSG_ADDR_TIMEOUT: DEBUG("ipv6: Router advertisement timer event received\n"); gnrc_ipv6_netif_remove_addr(KERNEL_PID_UNDEF, (ipv6_addr_t *)msg.content.ptr); break; case GNRC_NDP_MSG_NBR_SOL_RETRANS: DEBUG("ipv6: Neigbor solicitation retransmission timer event received\n"); gnrc_ndp_retrans_nbr_sol((gnrc_ipv6_nc_t *)msg.content.ptr); break; case GNRC_NDP_MSG_NC_STATE_TIMEOUT: DEBUG("ipv6: Neigbor cache state timeout received\n"); gnrc_ndp_state_timeout((gnrc_ipv6_nc_t *)msg.content.ptr); break; #endif #ifdef MODULE_GNRC_NDP_ROUTER case GNRC_NDP_MSG_RTR_ADV_RETRANS: DEBUG("ipv6: Router advertisement retransmission event received\n"); gnrc_ndp_router_retrans_rtr_adv((gnrc_ipv6_netif_t *)msg.content.ptr); break; case GNRC_NDP_MSG_RTR_ADV_DELAY: DEBUG("ipv6: Delayed router advertisement event received\n"); gnrc_ndp_router_send_rtr_adv((gnrc_ipv6_nc_t *)msg.content.ptr); break; #endif #ifdef MODULE_GNRC_NDP_HOST case GNRC_NDP_MSG_RTR_SOL_RETRANS: DEBUG("ipv6: Router solicitation retransmission event received\n"); gnrc_ndp_host_retrans_rtr_sol((gnrc_ipv6_netif_t *)msg.content.ptr); break; #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND case GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL: DEBUG("ipv6: Multicast router solicitation event received\n"); gnrc_sixlowpan_nd_mc_rtr_sol((gnrc_ipv6_netif_t *)msg.content.ptr); break; case GNRC_SIXLOWPAN_ND_MSG_UC_RTR_SOL: DEBUG("ipv6: Unicast router solicitation event received\n"); gnrc_sixlowpan_nd_uc_rtr_sol((gnrc_ipv6_nc_t *)msg.content.ptr); break; # ifdef MODULE_GNRC_SIXLOWPAN_CTX case GNRC_SIXLOWPAN_ND_MSG_DELETE_CTX: DEBUG("ipv6: Delete 6LoWPAN context event received\n"); gnrc_sixlowpan_ctx_remove(((((gnrc_sixlowpan_ctx_t *)msg.content.ptr)->flags_id) & GNRC_SIXLOWPAN_CTX_FLAGS_CID_MASK)); break; # endif #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER case GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT: DEBUG("ipv6: border router timeout event received\n"); gnrc_sixlowpan_nd_router_abr_remove( (gnrc_sixlowpan_nd_router_abr_t *)msg.content.ptr); break; case GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT: DEBUG("ipv6: address registration timeout received\n"); gnrc_sixlowpan_nd_router_gc_nc((gnrc_ipv6_nc_t *)msg.content.ptr); break; case GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY: DEBUG("ipv6: Delayed router advertisement event received\n"); gnrc_ipv6_nc_t *nc_entry = (gnrc_ipv6_nc_t *)msg.content.ptr; gnrc_ndp_internal_send_rtr_adv(nc_entry->iface, NULL, &(nc_entry->ipv6_addr), false); break; #endif default: break; } } return NULL; }