Exemplo n.º 1
0
void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                             ipv6_hdr_t *ipv6, ndp_nbr_sol_t *nbr_sol,
                             size_t icmpv6_size)
{
    uint16_t opt_offset = 0;
    uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
    uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ndp_nbr_sol_t);
    ipv6_addr_t *tgt;
    int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
    DEBUG("ndp: received neighbor solicitation (src: %s, ",
          ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
    DEBUG("dst: %s, ",
          ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
    DEBUG("tgt: %s)\n",
          ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str)));
    /* check validity */
    if ((ipv6->hl != 255) || (nbr_sol->code != 0) ||
        (icmpv6_size < sizeof(ndp_nbr_sol_t)) ||
        ipv6_addr_is_multicast(&nbr_sol->tgt) ||
        (ipv6_addr_is_unspecified(&ipv6->src) &&
         ipv6_addr_is_solicited_node(&ipv6->dst))) {
        DEBUG("ndp: neighbor solicitation was invalid.\n");
        /* ipv6 releases */
        return;
    }
    if ((tgt = gnrc_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) {
        DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n",
              iface);
        /* ipv6 releases */
        return;
    }
    sicmpv6_size -= sizeof(ndp_nbr_sol_t);
    while (sicmpv6_size > 0) {
        ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
        switch (opt->type) {
            case NDP_OPT_SL2A:
                if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, nbr_sol->type, opt,
                                                                   l2src)) < 0) {
                    /* -ENOTSUP can not happen, since the function only returns this for invalid
                     * message types containing the SL2A. Neighbor solicitations are not an
                     * invalid message type for SL2A. According to that, we don't need to watch
                     * out for that here, but regardless, the source link-layer address option
                     * is invalid. */
                    return;
                }
                break;
            default:
                /* silently discard all other options */
                break;
        }
        opt_offset += (opt->len * 8);
        sicmpv6_size -= (opt->len * 8);
    }
    _stale_nc(iface, &ipv6->src, l2src, l2src_len);
    gnrc_ndp_internal_send_nbr_adv(iface, tgt, &ipv6->src, ipv6_addr_is_multicast(&ipv6->dst),
                                   NULL);
}
Exemplo n.º 2
0
void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                             ipv6_hdr_t *ipv6, ndp_nbr_sol_t *nbr_sol,
                             size_t icmpv6_size)
{
    uint16_t opt_offset = 0;
    uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
    uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ndp_nbr_sol_t);
    ipv6_addr_t *tgt, nbr_adv_dst;
    gnrc_pktsnip_t *nbr_adv_opts = NULL;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
    ndp_opt_t *sl2a_opt = NULL;
    sixlowpan_nd_opt_ar_t *ar_opt = NULL;
#endif
    int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
    DEBUG("ndp: received neighbor solicitation (src: %s, ",
          ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
    DEBUG("dst: %s, ",
          ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
    DEBUG("tgt: %s)\n",
          ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str)));
    /* check validity */
    if ((ipv6->hl != 255) || (nbr_sol->code != 0) ||
        (icmpv6_size < sizeof(ndp_nbr_sol_t)) ||
        ipv6_addr_is_multicast(&nbr_sol->tgt) ||
        (ipv6_addr_is_unspecified(&ipv6->src) &&
         ipv6_addr_is_solicited_node(&ipv6->dst))) {
        DEBUG("ndp: neighbor solicitation was invalid.\n");
        /* ipv6 releases */
        return;
    }
    if ((tgt = gnrc_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) {
        DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n",
              iface);
        /* ipv6 releases */
        return;
    }
    sicmpv6_size -= sizeof(ndp_nbr_sol_t);
    while (sicmpv6_size > 0) {
        ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
        switch (opt->type) {
            case NDP_OPT_SL2A:
                if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, nbr_sol->type, opt,
                                                                   l2src)) < 0) {
                    /* -ENOTSUP can not happen, since the function only returns this for invalid
                     * message types containing the SL2A. Neighbor solicitations are not an
                     * invalid message type for SL2A. According to that, we don't need to watch
                     * out for that here, but regardless, the source link-layer address option
                     * is invalid. */
                    return;
                }
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
                sl2a_opt = opt;
                break;
            case NDP_OPT_AR:
                /* actually handling at the end of the function (see below) */
                ar_opt = (sixlowpan_nd_opt_ar_t *)opt;
