Exemplo n.º 1
0
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
#ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER
            gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get();
            gnrc_sixlowpan_nd_router_abr_rem_prf(abr, entry, &entry->addrs[i]);
#endif

            mutex_unlock(&entry->mutex);
            return;
        }
    }

    mutex_unlock(&entry->mutex);
}
Exemplo n.º 2
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);
}
Exemplo n.º 3
0
void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
                                    bool fin)
{
    gnrc_pktsnip_t *hdr, *pkt = NULL;
    ipv6_addr_t all_nodes = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
    gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
    uint32_t reach_time = 0, retrans_timer = 0;
    uint16_t adv_ltime = 0;
    uint8_t cur_hl = 0;

    if (dst == NULL) {
        dst = &all_nodes;
    }
    DEBUG("ndp internal: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n",
          iface, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), fin ? ", final" : "");
    mutex_lock(&ipv6_iface->mutex);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
    if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
#endif
    hdr = _add_pios(ipv6_iface, pkt);
    if (hdr == NULL) {
        /* pkt already released in _add_pios */
        mutex_unlock(&ipv6_iface->mutex);
        return;
    }
    pkt = hdr;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
    }
    else {
        gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get();
        if (abr != NULL) {
            gnrc_sixlowpan_nd_router_prf_t *prf = abr->prfs;
            /* add prefixes from border router */
            while (prf) {
                bool processed_before = false;
                /* skip if prefix does not belong to iface */
                if (prf->iface != ipv6_iface) {
                    prf = prf->next;
                    continue;
                }
                /* skip if prefix has been processed already */
                for (gnrc_sixlowpan_nd_router_prf_t *tmp = abr->prfs; tmp != prf; tmp = tmp->next) {
                    if ((processed_before =
                             _check_prefixes(prf->prefix, tmp->prefix))) {
                        break;
                    }
                }

                if (processed_before) {
                    prf = prf->next;
                    continue;
                }

                if (_pio_from_iface_addr(&hdr, prf->prefix, pkt)) {
                    if (hdr != NULL) {
                        pkt = hdr;
                    }
                    else {
                        DEBUG("ndp rtr: error allocating PIO\n");
                        gnrc_pktbuf_release(pkt);
                        return;
                    }
                }
                prf = prf->next;
            }
            for (unsigned int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) {
                gnrc_sixlowpan_ctx_t *ctx;
                if (!bf_isset(abr->ctxs, i)) {
                    continue;
                }
                ctx = gnrc_sixlowpan_ctx_lookup_id(i);
                hdr = gnrc_sixlowpan_nd_opt_6ctx_build(ctx->prefix_len, ctx->flags_id, ctx->ltime,
                                                       &ctx->prefix, pkt);
                if (hdr == NULL) {
                    DEBUG("ndp rtr: error allocating 6CO\n");
                    gnrc_pktbuf_release(pkt);
                    return;
                }
                pkt = hdr;
            }
            hdr = gnrc_sixlowpan_nd_opt_abr_build(abr->version, abr->ltime, &abr->addr, pkt);
            if (hdr == NULL) {
                DEBUG("ndp internal: error allocating ABRO.\n");
                gnrc_pktbuf_release(pkt);
                return;
            }
            pkt = hdr;
        }
    }
#endif /* MODULE_GNRC_SIXLOWPAN_ND_ROUTER */
    if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) {
        if ((hdr = gnrc_ndp_opt_mtu_build(ipv6_iface->mtu, pkt)) == NULL) {
            DEBUG("ndp rtr: no space left in packet buffer\n");
            mutex_unlock(&ipv6_iface->mutex);
            gnrc_pktbuf_release(pkt);
            return;
        }
        pkt = hdr;
    }
    if (src == NULL) {
        mutex_unlock(&ipv6_iface->mutex);
        /* get address from source selection algorithm */
        src = gnrc_ipv6_netif_find_best_src_addr(iface, dst);
        mutex_lock(&ipv6_iface->mutex);
    }
    /* add SL2A for source address */
    if (src != NULL) {
        DEBUG(" - SL2A\n");
        uint8_t l2src[8];
        size_t l2src_len;
        /* optimization note: MAY also be omitted to facilitate in-bound load balancing over
         * replicated interfaces.
         * source: https://tools.ietf.org/html/rfc4861#section-6.2.3 */
        l2src_len = _get_l2src(iface, l2src, sizeof(l2src));
        if (l2src_len > 0) {
            /* add source address link-layer address option */
            hdr = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, pkt);

            if (hdr == NULL) {
                DEBUG("ndp internal: error allocating Source Link-layer address option.\n");
                mutex_unlock(&ipv6_iface->mutex);
                gnrc_pktbuf_release(pkt);
                return;
            }
            pkt = hdr;
        }
    }
    if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_CUR_HL) {
        cur_hl = ipv6_iface->cur_hl;
    }
    if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_REACH_TIME) {

        if (ipv6_iface->reach_time > (3600 * SEC_IN_USEC)) { /* reach_time > 1 hour */
            reach_time = (3600 * SEC_IN_MS);
        }
        else {
            reach_time = ipv6_iface->reach_time / MS_IN_USEC;
        }
    }
    if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER) {
        retrans_timer = ipv6_iface->retrans_timer / MS_IN_USEC;
    }
    if (!fin) {
        adv_ltime = ipv6_iface->adv_ltime;
    }
    mutex_unlock(&ipv6_iface->mutex);
    hdr = gnrc_ndp_rtr_adv_build(cur_hl,
                                 (ipv6_iface->flags & (GNRC_IPV6_NETIF_FLAGS_OTHER_CONF |
                                                       GNRC_IPV6_NETIF_FLAGS_MANAGED)) >> 8,
                                 adv_ltime, reach_time, retrans_timer, pkt);
    if (hdr == NULL) {
        DEBUG("ndp internal: error allocating router advertisement.\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
    pkt = hdr;
    hdr = _build_headers(iface, pkt, dst, src);
    if (hdr == NULL) {
        DEBUG("ndp internal: error adding lower-layer headers.\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
    else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) {
        DEBUG("ndp internal: unable to send router advertisement\n");
        gnrc_pktbuf_release(hdr);
    }
}