예제 #1
0
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);
}
예제 #2
0
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;
}