#endif
                break;
            default:
                /* silently discard all other options */
                break;
        }
        opt_offset += (opt->len * 8);
        sicmpv6_size -= (opt->len * 8);

#if ENABLE_DEBUG
        if (sicmpv6_size < 0) {
            DEBUG("ndp: Option parsing out of sync.\n");
        }
#endif
    }
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
    gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface);
    assert(ipv6_iface != NULL);
    if ((sl2a_opt != NULL) && (ar_opt != NULL) &&
        (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
        (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
        uint8_t status = gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6,
                                                         nbr_sol->type,
                                                         &ipv6->src, ar_opt,
                                                         l2src, l2src_len);
        /* check for multihop DAD return */
        nbr_adv_opts = gnrc_sixlowpan_nd_opt_ar_build(status, GNRC_SIXLOWPAN_ND_AR_LTIME,
                                                      &ar_opt->eui64, NULL);
        if (status == 0) {
            memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
        }
        else {
            /* see https://tools.ietf.org/html/rfc6775#section-6.5.2 */
            eui64_t iid;
            ieee802154_get_iid(&iid, ar_opt->eui64.uint8, sizeof(eui64_t));
            ipv6_addr_set_iid(&nbr_adv_dst, iid.uint64.u64);
            ipv6_addr_set_link_local_prefix(&nbr_adv_dst);
        }
    }
    else {  /* gnrc_sixlowpan_nd_opt_ar_handle updates neighbor cache */
        _stale_nc(iface, &ipv6->src, l2src, l2src_len);
        memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
    }
#else
    _stale_nc(iface, &ipv6->src, l2src, l2src_len);
    memcpy(&nbr_adv_dst, &ipv6->src, sizeof(ipv6_addr_t));
#endif
    gnrc_ndp_internal_send_nbr_adv(iface, tgt, &nbr_adv_dst, ipv6_addr_is_multicast(&ipv6->dst),
                                   nbr_adv_opts);
}
Exemplo n.º 3
0
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
                             ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size)
{
    uint8_t *buf = (uint8_t *)(rtr_adv + 1);
    gnrc_ipv6_nc_t *nc_entry = NULL;
    gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
    uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
#ifdef MODULE_GNRC_SIXLOWPAN_ND
    uint32_t next_rtr_sol = 0;
#endif
    int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
    uint16_t opt_offset = 0;

    if (!ipv6_addr_is_link_local(&ipv6->src) ||
        ipv6_addr_is_multicast(&ipv6->src) ||
        (ipv6->hl != 255) || (rtr_adv->code != 0) ||
        (icmpv6_size < sizeof(ndp_rtr_adv_t))) {
        DEBUG("ndp: router advertisement was invalid\n");
        /* ipv6 releases */
        return;
    }
    /* get source from default router list */
    nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
    if (nc_entry == NULL) { /* not in default router list */
        /* create default router list entry */
        nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0,
                                    GNRC_IPV6_NC_IS_ROUTER);
        if (nc_entry == NULL) {
            DEBUG("ndp: error on default router list entry creation\n");
            return;
        }
    }
    else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) {
        nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
    }
    else {
        nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
    }
    /* set router life timer */
    if (rtr_adv->ltime.u16 != 0) {
        uint16_t ltime = byteorder_ntohs(rtr_adv->ltime);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
        next_rtr_sol = ltime;
#endif
        xtimer_set_msg(&nc_entry->rtr_timeout, (ltime * SEC_IN_USEC),
                       &nc_entry->rtr_timeout_msg, thread_getpid());
    }
    /* set current hop limit from message if available */
    if (rtr_adv->cur_hl != 0) {
        if_entry->cur_hl = rtr_adv->cur_hl;
    }
    /* set flags from message */
    if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
    if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) &
                       GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
    /* set reachable time from message if it is not the same as the random base
     * value */
    if ((rtr_adv->reach_time.u32 != 0) &&
        (if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) {
        _set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time));
    }
    /* set retransmission timer from message */
    if (rtr_adv->retrans_timer.u32 != 0) {
        if_entry->retrans_timer = timex_set(0, byteorder_ntohl(rtr_adv->retrans_timer));
        timex_normalize(&if_entry->retrans_timer);
    }
    mutex_unlock(&if_entry->mutex);
    sicmpv6_size -= sizeof(ndp_rtr_adv_t);
    /* parse options */
    while (sicmpv6_size > 0) {
        ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
        switch (opt->type) {
            case NDP_OPT_SL2A:
                if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt,
                                                                   l2src)) < 0) {
                    /* -ENOTSUP can not happen */
                    /* invalid source link-layer address option */
                    return;
                }
                break;
            case NDP_OPT_MTU:
                if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) {
                    /* invalid MTU option */
                    return;
                }
                break;
            case NDP_OPT_PI:
                if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) {
                    /* invalid prefix information option */
                    return;
                }
