Exemple #1
0
static void test_pktqueue_remove_head_empty(void)
{
    ng_pktqueue_t *root = &q;
    ng_pktqueue_node_t *res;

    res = ng_pktqueue_remove_head(root);

    TEST_ASSERT_NULL(res);
}
Exemple #2
0
static void test_pktqueue_remove_head_one(void)
{
    ng_pktqueue_t *root = &q;
    ng_pktqueue_node_t *elem = &(qe[1]), *res;

    elem->data = (ng_pktsnip_t *)62801;

    ng_pktqueue_add(root, elem);

    res = ng_pktqueue_remove_head(root);

    TEST_ASSERT(res == elem);
    TEST_ASSERT(((ng_pktsnip_t *)62801) == res->data);

    res = ng_pktqueue_remove_head(root);

    TEST_ASSERT_NULL(res);
}
Exemple #3
0
void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt,
                           ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_adv_t *nbr_adv,
                           size_t icmpv6_size)
{
    uint16_t opt_offset = 0;
    uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ng_ndp_nbr_adv_t);
    int l2tgt_len = 0;
    uint8_t l2tgt[NG_IPV6_NC_L2_ADDR_MAX];
    int sicmpv6_size = (int)icmpv6_size;
    ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, &nbr_adv->tgt);
    ng_pktsnip_t *netif;
    ng_netif_hdr_t *netif_hdr = NULL;

    DEBUG("ndp: received neighbor advertisement (src: %s, ",
          ng_ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
    DEBUG("dst: %s, ",
          ng_ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
    DEBUG("tgt: %s)\n",
          ng_ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str)));

    /* check validity */
    if ((ipv6->hl != 255) || (nbr_adv->code != 0) ||
        (icmpv6_size < sizeof(ng_ndp_nbr_adv_t)) ||
        ng_ipv6_addr_is_multicast(&nbr_adv->tgt)) {
        DEBUG("ndp: neighbor advertisement was invalid.\n");
        /* ipv6 releases */
        return;
    }

    if (nc_entry == NULL) {
        /* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */
        DEBUG("ndp: no neighbor cache entry found for advertisement's target\n");
        /* ipv6 releases */
        return;
    }

    sicmpv6_size -= sizeof(ng_ndp_nbr_adv_t);

    while (sicmpv6_size > 0) {
        ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset);

        switch (opt->type) {
            case NG_NDP_OPT_TL2A:
                if ((l2tgt_len = _handle_tl2a_opt(pkt, ipv6, nbr_adv->type, opt,
                                                  l2tgt)) < 0) {
                    /* invalid target link-layer address option */
                    return;
                }

                break;

            default:
                /* silently discard all other options */
                break;
        }

        opt_offset += (opt->len * 8);
        sicmpv6_size -= (opt->len * 8);
    }

    LL_SEARCH_SCALAR(pkt, netif, type, NG_NETTYPE_NETIF);

    if (netif != NULL) {
        netif_hdr = netif->data;
    }

    if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) {
        ng_pktqueue_t *queued_pkt;

        if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) {
            /* link-layer has addresses, but no TLLAO supplied: discard silently
             * (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */
            return;
        }

        nc_entry->iface = iface;
        nc_entry->l2_addr_len = l2tgt_len;
        memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);

        if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) {
            _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
        }
        else {
            _set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
        }

        if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) {
            nc_entry->flags |= NG_IPV6_NC_IS_ROUTER;
        }
        else {
            nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER;
            /* TODO: update FIB */
        }

        while ((queued_pkt = ng_pktqueue_remove_head(&nc_entry->pkts)) != NULL) {
            ng_netapi_send(ng_ipv6_pid, queued_pkt->pkt);
            queued_pkt->pkt = NULL;
        }
    }
    else {
        /* first or-term: no link-layer, but nc_entry has l2addr,
         * second or-term: different l2addr cached */
        bool l2tgt_changed = false;

        if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) {
            /* there was previously a L2 address registered */
            l2tgt_changed = (nc_entry->l2_addr_len != 0);
        }
        /* link-layer has addresses and TLLAO with different address */
        else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) {
            l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) &&
                            (memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0);
        }

        if ((nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed ||
            (l2tgt_len == 0)) {
            if (l2tgt_len != 0) {
                nc_entry->iface = iface;
                nc_entry->l2_addr_len = l2tgt_len;
                memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
            }

            if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) {
                _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE);
            }
            else if (l2tgt_changed && (l2tgt_len != 0)) {
                _set_state(nc_entry, NG_IPV6_NC_STATE_STALE);
            }

            if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) {
                nc_entry->flags |= NG_IPV6_NC_IS_ROUTER;
            }
            else {
                nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER;
                /* TODO: update FIB */
            }
        }
        else if (l2tgt_changed) {
            if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_REACHABLE) {
                _set_state(nc_entry, NG_IPV6_NC_STATE_STALE);

            }
        }
    }

    return;
}
Exemple #4
0
void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry)
{
    if ((nc_entry->probes_remaining > 1) &&
        ((ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) ||
         (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_PROBE))) {
        ng_ipv6_addr_t dst;

        DEBUG("ndp: Retransmit neighbor solicitation for %s\n",
              ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)));

        /* retransmit neighbor solicatation */
        if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) {
            ng_ipv6_addr_set_solicited_nodes(&dst, &nc_entry->ipv6_addr);
        }
        else {
            dst.u64[0] = nc_entry->ipv6_addr.u64[0];
            dst.u64[1] = nc_entry->ipv6_addr.u64[1];
        }

        nc_entry->probes_remaining--;

        if (nc_entry->iface == KERNEL_PID_UNDEF) {
            timex_t t = { 0, NG_NDP_RETRANS_TIMER };
            kernel_pid_t ifs[NG_NETIF_NUMOF];
            size_t ifnum = ng_netif_get(ifs);

            for (size_t i = 0; i < ifnum; i++) {
                _send_nbr_sol(ifs[i], &nc_entry->ipv6_addr, &dst);
            }

            vtimer_remove(&nc_entry->nbr_sol_timer);
            vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid,
                           NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
        }
        else {
            ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(nc_entry->iface);

            _send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst);

            mutex_lock(&ipv6_iface->mutex);
            vtimer_remove(&nc_entry->nbr_sol_timer);
            vtimer_set_msg(&nc_entry->nbr_sol_timer,
                           ipv6_iface->retrans_timer, ng_ipv6_pid,
                           NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
            mutex_unlock(&ipv6_iface->mutex);
        }
    }
    else if (nc_entry->probes_remaining <= 1) {
        ng_pktqueue_node_t *queue_node;

        /* No need to call ng_ipv6_nc_remove() we know already were the
         * entry is */

        DEBUG("ndp: Remove nc entry %s for interface %" PRIkernel_pid "\n",
              ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)),
              nc_entry->iface);

        while ((queue_node = ng_pktqueue_remove_head(&nc_entry->pkts))) {
            ng_pktbuf_release(queue_node->data);
            queue_node->data = NULL;
        }

        ng_ipv6_addr_set_unspecified(&(nc_entry->ipv6_addr));
        nc_entry->iface = KERNEL_PID_UNDEF;
        nc_entry->flags = 0;
        nc_entry->probes_remaining = 0;
    }
}