Esempio n. 1
0
void gnrc_sixlowpan_nd_uc_rtr_sol(gnrc_ipv6_nc_t *nce)
{
    assert(gnrc_ipv6_netif_get(nce->iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN);
    /* neighbor is not a router anymore */
    if (!(nce->flags & GNRC_IPV6_NC_IS_ROUTER) || ipv6_addr_is_unspecified(&nce->ipv6_addr)) {
        /* and there are no routers anymore */
        if (gnrc_ipv6_nc_get_next_router(NULL) == NULL) {
            /* start search for routers */
            gnrc_sixlowpan_nd_init(gnrc_ipv6_netif_get(nce->iface));
        }
        /* otherwise ignore this call */
        return;
    }
    /* next RS is rescheduled by RA handle function */
    gnrc_ndp_internal_send_rtr_sol(nce->iface, &nce->ipv6_addr);
}
Esempio n. 2
0
void gnrc_ipv6_netif_init_by_dev(void)
{
    kernel_pid_t ifs[GNRC_NETIF_NUMOF];
    size_t ifnum = gnrc_netif_get(ifs);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER
    bool abr_init = false;
#endif

    for (size_t i = 0; i < ifnum; i++) {
        ipv6_addr_t addr;
        eui64_t iid;
        uint16_t tmp;
        gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]);

        if (ipv6_if == NULL) {
            continue;
        }

        mutex_lock(&ipv6_if->mutex);

#ifdef MODULE_GNRC_SIXLOWPAN
        gnrc_nettype_t if_type = GNRC_NETTYPE_UNDEF;

        if ((gnrc_netapi_get(ifs[i], NETOPT_PROTO, 0, &if_type,
                             sizeof(if_type)) != -ENOTSUP) &&
            (if_type == GNRC_NETTYPE_SIXLOWPAN)) {
            uint16_t src_len = 8;
            uint16_t max_frag_size = UINT16_MAX;

            DEBUG("ipv6 netif: Set 6LoWPAN flag\n");
            ipv6_ifs[i].flags |= GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN;

            /* the router flag must be set early here, because otherwise
             * _add_addr_to_entry() wouldn't set the solicited node address.
             * However, addresses have to be configured before calling
             * gnrc_ipv6_netif_set_router().
             */
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
            DEBUG("ipv6 netif: Set router flag\n");
            ipv6_ifs[i].flags |= GNRC_IPV6_NETIF_FLAGS_ROUTER;
#endif
            /* use EUI-64 (8-byte address) for IID generation and for sending
             * packets */
            gnrc_netapi_set(ifs[i], NETOPT_SRC_LEN, 0, &src_len,
                            sizeof(src_len)); /* don't care for result */

            if (gnrc_netapi_get(ifs[i], NETOPT_MAX_PACKET_SIZE,
                                0, &max_frag_size, sizeof(max_frag_size)) < 0) {
                /* if error we assume it works */
                DEBUG("ipv6 netif: Can not get max packet size from interface %"
                      PRIkernel_pid "\n", ifs[i]);
            }

            gnrc_sixlowpan_netif_add(ifs[i], max_frag_size);
        }
#endif

        /* set link-local address */
        if ((gnrc_netapi_get(ifs[i], NETOPT_IPV6_IID, 0, &iid,
                             sizeof(eui64_t)) < 0)) {
            mutex_unlock(&ipv6_if->mutex);
            continue;
        }

        ipv6_addr_set_aiid(&addr, iid.uint8);
        ipv6_addr_set_link_local_prefix(&addr);
        _add_addr_to_entry(ipv6_if, &addr, 64, 0);

        /* set link MTU */
        if ((gnrc_netapi_get(ifs[i], NETOPT_MAX_PACKET_SIZE, 0, &tmp,
                             sizeof(uint16_t)) >= 0)) {
            if (tmp >= IPV6_MIN_MTU) {
                ipv6_if->mtu = tmp;
            }
            /* otherwise leave at GNRC_IPV6_NETIF_DEFAULT_MTU as initialized in
             * gnrc_ipv6_netif_add() */
        }

        if (gnrc_netapi_get(ifs[i], NETOPT_IS_WIRED, 0, &tmp, sizeof(int)) > 0) {
            ipv6_if->flags |= GNRC_IPV6_NETIF_FLAGS_IS_WIRED;
        }
        else {
            ipv6_if->flags &= ~GNRC_IPV6_NETIF_FLAGS_IS_WIRED;
        }

        mutex_unlock(&ipv6_if->mutex);
#if (defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER))
        gnrc_ipv6_netif_set_router(ipv6_if, true);
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND
        if (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
#ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER
            /* first interface wins */
            if (!abr_init) {
                gnrc_sixlowpan_nd_router_abr_create(&addr, 0);
                gnrc_ipv6_netif_set_rtr_adv(ipv6_if, true);
                abr_init = true;
            }
#endif
            gnrc_sixlowpan_nd_init(ipv6_if);
            continue;   /* skip gnrc_ndp_host_init() */
        }
#endif
#ifdef MODULE_GNRC_NDP_HOST
        /* start periodic router solicitations */
        gnrc_ndp_host_init(ipv6_if);
#endif
    }
}
Esempio n. 3
0
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;
}