#ifdef MODULE_GNRC_SIXLOWPAN_ND
                uint32_t valid_ltime = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime);
                if ((valid_ltime != 0) && (valid_ltime < next_rtr_sol)) {
                    next_rtr_sol = valid_ltime;
                }
#endif
                break;
#ifdef MODULE_GNRC_SIXLOWPAN_ND
            case NDP_OPT_6CTX:
                if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type,
                                                       (sixlowpan_nd_opt_6ctx_t *)opt)) {
                    /* invalid 6LoWPAN context option */
                    return;
                }
                uint16_t ltime = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime);
                if ((ltime != 0) && (ltime < (next_rtr_sol / 60))) {
                    next_rtr_sol = ltime * 60;
                }

                break;
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
            case NDP_OPT_ABR:
                gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size,
                                                 (sixlowpan_nd_opt_abr_t *)opt);
                break;
#endif
        }

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

#if ENABLE_DEBUG
        if (sicmpv6_size < 0) {
            DEBUG("ndp: Option parsing out of sync.\n");
        }
#endif
    }
#if ENABLE_DEBUG && defined(MODULE_GNRC_SIXLOWPAN_ND)
    if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) {
        DEBUG("ndp: Router advertisement did not contain any source address information\n");
    }
#endif
    _stale_nc(iface, &ipv6->src, l2src, l2src_len);
    /* stop multicast router solicitation retransmission timer */
    xtimer_remove(&if_entry->rtr_sol_timer);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
    if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
        /* 3/4 of the time should be "well before" enough the respective timeout
         * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */
        next_rtr_sol *= 3;
        next_rtr_sol = (next_rtr_sol > 4) ? (next_rtr_sol >> 2) : 1;
        /* according to https://tools.ietf.org/html/rfc6775#section-5.3:
         * "In all cases, the RS retransmissions are terminated when an RA is
         *  received."
         *  Hence, reset router solicitation counter and reset timer. */
        if_entry->rtr_sol_count = 0;
        gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol);
        gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr,
                                       &nc_entry->ipv6_addr);
        if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
            gnrc_ipv6_netif_set_rtr_adv(if_entry, true);
        }
    }
Exemplo n.º 4
0
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                             ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol,
                             size_t icmpv6_size)
{
    gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);

    if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
        int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
        uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
        uint16_t opt_offset = 0;
        uint8_t *buf = (uint8_t *)(rtr_sol + 1);
        /* check validity */
        if ((ipv6->hl != 255) || (rtr_sol->code != 0) ||
            (icmpv6_size < sizeof(ndp_rtr_sol_t))) {
            DEBUG("ndp: router solicitation was invalid\n");
            return;
        }
        sicmpv6_size -= sizeof(ndp_rtr_sol_t);
        while (sicmpv6_size > 0) {
            ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);

            switch (opt->type) {
                case NDP_OPT_SL2A:
                    if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_sol->type, opt,
                                                                       l2src)) < 0) {
                        /* -ENOTSUP can not happen */
                        /* invalid source link-layer address option */
                        return;
                    }
                    break;

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

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

