static void _add_prefix(kernel_pid_t iface, gnrc_sixlowpan_nd_router_abr_t *abr, ndp_opt_pi_t *pi_opt) { gnrc_sixlowpan_nd_router_prf_t *prf_ent; gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); ipv6_addr_t *prefix; if ((pi_opt->len != NDP_OPT_PI_LEN) || ipv6_addr_is_link_local(&pi_opt->prefix) || (pi_opt->flags & NDP_OPT_PI_FLAGS_A) || (pi_opt->flags & NDP_OPT_PI_FLAGS_L) || (pi_opt->valid_ltime.u32 == 0)) { return; } prefix = gnrc_ipv6_netif_match_prefix(iface, &pi_opt->prefix); prf_ent = _get_free_prefix(&pi_opt->prefix, pi_opt->prefix_len); if (prf_ent != NULL) { prf_ent->iface = ipv6_iface; prf_ent->prefix = container_of(prefix, gnrc_ipv6_netif_addr_t, addr); } LL_PREPEND(abr->prfs, prf_ent); }
bool _resolve_addr_from_ipv6(const ipv6_addr_t *dst, gnrc_netif_t *netif, gnrc_ipv6_nib_nc_t *nce) { bool res = (netif != NULL) && gnrc_netif_is_6ln(netif) && ipv6_addr_is_link_local(dst); if (res) { uint8_t l2addr_len; if ((l2addr_len = _reverse_iid(dst, netif, nce->l2addr)) > 0) { DEBUG("nib: resolve address %s%%%u by reverse translating to ", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), (unsigned)netif->pid); nce->l2addr_len = l2addr_len; DEBUG("%s\n", gnrc_netif_addr_to_str(nce->l2addr, nce->l2addr_len, addr_str)); memcpy(&nce->ipv6, dst, sizeof(nce->ipv6)); nce->info = 0; nce->info |= (netif->pid << GNRC_IPV6_NIB_NC_INFO_IFACE_POS) & GNRC_IPV6_NIB_NC_INFO_IFACE_MASK; nce->info |= GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE; nce->info |= GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED; } else { res = false; } } return res; }
static void _remove_addr_from_entry(gnrc_ipv6_netif_t *entry, ipv6_addr_t *addr) { mutex_lock(&entry->mutex); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if (ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { DEBUG("ipv6 netif: Remove %s to interface %" PRIkernel_pid "\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), entry->pid); ipv6_addr_set_unspecified(&(entry->addrs[i].addr)); entry->addrs[i].flags = 0; #ifdef MODULE_GNRC_NDP_ROUTER /* Removal of 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_ROUTER) && (entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) && (!ipv6_addr_is_multicast(addr) && !ipv6_addr_is_link_local(addr))) { entry->rtr_adv_count = GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF; mutex_unlock(&entry->mutex); /* function below relocks the mutex */ gnrc_ndp_router_retrans_rtr_adv(entry); return; } #endif mutex_unlock(&entry->mutex); return; } } mutex_unlock(&entry->mutex); }
static void _print_addr(ipv6_addr_t *addr, uint8_t flags) { char addr_str[IPV6_ADDR_MAX_STR_LEN]; printf(" inet6 addr: "); ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)); printf("%s scope: ", addr_str); if ((ipv6_addr_is_link_local(addr))) { printf("local"); } else { printf("global"); } if (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST) { printf(" [anycast]"); } if (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE) { printf(" TNT[%u]", flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE); } else { switch (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK) { case GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_DEPRECATED: printf(" DPR"); break; case GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID: printf(" VAL"); break; default: printf(" UNK"); break; } } printf("\n"); }
static void *_ipv6_fwd_eventloop(void *arg) { (void)arg; msg_t msg, msg_q[8]; gnrc_netreg_entry_t me_reg; msg_init_queue(msg_q, 8); me_reg.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL; me_reg.pid = thread_getpid(); gnrc_netreg_register(GNRC_NETTYPE_SIXLOWPAN, &me_reg); while(1) { msg_receive(&msg); gnrc_pktsnip_t *pkt = msg.content.ptr; if(msg.type == GNRC_NETAPI_MSG_TYPE_SND) { gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); ipv6 = ipv6->data; ipv6_hdr_t *ipv6_hdr =(ipv6_hdr_t *)ipv6; /* get the first IPv6 interface and prints its address */ kernel_pid_t ifs[GNRC_NETIF_NUMOF]; gnrc_netif_get(ifs); gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(ifs[0]); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if ( (!ipv6_addr_is_link_local(&entry->addrs[i].addr)) && (!ipv6_addr_is_link_local(&ipv6_hdr->src)) && (!ipv6_addr_is_link_local(&ipv6_hdr->dst)) && !(entry->addrs[i].flags & GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) && (!ipv6_addr_is_unspecified(&entry->addrs[i].addr)) ) { if(!ipv6_addr_equal(&entry->addrs[i].addr, &(ipv6_hdr->src))){ char addr_str[IPV6_ADDR_MAX_STR_LEN]; printf("IPv6 ROUTER: forward from src = %s ", ipv6_addr_to_str(addr_str, &(ipv6_hdr->src), sizeof(addr_str)) ); printf("to dst = %s\n",ipv6_addr_to_str(addr_str, &(ipv6_hdr->dst), sizeof(addr_str))); } } } } gnrc_pktbuf_release(pkt); } /* never reached */ return NULL; }
void ipv6_net_if_get_best_src_addr(ipv6_addr_t *src, const ipv6_addr_t *dest) { /* try to find best match if dest is not mcast or link local */ int if_id = 0; // TODO: get this somehow uint8_t tmp = 0; uint8_t bmatch = 0; ipv6_net_if_addr_t *addr = NULL; ipv6_net_if_addr_t *tmp_addr = NULL; if (!(ipv6_addr_is_link_local(dest)) && !(ipv6_addr_is_multicast(dest))) { while ((addr = (ipv6_net_if_addr_t *)net_if_iter_addresses(if_id, (net_if_addr_t **)&addr))) { if (addr->ndp_state == NDP_ADDR_STATE_PREFERRED) { if (!ipv6_addr_is_link_local(addr->addr_data) && !ipv6_addr_is_multicast(addr->addr_data) && !ipv6_addr_is_unique_local_unicast(addr->addr_data)) { tmp = ipv6_get_addr_match(dest, addr->addr_data); if (tmp >= bmatch) { bmatch = tmp; tmp_addr = addr; } } } } } else { while ((addr = (ipv6_net_if_addr_t *)net_if_iter_addresses(if_id, (net_if_addr_t **)&addr))) { if (addr->ndp_state == NDP_ADDR_STATE_PREFERRED && ipv6_addr_is_link_local(addr->addr_data) && !ipv6_addr_is_multicast(addr->addr_data)) { tmp_addr = addr; } } } if (tmp_addr == NULL) { memset(src, 0, 16); } else { memcpy(src, tmp_addr->addr_data, 16); } }
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.", 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; if (ipv6_addr_is_multicast(addr)) { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { ipv6_addr_t sol_node; if (!ipv6_addr_is_link_local(addr)) { /* add also corresponding link-local address */ ipv6_addr_t ll_addr; ll_addr.u64[1] = addr->u64[1]; ipv6_addr_set_link_local_prefix(&ll_addr); _add_addr_to_entry(entry, &ll_addr, 64, flags | GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK); } else { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK; } ipv6_addr_set_solicited_nodes(&sol_node, addr); _add_addr_to_entry(entry, &sol_node, IPV6_ADDR_BIT_LEN, 0); } return &(tmp_addr->addr); }
static uint8_t _get_scope(const ipv6_addr_t *addr) { if (ipv6_addr_is_link_local(addr)) { return IPV6_ADDR_MCAST_SCP_LINK_LOCAL; } else if (ipv6_addr_is_site_local(addr)) { return IPV6_ADDR_MCAST_SCP_SITE_LOCAL; } else { return IPV6_ADDR_MCAST_SCP_GLOBAL; } }
void _auto_configure_addr(gnrc_netif_t *netif, const ipv6_addr_t *pfx, uint8_t pfx_len) { ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; int idx; uint8_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; if (!(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR)) { DEBUG("nib: interface %i has no link-layer addresses\n", netif->pid); return; } DEBUG("nib: add address based on %s/%u automatically to interface %u\n", ipv6_addr_to_str(addr_str, pfx, sizeof(addr_str)), pfx_len, netif->pid); #if GNRC_IPV6_NIB_CONF_6LN bool new_address = false; #endif /* GNRC_IPV6_NIB_CONF_6LN */ gnrc_netif_ipv6_get_iid(netif, (eui64_t *)&addr.u64[1]); ipv6_addr_init_prefix(&addr, pfx, pfx_len); if ((idx = gnrc_netif_ipv6_addr_idx(netif, &addr)) < 0) { if ((idx = gnrc_netif_ipv6_addr_add_internal(netif, &addr, pfx_len, flags)) < 0) { DEBUG("nib: Can't add link-local address on interface %u\n", netif->pid); return; } #if GNRC_IPV6_NIB_CONF_6LN new_address = true; #endif /* GNRC_IPV6_NIB_CONF_6LN */ } #if GNRC_IPV6_NIB_CONF_6LN /* mark link-local addresses as valid on 6LN */ if (gnrc_netif_is_6ln(netif) && ipv6_addr_is_link_local(pfx)) { /* don't do this beforehand or risk a deadlock: * - gnrc_netif_ipv6_addr_add_internal() adds VALID (i.e. manually configured * addresses to the prefix list locking the NIB's mutex which is already * locked here) */ netif->ipv6.addrs_flags[idx] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK; netif->ipv6.addrs_flags[idx] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID; } #endif /* GNRC_IPV6_NIB_CONF_6LN */ #if GNRC_IPV6_NIB_CONF_6LN if (new_address && gnrc_netif_is_6ln(netif) && !gnrc_netif_is_6lbr(netif)) { _handle_rereg_address(&netif->ipv6.addrs[idx]); } #else /* GNRC_IPV6_NIB_CONF_6LN */ (void)idx; #endif /* GNRC_IPV6_NIB_CONF_6LN */ }
/** * @brief selects potential source address candidates * @see <a href="http://tools.ietf.org/html/rfc6724#section-4"> * RFC6724, section 4 * </a> * @param[in] iface the interface used for sending * @param[in] dst the destination address * @param[out] candidate_set a bitfield representing all addresses * configured to @p iface, potential candidates * will be marked as 1 * * @return false if no candidates were found * @return true otherwise * * @pre the interface entry and its set of addresses must not be changed during * runtime of this function */ static int _create_candidate_set(gnrc_ipv6_netif_t *iface, const ipv6_addr_t *dst, uint8_t *candidate_set, bool link_local_only) { int res = -1; DEBUG("gathering candidates\n"); /* currently this implementation supports only addresses as source address * candidates assigned to this interface. Thus we assume all addresses to be * on interface @p iface */ (void) dst; for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { gnrc_ipv6_netif_addr_t *iter = &(iface->addrs[i]); DEBUG("Checking address: %s\n", ipv6_addr_to_str(addr_str, &(iter->addr), sizeof(addr_str))); /* "In any case, multicast addresses and the unspecified address MUST NOT * be included in a candidate set." */ if (ipv6_addr_is_multicast(&(iter->addr)) || ipv6_addr_is_unspecified(&(iter->addr))) { continue; } /* Check if we only want link local addresses */ if (link_local_only && !ipv6_addr_is_link_local(&(iter->addr))) { continue; } /* "For all multicast and link-local destination addresses, the set of * candidate source addresses MUST only include addresses assigned to * interfaces belonging to the same link as the outgoing interface." * * "For site-local unicast destination addresses, the set of candidate * source addresses MUST only include addresses assigned to interfaces * belonging to the same site as the outgoing interface." * -> we should also be fine, since we're only iterating addresses of * the sending interface */ /* put all other addresses into the candidate set */ DEBUG("add to candidate set\n"); bf_set(candidate_set, i); res = i; } return res; }
/** * @brief Determines the scope of the given address. * * @param[in] addr The IPv6 address to check. * @param[in] maybe_multicast False if @p addr is definitely no multicast * address, true otherwise. * * @return The scope of the address. * * @pre address is not loopback or unspecified. * see http://tools.ietf.org/html/rfc6724#section-4 */ static uint8_t _get_scope(const ipv6_addr_t *addr, const bool maybe_multicast) { if (maybe_multicast && ipv6_addr_is_multicast(addr)) { return (addr->u8[1] & 0x0f); } else if (ipv6_addr_is_link_local(addr)) { return IPV6_ADDR_MCAST_SCP_LINK_LOCAL; } else if (ipv6_addr_is_site_local(addr)) { return IPV6_ADDR_MCAST_SCP_SITE_LOCAL; } else { return IPV6_ADDR_MCAST_SCP_GLOBAL; } }
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; }
/** * @brief selects potential source address candidates * @see <a href="http://tools.ietf.org/html/rfc6724#section-4"> * RFC6724, section 4 * </a> * @param[in] netif the interface used for sending * @param[in] dst the destination address * @param[in] ll_only only consider link-local addresses * @param[out] candidate_set a bitfield representing all addresses * configured to @p netif, potential candidates * will be marked as 1 * * @return -1 if no candidates were found * @return the index of the first candidate otherwise * * @pre the interface entry and its set of addresses must not be changed during * runtime of this function */ static int _create_candidate_set(const gnrc_netif_t *netif, const ipv6_addr_t *dst, bool ll_only, uint8_t *candidate_set) { int res = -1; DEBUG("gathering candidates\n"); /* currently this implementation supports only addresses as source address * candidates assigned to this interface. Thus we assume all addresses to be * on interface @p netif */ (void) dst; for (int i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { const ipv6_addr_t *tmp = &(netif->ipv6.addrs[i]); DEBUG("Checking address: %s\n", ipv6_addr_to_str(addr_str, tmp, sizeof(addr_str))); /* "In any case, multicast addresses and the unspecified address MUST NOT * be included in a candidate set." */ if ((netif->ipv6.addrs_flags[i] == 0) || (gnrc_netif_ipv6_addr_get_state(netif, i) == GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE)) { continue; } /* Check if we only want link local addresses */ if (ll_only && !ipv6_addr_is_link_local(tmp)) { continue; } /* "For all multicast and link-local destination addresses, the set of * candidate source addresses MUST only include addresses assigned to * interfaces belonging to the same link as the outgoing interface." * * "For site-local unicast destination addresses, the set of candidate * source addresses MUST only include addresses assigned to interfaces * belonging to the same site as the outgoing interface." * -> we should also be fine, since we're only iterating addresses of * the sending interface */ /* put all other addresses into the candidate set */ DEBUG("add to candidate set\n"); bf_set(candidate_set, i); if (res < 0) { res = i; } } return res; }
/* functions for receiving */ static inline bool _pkt_not_for_me(kernel_pid_t *iface, ipv6_hdr_t *hdr) { if (ipv6_addr_is_loopback(&hdr->dst)) { return false; } else if ((!ipv6_addr_is_link_local(&hdr->dst)) || (*iface == KERNEL_PID_UNDEF)) { kernel_pid_t if_pid = gnrc_ipv6_netif_find_by_addr(NULL, &hdr->dst); if (*iface == KERNEL_PID_UNDEF) { *iface = if_pid; /* Use original interface for reply if * existent */ } return (if_pid == KERNEL_PID_UNDEF); } else { return (gnrc_ipv6_netif_find_addr(*iface, &hdr->dst) == NULL); } }
static bool _pio_from_iface_addr(gnrc_pktsnip_t **res, gnrc_ipv6_netif_addr_t *addr, gnrc_pktsnip_t *next) { if (((addr->prefix_len - 1U) > 127U) && /* 0 < prefix_len < 128 */ !ipv6_addr_is_unspecified(&addr->addr) && !ipv6_addr_is_link_local(&addr->addr) && !gnrc_ipv6_netif_addr_is_non_unicast(&addr->addr)) { DEBUG(" - PIO for %s/%" PRIu8 "\n", ipv6_addr_to_str(addr_str, &addr->addr, sizeof(addr_str)), addr->prefix_len); *res = gnrc_ndp_opt_pi_build(addr->prefix_len, (addr->flags & (GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO | GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)), addr->valid, addr->preferred, &addr->addr, next); return true; } return false; }
void _remove_tentative_addr(gnrc_netif_t *netif, const ipv6_addr_t *addr) { DEBUG("nib: other node has TENTATIVE address %s assigned " "=> removing that address\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); gnrc_netif_ipv6_addr_remove_internal(netif, addr); if (!ipv6_addr_is_link_local(addr) || !_try_addr_reconfiguration(netif)) { /* Cannot use target address as personal address and can * not change hardware address to retry SLAAC => use purely * DHCPv6 instead */ /* TODO: implement IA_NA for DHCPv6 */ /* then => tgt_netif->aac_mode = GNRC_NETIF_AAC_DHCP; */ DEBUG("nib: would set interface %i to DHCPv6, " "but is not implemented yet", netif->pid); } }
static unsigned _match(const gnrc_netif_t *netif, const ipv6_addr_t *addr, const uint8_t *filter, int *idx) { unsigned best_match = 0; assert(idx != NULL); *idx = -1; for (int i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { unsigned match; if ((netif->ipv6.addrs_flags[i] == 0) || ((filter != NULL) && _addr_anycast(netif, i)) || /* discard const intentionally */ ((filter != NULL) && !(bf_isset((uint8_t *)filter, i)))) { continue; } match = ipv6_addr_match_prefix(&(netif->ipv6.addrs[i]), addr); if (((match > 64U) || !ipv6_addr_is_link_local(&(netif->ipv6.addrs[i]))) && (match >= best_match)) { if (idx != NULL) { *idx = i; } best_match = match; } } if (*idx >= 0) { DEBUG("gnrc_netif: Found %s on interface %" PRIkernel_pid " matching ", ipv6_addr_to_str(addr_str, &netif->ipv6.addrs[*idx], sizeof(addr_str)), netif->pid); DEBUG("%s by %u bits (used as source address = %s)\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), best_match, (filter != NULL) ? "true" : "false"); } else { DEBUG("gnrc_netif: Did not found any address on interface %" PRIkernel_pid " matching %s (used as source address = %s)\n", netif->pid, ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), (filter != NULL) ? "true" : "false"); } return best_match; }
int sixlowpan_lowpan_border_init(int if_id) { ipv6_net_if_addr_t *addr = NULL; uint8_t abr_addr_initialized = 0; serial_reader_pid = thread_create( serial_reader_stack, READER_STACK_SIZE, PRIORITY_MAIN - 1, CREATE_STACKTEST, serial_reader_f, "serial_reader"); ip_process_pid = thread_create(ip_process_buf, IP_PROCESS_STACKSIZE, PRIORITY_MAIN - 1, CREATE_STACKTEST, border_process_lowpan, "border_process_lowpan"); if (ip_process_pid < 0) { return 0; } if (!sixlowpan_lowpan_init_interface(if_id)) { return 0; } while (net_if_iter_addresses(if_id, (net_if_addr_t **) &addr)) { if (!ipv6_addr_is_multicast(addr->addr_data) && !ipv6_addr_is_link_local(addr->addr_data) && !ipv6_addr_is_loopback(addr->addr_data) && !ipv6_addr_is_unique_local_unicast(addr->addr_data)) { abr_addr_initialized = 1; abr_addr = addr->addr_data; break; } } if (!abr_addr_initialized) { DEBUG("sixlowpan_lowpan_border_init(): A prefix must be initialized to" "interface %d first", if_id); return 0; } ipv6_init_as_router(); return 1; }
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 void _netif_list(kernel_pid_t dev) { uint8_t hwaddr[MAX_ADDR_LEN]; uint16_t u16; int16_t i16; int res; netopt_state_t state; netopt_enable_t enable; bool linebreak = false; #ifdef MODULE_GNRC_IPV6_NETIF gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(dev); char ipv6_addr[IPV6_ADDR_MAX_STR_LEN]; #endif printf("Iface %2d ", dev); res = gnrc_netapi_get(dev, NETOPT_ADDRESS, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf(" HWaddr: "); printf("%s", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); printf(" "); } res = gnrc_netapi_get(dev, NETOPT_CHANNEL, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" Channel: %" PRIu16 " ", u16); } res = gnrc_netapi_get(dev, NETOPT_NID, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" NID: 0x%" PRIx16 " ", u16); } res = gnrc_netapi_get(dev, NETOPT_TX_POWER, 0, &i16, sizeof(i16)); if (res >= 0) { printf(" TX-Power: %" PRIi16 "dBm ", i16); } res = gnrc_netapi_get(dev, NETOPT_STATE, 0, &state, sizeof(state)); if (res >= 0) { printf(" State: "); _print_netopt_state(state); } printf("\n "); res = gnrc_netapi_get(dev, NETOPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf("Long HWaddr: "); printf("%s", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); printf("\n "); } res = gnrc_netapi_get(dev, NETOPT_PROMISCUOUSMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("PROMISC "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_AUTOACK, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("AUTOACK "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_PRELOADING, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("PRELOAD "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_RAWMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("RAWMODE "); linebreak = true; } #ifdef MODULE_GNRC_IPV6_NETIF if ((entry != NULL) && (entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { printf("6LO "); linebreak = true; } #endif #if defined(MODULE_GNRC_SIXLOWPAN_NETIF) && defined(MODULE_GNRC_SIXLOWPAN_IPHC) gnrc_sixlowpan_netif_t *sixlo_entry = gnrc_sixlowpan_netif_get(dev); if ((sixlo_entry != NULL) && (sixlo_entry->iphc_enabled)) { printf("IPHC "); linebreak = true; } #endif if (linebreak) { printf("\n "); } res = gnrc_netapi_get(dev, NETOPT_SRC_LEN, 0, &u16, sizeof(u16)); if (res >= 0) { printf("Source address length: %" PRIu16 "\n ", u16); } #ifdef MODULE_GNRC_IPV6_NETIF for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if (!ipv6_addr_is_unspecified(&entry->addrs[i].addr)) { printf("inet6 addr: "); if (ipv6_addr_to_str(ipv6_addr, &entry->addrs[i].addr, IPV6_ADDR_MAX_STR_LEN)) { printf("%s/%" PRIu8 " scope: ", ipv6_addr, entry->addrs[i].prefix_len); if ((ipv6_addr_is_link_local(&entry->addrs[i].addr))) { printf("local"); } else { printf("global"); } if (entry->addrs[i].flags & GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) { if (ipv6_addr_is_multicast(&entry->addrs[i].addr)) { printf(" [multicast]"); } else { printf(" [anycast]"); } } } else { printf("error in conversion"); } printf("\n "); } } #endif puts(""); }
static void _receive(gnrc_pktsnip_t *pkt) { kernel_pid_t iface = KERNEL_PID_UNDEF; gnrc_pktsnip_t *ipv6, *netif, *first_ext; ipv6_hdr_t *hdr; assert(pkt != NULL); netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF); if (netif != NULL) { iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid; #ifdef MODULE_NETSTATS_IPV6 assert(iface); netstats_t *stats = gnrc_ipv6_netif_get_stats(iface); stats->rx_count++; stats->rx_bytes += (gnrc_pkt_len(pkt) - netif->size); #endif } first_ext = pkt; for (ipv6 = pkt; ipv6 != NULL; ipv6 = ipv6->next) { /* find IPv6 header if already marked */ if ((ipv6->type == GNRC_NETTYPE_IPV6) && (ipv6->size == sizeof(ipv6_hdr_t)) && (ipv6_hdr_is(ipv6->data))) { break; } first_ext = ipv6; } if (ipv6 == NULL) { if (!ipv6_hdr_is(pkt->data)) { DEBUG("ipv6: Received packet was not IPv6, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } #ifdef MODULE_GNRC_IPV6_WHITELIST if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(pkt->data))->src)) { DEBUG("ipv6: Source address not whitelisted, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } #endif #ifdef MODULE_GNRC_IPV6_BLACKLIST if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(pkt->data))->src)) { DEBUG("ipv6: Source address blacklisted, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } #endif /* seize ipv6 as a temporary variable */ ipv6 = gnrc_pktbuf_start_write(pkt); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to packet, drop it\n"); gnrc_pktbuf_release(pkt); return; } pkt = ipv6; /* reset pkt from temporary variable */ ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6); first_ext = pkt; pkt->type = GNRC_NETTYPE_UNDEF; /* snip is no longer IPv6 */ if (ipv6 == NULL) { DEBUG("ipv6: error marking IPv6 header, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } } #ifdef MODULE_GNRC_IPV6_WHITELIST else if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(ipv6->data))->src)) { /* if ipv6 header already marked*/ DEBUG("ipv6: Source address not whitelisted, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } #endif #ifdef MODULE_GNRC_IPV6_BLACKLIST else if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(ipv6->data))->src)) { /* if ipv6 header already marked*/ DEBUG("ipv6: Source address blacklisted, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } #endif /* extract header */ hdr = (ipv6_hdr_t *)ipv6->data; /* if available, remove any padding that was added by lower layers * to fulfill their minimum size requirements (e.g. ethernet) */ if (byteorder_ntohs(hdr->len) < pkt->size) { gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len)); } else if (byteorder_ntohs(hdr->len) > (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))) { DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n", (int) byteorder_ntohs(hdr->len), (int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))); gnrc_pktbuf_release(pkt); return; } DEBUG("ipv6: Received (src = %s, ", ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str))); DEBUG("dst = %s, next header = %u, length = %" PRIu16 ")\n", ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)), hdr->nh, byteorder_ntohs(hdr->len)); if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */ DEBUG("ipv6: packet destination not this host\n"); #ifdef MODULE_GNRC_IPV6_ROUTER /* only routers redirect */ /* redirect to next hop */ DEBUG("ipv6: decrement hop limit to %u\n", (uint8_t) (hdr->hl - 1)); /* RFC 4291, section 2.5.6 states: "Routers must not forward any * packets with Link-Local source or destination addresses to other * links." */ if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) { DEBUG("ipv6: do not forward packets with link-local source or" " destination address\n"); gnrc_pktbuf_release(pkt); return; } /* TODO: check if receiving interface is router */ else if (--(hdr->hl) > 0) { /* drop packets that *reach* Hop Limit 0 */ gnrc_pktsnip_t *reversed_pkt = NULL, *ptr = pkt; DEBUG("ipv6: forward packet to next hop\n"); /* pkt might not be writable yet, if header was given above */ ipv6 = gnrc_pktbuf_start_write(ipv6); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to packet: dropping it\n"); gnrc_pktbuf_release(pkt); return; } /* remove L2 headers around IPV6 */ netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF); if (netif != NULL) { gnrc_pktbuf_remove_snip(pkt, netif); } /* reverse packet snip list order */ while (ptr != NULL) { gnrc_pktsnip_t *next; ptr = gnrc_pktbuf_start_write(ptr); /* duplicate if not already done */ if (ptr == NULL) { DEBUG("ipv6: unable to get write access to packet: dropping it\n"); gnrc_pktbuf_release(reversed_pkt); gnrc_pktbuf_release(pkt); return; } next = ptr->next; ptr->next = reversed_pkt; reversed_pkt = ptr; ptr = next; } _send(reversed_pkt, false); return; } else { DEBUG("ipv6: hop limit reached 0: drop packet\n"); gnrc_pktbuf_release(pkt); return; } #else /* MODULE_GNRC_IPV6_ROUTER */ DEBUG("ipv6: dropping packet\n"); /* non rounting hosts just drop the packet */ gnrc_pktbuf_release(pkt); return; #endif /* MODULE_GNRC_IPV6_ROUTER */ } /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */ gnrc_ipv6_demux(iface, first_ext, pkt, hdr->nh); }
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.", 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; if (ipv6_addr_is_multicast(addr)) { tmp_addr->flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { if (!ipv6_addr_is_link_local(addr)) { /* add also corresponding link-local address */ ipv6_addr_t ll_addr; ll_addr.u64[1] = addr->u64[1]; ipv6_addr_set_link_local_prefix(&ll_addr); _add_addr_to_entry(entry, &ll_addr, 64, flags | GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK); #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_ROUTER) && (entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) { entry->rtr_adv_count = GNRC_NDP_MAX_INIT_RTR_ADV_NUMOF; mutex_unlock(&entry->mutex); /* function below relocks mutex */ gnrc_ndp_router_retrans_rtr_adv(entry); 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. */ } return &(tmp_addr->addr); }
void rpl_recv_DIO(void) { ipv6_buf = get_rpl_ipv6_buf(); rpl_dio_buf = get_rpl_dio_buf(); DEBUGF("instance %04X ", rpl_dio_buf->rpl_instanceid); DEBUGF("rank %04X\n", byteorder_ntohs(rpl_dio_buf->rank)); int len = DIO_BASE_LEN; rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid); rpl_instance_t *my_inst = rpl_get_my_instance(); if (dio_inst == NULL) { if (my_inst != NULL) { /* already part of a DODAG -> impossible to join other instance */ DEBUGF("Not joining another DODAG!\n"); return; } dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid); if (dio_inst == NULL) { DEBUGF("Failed to create a new RPL instance!\n"); return; } } else if (my_inst == NULL) { DEBUGF("Not joined an instance yet\n"); } else if (my_inst->id != dio_inst->id) { /* TODO: Add support support for several instances. */ /* At the moment, nodes can only join one instance, this is * the instance they join first. * Instances cannot be switched later on. */ DEBUGF("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id); return; } rpl_dodag_t dio_dodag; memset(&dio_dodag, 0, sizeof(dio_dodag)); memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id)); dio_dodag.dtsn = rpl_dio_buf->dtsn; dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK); dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT; dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK); dio_dodag.version = rpl_dio_buf->version_number; dio_dodag.instance = dio_inst; uint8_t has_dodag_conf_opt = 0; /* Parse until all options are consumed. * ipv6_buf->length contains the packet length minus ipv6 and * icmpv6 header, so only ICMPV6_HDR_LEN remains to be * subtracted. */ while (len < (NTOHS(ipv6_buf->length) - ICMPV6_HDR_LEN)) { DEBUGF("parsing DIO options\n"); rpl_opt_buf = get_rpl_opt_buf(len); switch (rpl_opt_buf->type) { case (RPL_OPT_PAD1): { len += 1; break; } case (RPL_OPT_PADN): { len += rpl_opt_buf->length; break; } case (RPL_OPT_DAG_METRIC_CONTAINER): { len += rpl_opt_buf->length; break; } case (RPL_OPT_ROUTE_INFO): { len += rpl_opt_buf->length; break; } case (RPL_OPT_DODAG_CONF): { has_dodag_conf_opt = 1; if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) { DEBUGF("DODAG configuration is malformed.\n"); /* error malformed */ return; } rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len); dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl; dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin; dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun; dio_dodag.maxrankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MaxRankIncrease); dio_dodag.minhoprankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MinHopRankIncrease); dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime; dio_dodag.lifetime_unit = byteorder_ntohs(rpl_opt_dodag_conf_buf->lifetime_unit); dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp)); if (dio_dodag.of == NULL) { DEBUGF("[Error] OCP from DIO is not supported! ocp: %x\n", byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp)); return; } len += RPL_OPT_DODAG_CONF_LEN_WITH_OPT_LEN; break; } case (RPL_OPT_PREFIX_INFO): { if (rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) { /* error malformed */ return; } rpl_opt_prefix_information_buf = get_rpl_opt_prefix_information_buf(len); /* autonomous address-configuration flag */ if (rpl_opt_prefix_information_buf->flags & (1 << 6)) { ipv6_addr_t tmp; tmp = rpl_opt_prefix_information_buf->prefix; if (!ipv6_addr_is_link_local(&tmp)) { if (byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime) <= byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime)) { ipv6_addr_set_by_eui64(&tmp, rpl_if_id, &tmp); ipv6_net_if_add_addr(rpl_if_id, &tmp, NDP_ADDR_STATE_PREFERRED, byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime), byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime), 0); dio_dodag.prefix = rpl_opt_prefix_information_buf->prefix; dio_dodag.prefix_length = rpl_opt_prefix_information_buf->prefix_length; dio_dodag.prefix_valid_lifetime = byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime); dio_dodag.prefix_preferred_lifetime = byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime); dio_dodag.prefix_flags = rpl_opt_prefix_information_buf->flags; } } } len += RPL_OPT_PREFIX_INFO_LEN_WITH_OPT_LEN; break; } default: DEBUGF("[Error] Unsupported DIO option\n"); return; } } /* handle packet content... */ rpl_dodag_t *my_dodag = rpl_get_joined_dodag(dio_inst->id); if (my_dodag == NULL) { if (!has_dodag_conf_opt) { DEBUGF("send DIS\n"); rpl_send_DIS(&ipv6_buf->srcaddr); } if (byteorder_ntohs(rpl_dio_buf->rank) < ROOT_RANK) { DEBUGF("DIO with Rank < ROOT_RANK\n"); } if (dio_dodag.mop != RPL_DEFAULT_MOP) { DEBUGF("Required MOP not supported\n"); } if (dio_dodag.of == NULL) { DEBUGF("Required objective function not supported\n"); } if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) { DEBUGF("Will join DODAG\n"); rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); } else { DEBUGF("Cannot access DODAG because of DIO with infinite rank\n"); } return; } if (rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) { /* "our" DODAG */ if (RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) { if (my_dodag->my_rank == ROOT_RANK) { DEBUGF("[Warning] Inconsistent Dodag Version\n"); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); trickle_reset_timer(&my_dodag->trickle); } else { DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n"); my_dodag->version = dio_dodag.version; rpl_global_repair(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); } return; } else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { /* lower version number detected -> send more DIOs */ trickle_reset_timer(&my_dodag->trickle); return; } } /* version matches, DODAG matches */ if (byteorder_ntohs(rpl_dio_buf->rank) == INFINITE_RANK) { trickle_reset_timer(&my_dodag->trickle); } /* We are root, all done!*/ if (my_dodag->my_rank == ROOT_RANK) { if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) { trickle_increment_counter(&my_dodag->trickle); } return; } /********************* Parent Handling *********************/ rpl_parent_t *parent; parent = rpl_find_parent(my_dodag, &ipv6_buf->srcaddr); if (parent == NULL) { /* add new parent candidate */ parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank)); if (parent == NULL) { return; } } else { /* DIO OK */ trickle_increment_counter(&my_dodag->trickle); } /* update parent rank */ parent->rank = byteorder_ntohs(rpl_dio_buf->rank); rpl_parent_update(my_dodag, parent); if (my_dodag->my_preferred_parent == NULL) { DEBUGF("My dodag has no preferred_parent yet - seems to be odd since I have a parent...\n"); } else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) { rpl_delay_dao(my_dodag); } parent->dtsn = rpl_dio_buf->dtsn; }
/** * @brief FSM handling function for processing of an incomming TCP packet. * * @param[in,out] tcb TCB holding the connection information. * @param[in] in_pkt Incomming packet. * * @returns Zero on success. * -ENOMEM if receive buffer could not be allocated. */ static int _fsm_rcvd_pkt(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *in_pkt) { gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ uint16_t seq_con = 0; /* Sequence number consumption of outgoing packet */ gnrc_pktsnip_t *snp = NULL; /* Temporary packet snip */ gnrc_tcp_tcb_t *lst = NULL; /* Temporary pointer to TCB */ uint16_t ctl = 0; /* Control bits of the incomming packet */ uint32_t seg_seq = 0; /* Sequence number of the incomming packet*/ uint32_t seg_ack = 0; /* Acknowledgment number of the incomming packet */ uint32_t seg_wnd = 0; /* Receive window of the incomming packet */ uint32_t seg_len = 0; /* Segment length of the incomming packet */ uint32_t pay_len = 0; /* Payload length of the incomming packet */ DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt()\n"); /* Search for TCP header. */ LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_TCP); tcp_hdr_t *tcp_hdr = (tcp_hdr_t *) snp->data; /* Parse packet options, return if they are malformed */ if (_option_parse(tcb, tcp_hdr) < 0) { return 0; } /* Extract header values */ ctl = byteorder_ntohs(tcp_hdr->off_ctl); seg_seq = byteorder_ntohl(tcp_hdr->seq_num); seg_ack = byteorder_ntohl(tcp_hdr->ack_num); seg_wnd = byteorder_ntohs(tcp_hdr->window); /* Extract network layer header */ #ifdef MODULE_GNRC_IPV6 LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_IPV6); if (snp == NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : incomming packet had no IPv6 header\n"); return 0; } void *ip = snp->data; #endif /* Handle state LISTEN */ if (tcb->state == FSM_STATE_LISTEN) { /* 1) Check RST: if RST is set: return */ if (ctl & MSK_RST) { return 0; } /* 2) Check ACK: if ACK is set: send RST with seq_no = ack_no and return */ if (ctl & MSK_ACK) { _pkt_build_reset_from_pkt(&out_pkt, in_pkt); _pkt_send(tcb, out_pkt, 0, false); return 0; } /* 3) Check SYN: if SYN is set prepare for incomming connection */ if (ctl & MSK_SYN) { uint16_t src = byteorder_ntohs(tcp_hdr->src_port); uint16_t dst = byteorder_ntohs(tcp_hdr->dst_port); /* Check if SYN request is handled by another connection */ lst = _list_tcb_head; while (lst) { /* Compare port numbers and network layer adresses */ if (lst->local_port == dst && lst->peer_port == src) { #ifdef MODULE_GNRC_IPV6 if (snp->type == GNRC_NETTYPE_IPV6 && lst->address_family == AF_INET6) { ipv6_addr_t *dst_addr = &((ipv6_hdr_t *)ip)->dst; ipv6_addr_t *src_addr = &((ipv6_hdr_t *)ip)->src; if (ipv6_addr_equal((ipv6_addr_t *)lst->local_addr, dst_addr) && ipv6_addr_equal((ipv6_addr_t *)lst->peer_addr, src_addr)) { break; } } #endif } lst = lst->next; } /* Return if connection is already handled (port and addresses match) */ if (lst != NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : Connection already handled\n"); return 0; } /* SYN request is valid, fill TCB with connection information */ #ifdef MODULE_GNRC_IPV6 if (snp->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) { memcpy(tcb->local_addr, &((ipv6_hdr_t *)ip)->dst, sizeof(ipv6_addr_t)); memcpy(tcb->peer_addr, &((ipv6_hdr_t *)ip)->src, sizeof(ipv6_addr_t)); /* In case peer_addr is link local: Store interface Id in tcb */ if (ipv6_addr_is_link_local((ipv6_addr_t *) tcb->peer_addr)) { gnrc_pktsnip_t *tmp = NULL; LL_SEARCH_SCALAR(in_pkt, tmp, type, GNRC_NETTYPE_NETIF); /* cppcheck-suppress knownConditionTrueFalse * (reason: tmp *can* be != NULL after LL_SEARCH_SCALAR) */ if (tmp == NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() :\ incomming packet had no netif header\n"); return 0; } tcb->ll_iface = ((gnrc_netif_hdr_t *)tmp->data)->if_pid; }
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.", 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 = 0xFFFF; gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get(); 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. */ } return &(tmp_addr->addr); }
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; }
kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ipv6_addr_t *dst) { ipv6_addr_t *next_hop = NULL; gnrc_ipv6_nc_t *nc_entry = NULL; #ifdef MODULE_GNRC_IPV6_EXT_RH ipv6_hdr_t *hdr; gnrc_pktsnip_t *ipv6; LL_SEARCH_SCALAR(pkt, ipv6, type, GNRC_NETTYPE_IPV6); assert(ipv6); hdr = ipv6->data; next_hop = ipv6_ext_rh_next_hop(hdr); #endif #ifdef MODULE_FIB ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ /* don't look-up link local addresses in FIB */ if ((next_hop == NULL) && !ipv6_addr_is_link_local(dst)) { size_t next_hop_size = sizeof(ipv6_addr_t); uint32_t next_hop_flags = 0; if ((next_hop == NULL) && (fib_get_next_hop(&gnrc_ipv6_fib_table, &iface, next_hop_actual.u8, &next_hop_size, &next_hop_flags, (uint8_t *)dst, sizeof(ipv6_addr_t), 0) >= 0) && (next_hop_size == sizeof(ipv6_addr_t))) { next_hop = &next_hop_actual; } } #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* next hop determination: https://tools.ietf.org/html/rfc6775#section-6.5.4 */ nc_entry = gnrc_ipv6_nc_get(iface, dst); /* if NCE found */ if (nc_entry != NULL) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(nc_entry->iface); /* and interface is not 6LoWPAN */ if (!(ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) || /* or entry is registered */ (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED)) { next_hop = dst; } } #endif /* next hop determination according to: https://tools.ietf.org/html/rfc6775#section-5.6 */ if ((next_hop == NULL) && ipv6_addr_is_link_local(dst)) { /* prefix is "on-link" */ /* multicast is not handled here anyway so we don't need to check that */ next_hop = dst; } else if (next_hop == NULL) { /* prefix is off-link */ next_hop = gnrc_ndp_internal_default_router(); } /* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */ if ((nc_entry == NULL) || (next_hop != dst)) { /* get if not gotten from previous check */ nc_entry = gnrc_ipv6_nc_get(iface, next_hop); } /* If a NCE for this destination exist, we can use even for link-local * addresses. This should be only the case for 6LBRs. */ if ((ipv6_addr_is_link_local(next_hop)) && (nc_entry == NULL)) { /* in case of a border router there is no sensible way for address resolution * if the interface is not given */ #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER /* if no interface is specified it is impossible to resolve the * link-layer address for a link-local address on a 6LBR */ if (iface == KERNEL_PID_UNDEF) { return KERNEL_PID_UNDEF; } #endif kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = gnrc_netif_get(ifs); /* we don't need address resolution, the EUI-64 is in next_hop's IID */ *l2addr_len = sizeof(eui64_t); memcpy(l2addr, &next_hop->u8[8], sizeof(eui64_t)); _revert_iid(l2addr); if (iface == KERNEL_PID_UNDEF) { for (unsigned i = 0; i < ifnum; i++) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]); if ((ipv6_if != NULL) && (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { /* always take the first 6LoWPAN interface we can find */ return ifs[i]; } } } return iface; } if ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry)) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) { return KERNEL_PID_UNDEF; } else { if (nc_entry->l2_addr_len > 0) { memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len); } *l2addr_len = nc_entry->l2_addr_len; } return nc_entry->iface; }
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 void _netif_list(kernel_pid_t dev) { uint8_t hwaddr[MAX_ADDR_LEN]; uint16_t u16; int16_t i16; uint8_t u8; int res; netopt_state_t state; netopt_enable_t enable = NETOPT_DISABLE; bool linebreak = false; #ifdef MODULE_GNRC_IPV6_NETIF gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(dev); char ipv6_addr[IPV6_ADDR_MAX_STR_LEN]; #endif printf("Iface %2d ", dev); res = gnrc_netapi_get(dev, NETOPT_ADDRESS, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf(" HWaddr: "); printf("%s", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); printf(" "); } res = gnrc_netapi_get(dev, NETOPT_CHANNEL, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" Channel: %" PRIu16 " ", u16); } res = gnrc_netapi_get(dev, NETOPT_CHANNEL_PAGE, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" Page: %" PRIu16 " ", u16); } res = gnrc_netapi_get(dev, NETOPT_NID, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" NID: 0x%" PRIx16, u16); } printf("\n "); res = gnrc_netapi_get(dev, NETOPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf("Long HWaddr: "); printf("%s ", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); linebreak = true; } if (linebreak) { printf("\n "); } res = gnrc_netapi_get(dev, NETOPT_TX_POWER, 0, &i16, sizeof(i16)); if (res >= 0) { printf(" TX-Power: %" PRIi16 "dBm ", i16); } res = gnrc_netapi_get(dev, NETOPT_STATE, 0, &state, sizeof(state)); if (res >= 0) { printf(" State: "); _print_netopt_state(state); printf(" "); } res = gnrc_netapi_get(dev, NETOPT_RETRANS, 0, &u8, sizeof(u8)); if (res >= 0) { printf(" max. Retrans.: %u ", (unsigned)u8); } res = gnrc_netapi_get(dev, NETOPT_CSMA_RETRIES, 0, &u8, sizeof(u8)); if (res >= 0) { res = gnrc_netapi_get(dev, NETOPT_CSMA, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf(" CSMA Retries: %u ", (unsigned)u8); } } printf("\n "); res = gnrc_netapi_get(dev, NETOPT_PROMISCUOUSMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("PROMISC "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_AUTOACK, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("AUTOACK "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_ACK_REQ, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("ACK_REQ "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_PRELOADING, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("PRELOAD "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_RAWMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("RAWMODE "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_CSMA, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("CSMA "); linebreak = true; } res = gnrc_netapi_get(dev, NETOPT_AUTOCCA, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf("AUTOCCA "); linebreak = true; } #ifdef MODULE_GNRC_IPV6_NETIF if (entry != NULL) { printf("MTU:%" PRIu16 " ", entry->mtu); printf("HL:%u ", (unsigned)entry->cur_hl); if (entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { printf("6LO "); } if (entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { printf("RTR "); } if (entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) { printf("RTR_ADV "); } linebreak = true; } #endif #if defined(MODULE_GNRC_SIXLOWPAN_NETIF) && defined(MODULE_GNRC_SIXLOWPAN_IPHC) gnrc_sixlowpan_netif_t *sixlo_entry = gnrc_sixlowpan_netif_get(dev); if ((sixlo_entry != NULL) && (sixlo_entry->iphc_enabled)) { printf("IPHC "); linebreak = true; } #endif if (linebreak) { printf("\n "); } res = gnrc_netapi_get(dev, NETOPT_SRC_LEN, 0, &u16, sizeof(u16)); if (res >= 0) { printf("Source address length: %" PRIu16 "\n ", u16); } #ifdef MODULE_GNRC_IPV6_NETIF if (entry == NULL) { puts(""); return; } printf("Link type: %s", (entry->flags & GNRC_IPV6_NETIF_FLAGS_IS_WIRED) ? "wired" : "wireless"); printf("\n "); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if (!ipv6_addr_is_unspecified(&entry->addrs[i].addr)) { printf("inet6 addr: "); if (ipv6_addr_to_str(ipv6_addr, &entry->addrs[i].addr, IPV6_ADDR_MAX_STR_LEN)) { printf("%s/%u scope: ", ipv6_addr, (unsigned)entry->addrs[i].prefix_len); if ((ipv6_addr_is_link_local(&entry->addrs[i].addr))) { printf("local"); } else { printf("global"); } if (entry->addrs[i].flags & GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) { if (ipv6_addr_is_multicast(&entry->addrs[i].addr)) { printf(" [multicast]"); } else { printf(" [anycast]"); } } } else { printf("error in conversion"); } printf("\n "); } } #endif #ifdef MODULE_L2FILTER l2filter_t *filter = NULL; res = gnrc_netapi_get(dev, NETOPT_L2FILTER, 0, &filter, sizeof(filter)); if (res > 0) { #ifdef MODULE_L2FILTER_WHITELIST puts("\n White-listed link layer addresses:"); #else puts("\n Black-listed link layer addresses:"); #endif int count = 0; for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) { if (filter[i].addr_len > 0) { char hwaddr_str[filter[i].addr_len * 3]; gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), filter[i].addr, filter[i].addr_len); printf(" %2i: %s\n", count++, hwaddr_str); } } if (count == 0) { puts(" --- none ---"); } } #endif #ifdef MODULE_NETSTATS_L2 puts(""); _netif_stats(dev, NETSTATS_LAYER2, false); #endif #ifdef MODULE_NETSTATS_IPV6 _netif_stats(dev, NETSTATS_IPV6, false); #endif puts(""); }
static void _receive(gnrc_pktsnip_t *pkt) { kernel_pid_t iface = KERNEL_PID_UNDEF; gnrc_pktsnip_t *ipv6, *netif; ipv6_hdr_t *hdr; assert(pkt != NULL); LL_SEARCH_SCALAR(pkt, netif, type, GNRC_NETTYPE_NETIF); if (netif != NULL) { iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid; } if ((pkt->next != NULL) && (pkt->next->type == GNRC_NETTYPE_IPV6) && (pkt->next->size == sizeof(ipv6_hdr_t))) { /* IP header was already marked. Take it. */ ipv6 = pkt->next; if (!ipv6_hdr_is(ipv6->data)) { DEBUG("ipv6: Received packet was not IPv6, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } } else { if (!ipv6_hdr_is(pkt->data)) { DEBUG("ipv6: Received packet was not IPv6, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } /* seize ipv6 as a temporary variable */ ipv6 = gnrc_pktbuf_start_write(pkt); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to packet, drop it\n"); gnrc_pktbuf_release(pkt); return; } pkt = ipv6; /* reset pkt from temporary variable */ ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6); if (ipv6 == NULL) { DEBUG("ipv6: error marking IPv6 header, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } } /* extract header */ hdr = (ipv6_hdr_t *)ipv6->data; /* if available, remove any padding that was added by lower layers * to fulfill their minimum size requirements (e.g. ethernet) */ if (byteorder_ntohs(hdr->len) < pkt->size) { gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len)); } DEBUG("ipv6: Received (src = %s, ", ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str))); DEBUG("dst = %s, next header = %" PRIu8 ", length = %" PRIu16 ")\n", ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)), hdr->nh, byteorder_ntohs(hdr->len)); if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */ DEBUG("ipv6: packet destination not this host\n"); #ifdef MODULE_GNRC_IPV6_ROUTER /* only routers redirect */ /* redirect to next hop */ DEBUG("ipv6: decrement hop limit to %" PRIu8 "\n", hdr->hl - 1); /* RFC 4291, section 2.5.6 states: "Routers must not forward any * packets with Link-Local source or destination addresses to other * links." */ if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) { DEBUG("ipv6: do not forward packets with link-local source or"\ " destination address\n"); gnrc_pktbuf_release(pkt); return; } /* TODO: check if receiving interface is router */ else if (--(hdr->hl) > 0) { /* drop packets that *reach* Hop Limit 0 */ gnrc_pktsnip_t *tmp = pkt; DEBUG("ipv6: forward packet to next hop\n"); /* pkt might not be writable yet, if header was given above */ pkt = gnrc_pktbuf_start_write(tmp); ipv6 = gnrc_pktbuf_start_write(ipv6); if ((ipv6 == NULL) || (pkt == NULL)) { DEBUG("ipv6: unable to get write access to packet: dropping it\n"); gnrc_pktbuf_release(tmp); return; } gnrc_pktbuf_release(ipv6->next); /* remove headers around IPV6 */ ipv6->next = pkt; /* reorder for sending */ pkt->next = NULL; _send(ipv6, false); return; } else { DEBUG("ipv6: hop limit reached 0: drop packet\n"); gnrc_pktbuf_release(pkt); return; } #else /* MODULE_GNRC_IPV6_ROUTER */ DEBUG("ipv6: dropping packet\n"); /* non rounting hosts just drop the packet */ gnrc_pktbuf_release(pkt); return; #endif /* MODULE_GNRC_IPV6_ROUTER */ } /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */ gnrc_ipv6_demux(iface, pkt, hdr->nh); }