static bool _try_addr_reconfiguration(gnrc_netif_t *netif) { eui64_t orig_iid; bool remove_old = false, hwaddr_reconf; if (gnrc_netif_ipv6_get_iid(netif, &orig_iid) > 0) { remove_old = true; } /* seize netif to netif thread since _try_l2addr_reconfiguration uses * gnrc_netapi_get()/gnrc_netapi_set(). Since these are synchronous this is * safe */ gnrc_netif_release(netif); /* reacquire netif for IPv6 address reconfiguraton */ hwaddr_reconf = _try_l2addr_reconfiguration(netif); gnrc_netif_acquire(netif); if (hwaddr_reconf) { if (remove_old) { for (unsigned i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { ipv6_addr_t *addr = &netif->ipv6.addrs[i]; if (addr->u64[1].u64 == orig_iid.uint64.u64) { gnrc_netif_ipv6_addr_remove_internal(netif, addr); } } } DEBUG("nib: Changed hardware address, due to DAD\n"); _auto_configure_addr(netif, &ipv6_addr_link_local_prefix, 64U); } return hwaddr_reconf; }
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 */ }
int gnrc_netif_get_from_netdev(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt) { int res = -ENOTSUP; gnrc_netif_acquire(netif); switch (opt->opt) { case NETOPT_HOP_LIMIT: assert(opt->data_len == sizeof(uint8_t)); *((uint8_t *)opt->data) = netif->cur_hl; res = sizeof(uint8_t); break; case NETOPT_STATS: /* XXX discussed this with Oleg, it's supposed to be a pointer */ switch ((int16_t)opt->context) { #if defined(MODULE_NETSTATS_IPV6) && defined(MODULE_GNRC_IPV6) case NETSTATS_IPV6: assert(opt->data_len == sizeof(netstats_t *)); *((netstats_t **)opt->data) = &netif->ipv6.stats; res = sizeof(&netif->ipv6.stats); break; #endif default: /* take from device */ break; } break; #ifdef MODULE_GNRC_IPV6 case NETOPT_IPV6_ADDR: { assert(opt->data_len >= sizeof(ipv6_addr_t)); ipv6_addr_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_ADDRS_NUMOF); i++) { if (netif->ipv6.addrs_flags[i] != 0) { memcpy(tgt, &netif->ipv6.addrs[i], sizeof(ipv6_addr_t)); res += sizeof(ipv6_addr_t); tgt++; } } } break; case NETOPT_IPV6_ADDR_FLAGS: { assert(opt->data_len >= sizeof(uint8_t)); uint8_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_ADDRS_NUMOF); i++) { if (netif->ipv6.addrs_flags[i] != 0) { *tgt = netif->ipv6.addrs_flags[i]; res += sizeof(uint8_t); tgt++; } } } break; case NETOPT_IPV6_GROUP: { assert(opt->data_len >= sizeof(ipv6_addr_t)); ipv6_addr_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_GROUPS_NUMOF); i++) { if (!ipv6_addr_is_unspecified(&netif->ipv6.groups[i])) { memcpy(tgt, &netif->ipv6.groups[i], sizeof(ipv6_addr_t)); res += sizeof(ipv6_addr_t); tgt++; } } } break; case NETOPT_IPV6_IID: assert(opt->data_len >= sizeof(eui64_t)); if (gnrc_netif_ipv6_get_iid(netif, opt->data) == 0) { res = sizeof(eui64_t); } break; case NETOPT_MAX_PACKET_SIZE: if (opt->context == GNRC_NETTYPE_IPV6) { assert(opt->data_len == sizeof(uint16_t)); *((uint16_t *)opt->data) = netif->ipv6.mtu; res = sizeof(uint16_t); } /* else ask device */ break; #if GNRC_IPV6_NIB_CONF_ROUTER case NETOPT_IPV6_FORWARDING: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (gnrc_netif_is_rtr(netif)) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; case NETOPT_IPV6_SND_RTR_ADV: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (gnrc_netif_is_rtr_adv(netif)) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; #endif /* GNRC_IPV6_NIB_CONF_ROUTER */ #endif /* MODULE_GNRC_IPV6 */ #ifdef MODULE_GNRC_SIXLOWPAN_IPHC case NETOPT_6LO_IPHC: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (netif->flags & GNRC_NETIF_FLAGS_6LO_HC) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; #endif /* MODULE_GNRC_SIXLOWPAN_IPHC */ default: break; } if (res == -ENOTSUP) { res = netif->dev->driver->get(netif->dev, opt->opt, opt->data, opt->data_len); } gnrc_netif_release(netif); return res; }