#if ENABLE_DEBUG
            if (sicmpv6_size < 0) {
                DEBUG("ndp: Option parsing out of sync.\n");
            }
#endif
        }
        _stale_nc(iface, &ipv6->src, l2src, l2src_len);
        /* send delayed */
        if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) {
            uint32_t delay;
            uint32_t ms = GNRC_NDP_MAX_RTR_ADV_DELAY;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
            if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
                ms = GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY;
            }
#endif
            delay = genrand_uint32_range(0, ms);
            xtimer_remove(&if_entry->rtr_adv_timer);
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
            /* in case of a 6LBR we have to check if the interface is actually
             * the 6lo interface */
            if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
                gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
                if (nc_entry != NULL) {
                    if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY;
                    if_entry->rtr_adv_msg.content.ptr = (char *) nc_entry;
                    xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg,
                                   gnrc_ipv6_pid);
                }
            }
#elif defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER)
            if (ipv6_addr_is_unspecified(&ipv6->src)) {
                /* either multicast, if source unspecified */
                if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS;
                if_entry->rtr_adv_msg.content.ptr = (char *) if_entry;
                xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg,
                               gnrc_ipv6_pid);
            }
            else {
                /* or unicast, if source is known */
                /* XXX: can't just use GNRC_NETAPI_MSG_TYPE_SND, since the next retransmission
                 * must also be set. */
                gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
                xtimer_set_msg(&nc_entry->rtr_adv_timer, delay, &nc_entry->rtr_adv_msg,
                               gnrc_ipv6_pid);
            }
#endif
        }
    }
    /* otherwise ignore silently */
}
Exemplo n.º 5
0
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                             ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol,
                             size_t icmpv6_size)
{
    gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);

    if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
        int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
        uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
        uint16_t opt_offset = 0;
        uint8_t *buf = (uint8_t *)(rtr_sol + 1);
        /* check validity */
        if ((ipv6->hl != 255) || (rtr_sol->code != 0) ||
            (icmpv6_size < sizeof(ndp_rtr_sol_t))) {
            DEBUG("ndp: router solicitation was invalid\n");
            return;
        }
        sicmpv6_size -= sizeof(ndp_rtr_sol_t);
        while (sicmpv6_size > 0) {
            ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);

            switch (opt->type) {
                case NDP_OPT_SL2A:
                    if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_sol->type, opt,
                                                                       l2src)) < 0) {
                        /* -ENOTSUP can not happen */
                        /* invalid source link-layer address option */
                        return;
                    }
                    break;

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

            opt_offset += (opt->len * 8);
            sicmpv6_size -= (opt->len * 8);
        }
        _stale_nc(iface, &ipv6->src, l2src, l2src_len);
        /* send delayed */
        if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) {
            timex_t delay = timex_set(0, genrand_uint32_range(0, GNRC_NDP_MAX_RTR_ADV_DELAY));
            vtimer_remove(&if_entry->rtr_adv_timer);
            if (ipv6_addr_is_unspecified(&ipv6->src)) {
                /* either multicast, if source unspecified */
                vtimer_set_msg(&if_entry->rtr_adv_timer, delay, gnrc_ipv6_pid,
                               GNRC_NDP_MSG_RTR_ADV_RETRANS, if_entry);
            }
            else {
                /* or unicast, if source is known */
                /* XXX: can't just use GNRC_NETAPI_MSG_TYPE_SND, since the next retransmission
                 * must also be set. */
                gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
                vtimer_set_msg(&if_entry->rtr_adv_timer, delay, gnrc_ipv6_pid,
                               GNRC_NDP_MSG_RTR_ADV_DELAY, nc_entry);
            }
        }
    }
    /* otherwise ignore silently */
}