コード例 #1
0
ファイル: gnrc_ndp_internal.c プロジェクト: nlebang/RIOT
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
                                     ndp_opt_pi_t *pi_opt)
{
    ipv6_addr_t *prefix;
    gnrc_ipv6_netif_addr_t *netif_addr;

    if ((pi_opt->len != NDP_OPT_MTU_LEN)) {
        DEBUG("ndp: invalid MTU option received\n");
        return false;
    }
    if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) {
        /* else discard silently */
        return true;
    }
    prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix);
    if (((prefix == NULL) ||
         (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) &&
        (pi_opt->valid_ltime.u32 != 0)) {
        prefix = gnrc_ipv6_netif_add_addr(iface, &pi_opt->prefix,
                                          pi_opt->prefix_len,
                                          pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
        if (prefix == NULL) {
            DEBUG("ndp: could not add prefix to interface %d\n", iface);
            return false;
        }
    }
    netif_addr = gnrc_ipv6_netif_addr_get(prefix);
    if (pi_opt->valid_ltime.u32 == 0) {
        if (prefix != NULL) {
            gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr);
        }

        return true;
    }
    netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime);
    netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime);
    vtimer_remove(&netif_addr->valid_timeout);
    if (netif_addr->valid != UINT32_MAX) {
        vtimer_set_msg(&netif_addr->valid_timeout,
                       timex_set(byteorder_ntohl(pi_opt->valid_ltime), 0),
                       thread_getpid(), GNRC_NDP_MSG_ADDR_TIMEOUT, &netif_addr->addr);
    }
    /* TODO: preferred lifetime for address auto configuration */
    /* on-link flag MUST stay set if it was */
    netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A;
    netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
    return true;
}
コード例 #2
0
ファイル: tests-ipv6_addr.c プロジェクト: MtTsai/RIOT
static void test_ipv6_addr_set_solicited_nodes(void)
{
    ng_ipv6_addr_t a = NG_IPV6_ADDR_UNSPECIFIED;
    ng_ipv6_addr_t b = { {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
        }
    };

    ng_ipv6_addr_set_solicited_nodes(&a, &b);

    TEST_ASSERT_EQUAL_INT(0xff020000, byteorder_ntohl(a.u32[0]));
    TEST_ASSERT_EQUAL_INT(0, a.u32[1].u32);
    TEST_ASSERT_EQUAL_INT(1, byteorder_ntohl(a.u32[2]));
    TEST_ASSERT_EQUAL_INT(0xff0d0e0f, byteorder_ntohl(a.u32[3]));
}
コード例 #3
0
ファイル: sntp.c プロジェクト: deepfryed/RIOT
int sntp_sync(sock_udp_ep_t *server, uint32_t timeout)
{
    int result;

    mutex_lock(&_sntp_mutex);
    if ((result = sock_udp_create(&_sntp_sock,
                                  NULL,
                                  server,
                                  0)) < 0) {
        DEBUG("Error creating UDP sock\n");
        mutex_unlock(&_sntp_mutex);
        return result;
    }
    memset(&_sntp_packet, 0, sizeof(_sntp_packet));
    ntp_packet_set_vn(&_sntp_packet);
    ntp_packet_set_mode(&_sntp_packet, NTP_MODE_CLIENT);

    if ((result = (int)sock_udp_send(&_sntp_sock,
                                     &_sntp_packet,
                                     sizeof(_sntp_packet),
                                     NULL)) < 0) {
        DEBUG("Error sending message\n");
        sock_udp_close(&_sntp_sock);
        mutex_unlock(&_sntp_mutex);
        return result;
    }
    if ((result = (int)sock_udp_recv(&_sntp_sock,
                                     &_sntp_packet,
                                     sizeof(_sntp_packet),
                                     timeout,
                                     NULL)) < 0) {
        DEBUG("Error receiving message\n");
        sock_udp_close(&_sntp_sock);
        mutex_unlock(&_sntp_mutex);
        return result;
    }
    sock_udp_close(&_sntp_sock);
    _sntp_offset = (byteorder_ntohl(_sntp_packet.transmit.seconds) * US_PER_SEC) +
                   ((byteorder_ntohl(_sntp_packet.transmit.fraction) * 232)
                   / 1000000) - xtimer_now64();
    mutex_unlock(&_sntp_mutex);
    return 0;
}
コード例 #4
0
ファイル: tests-ipv6_addr.c プロジェクト: MtTsai/RIOT
static void test_ipv6_addr_set_all_routers_multicast_unusual(void)
{
    ng_ipv6_addr_t a;
    ng_ipv6_addr_mcast_scp_t scope = NG_IPV6_ADDR_MCAST_SCP_ORG_LOCAL;

    ng_ipv6_addr_set_all_routers_multicast(&a, scope);

    TEST_ASSERT_EQUAL_INT(0xff080000, byteorder_ntohl(a.u32[0]));
    TEST_ASSERT_EQUAL_INT(0, a.u32[1].u32);
    TEST_ASSERT_EQUAL_INT(2, byteorder_ntohll(a.u64[1]));
}
コード例 #5
0
ファイル: tests-ipv6_addr.c プロジェクト: MtTsai/RIOT
static void test_ipv6_addr_set_all_routers_multicast_site_local(void)
{
    ng_ipv6_addr_t a = NG_IPV6_ADDR_UNSPECIFIED;
    ng_ipv6_addr_t b = NG_IPV6_ADDR_ALL_ROUTERS_SITE_LOCAL;
    ng_ipv6_addr_mcast_scp_t scope = NG_IPV6_ADDR_MCAST_SCP_SITE_LOCAL;

    TEST_ASSERT_EQUAL_INT(0xff050000, byteorder_ntohl(b.u32[0])); /* Don't trust the macro ;) */
    TEST_ASSERT_EQUAL_INT(0, b.u32[1].u32);
    TEST_ASSERT_EQUAL_INT(2, byteorder_ntohll(b.u64[1]));

    ng_ipv6_addr_set_all_routers_multicast(&a, scope);

    TEST_ASSERT_EQUAL_INT(true, ng_ipv6_addr_equal(&a, &b));
}
コード例 #6
0
ファイル: tests-ipv6_addr.c プロジェクト: MtTsai/RIOT
static void test_ipv6_addr_set_all_nodes_multicast_link_local(void)
{
    ng_ipv6_addr_t a = NG_IPV6_ADDR_UNSPECIFIED;
    ng_ipv6_addr_t b = NG_IPV6_ADDR_ALL_NODES_LINK_LOCAL;
    ng_ipv6_addr_mcast_scp_t scope = NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL;

    TEST_ASSERT_EQUAL_INT(0xff020000, byteorder_ntohl(b.u32[0])); /* Don't trust the macro ;) */
    TEST_ASSERT_EQUAL_INT(0, b.u32[1].u32);
    TEST_ASSERT_EQUAL_INT(1, byteorder_ntohll(b.u64[1]));

    ng_ipv6_addr_set_all_nodes_multicast(&a, scope);

    TEST_ASSERT_EQUAL_INT(true, ng_ipv6_addr_equal(&a, &b));
}
コード例 #7
0
ファイル: gnrc_ndp_internal.c プロジェクト: khhhh/RIOT
bool gnrc_ndp_internal_mtu_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
                                      ndp_opt_mtu_t *mtu_opt)
{
    gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);

    if ((mtu_opt->len != NDP_OPT_MTU_LEN)) {
        DEBUG("ndp: invalid MTU option received\n");
        return false;
    }
    if (icmpv6_type != ICMPV6_RTR_ADV) {
        /* else discard silently */
        return true;
    }
    mutex_lock(&if_entry->mutex);
    if_entry->mtu = byteorder_ntohl(mtu_opt->mtu);
    mutex_unlock(&if_entry->mutex);
    return true;
}
コード例 #8
0
ファイル: rpl_control_messages.c プロジェクト: JiapengLi/RIOT
void rpl_recv_DIO(void)
{
    ipv6_buf = get_rpl_ipv6_buf();

    rpl_dio_buf = get_rpl_dio_buf();
    DEBUGF("instance %04X ", rpl_dio_buf->rpl_instanceid);
    DEBUGF("rank %04X\n", byteorder_ntohs(rpl_dio_buf->rank));
    int len = DIO_BASE_LEN;

    rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid);
    rpl_instance_t *my_inst = rpl_get_my_instance();

    if (dio_inst == NULL) {
        if (my_inst != NULL) {
            /* already part of a DODAG -> impossible to join other instance */
            DEBUGF("Not joining another DODAG!\n");
            return;
        }

        dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid);

        if (dio_inst == NULL) {
            DEBUGF("Failed to create a new RPL instance!\n");
            return;
        }
    }
    else if (my_inst == NULL) {
        DEBUGF("Not joined an instance yet\n");
    }
    else if (my_inst->id != dio_inst->id) {
        /* TODO: Add support support for several instances.  */

        /* At the moment, nodes can only join one instance, this is
        * the instance they join first.
        * Instances cannot be switched later on.  */

        DEBUGF("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id);
        return;
    }

    rpl_dodag_t dio_dodag;
    memset(&dio_dodag, 0, sizeof(dio_dodag));

    memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id));
    dio_dodag.dtsn = rpl_dio_buf->dtsn;
    dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK);
    dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT;
    dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK);
    dio_dodag.version = rpl_dio_buf->version_number;
    dio_dodag.instance = dio_inst;

    uint8_t has_dodag_conf_opt = 0;

    /* Parse until all options are consumed.
     * ipv6_buf->length contains the packet length minus ipv6 and
     * icmpv6 header, so only ICMPV6_HDR_LEN remains to be
     * subtracted.  */
    while (len < (NTOHS(ipv6_buf->length) - ICMPV6_HDR_LEN)) {
        DEBUGF("parsing DIO options\n");
        rpl_opt_buf = get_rpl_opt_buf(len);

        switch (rpl_opt_buf->type) {

            case (RPL_OPT_PAD1): {
                len += 1;
                break;
            }

            case (RPL_OPT_PADN): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_DAG_METRIC_CONTAINER): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_ROUTE_INFO): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_DODAG_CONF): {
                has_dodag_conf_opt = 1;

                if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) {
                    DEBUGF("DODAG configuration is malformed.\n");
                    /* error malformed */
                    return;
                }

                rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len);
                dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl;
                dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin;
                dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun;
                dio_dodag.maxrankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MaxRankIncrease);
                dio_dodag.minhoprankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MinHopRankIncrease);
                dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime;
                dio_dodag.lifetime_unit = byteorder_ntohs(rpl_opt_dodag_conf_buf->lifetime_unit);
                dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp));
                if (dio_dodag.of == NULL) {
                    DEBUGF("[Error] OCP from DIO is not supported! ocp: %x\n",
                    byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp));
                    return;
                }

                len += RPL_OPT_DODAG_CONF_LEN_WITH_OPT_LEN;
                break;
            }

            case (RPL_OPT_PREFIX_INFO): {
                if (rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) {
                    /* error malformed */
                    return;
                }

                rpl_opt_prefix_information_buf = get_rpl_opt_prefix_information_buf(len);

                /* autonomous address-configuration flag */
                if (rpl_opt_prefix_information_buf->flags & (1 << 6)) {
                    ipv6_addr_t tmp;
                    tmp = rpl_opt_prefix_information_buf->prefix;
                    if (!ipv6_addr_is_link_local(&tmp)) {
                        if (byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime)
                                <= byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime)) {
                            ipv6_addr_set_by_eui64(&tmp, rpl_if_id, &tmp);
                            ipv6_net_if_add_addr(rpl_if_id, &tmp,
                                    NDP_ADDR_STATE_PREFERRED,
                                    byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime),
                                    byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime),
                                    0);
                            dio_dodag.prefix = rpl_opt_prefix_information_buf->prefix;
                            dio_dodag.prefix_length = rpl_opt_prefix_information_buf->prefix_length;
                            dio_dodag.prefix_valid_lifetime =
                                byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime);
                            dio_dodag.prefix_preferred_lifetime =
                                byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime);
                            dio_dodag.prefix_flags = rpl_opt_prefix_information_buf->flags;
                        }
                    }
                }

                len += RPL_OPT_PREFIX_INFO_LEN_WITH_OPT_LEN;
                break;
            }

            default:
                DEBUGF("[Error] Unsupported DIO option\n");
                return;
        }
    }

    /* handle packet content... */
    rpl_dodag_t *my_dodag = rpl_get_joined_dodag(dio_inst->id);

    if (my_dodag == NULL) {
        if (!has_dodag_conf_opt) {
            DEBUGF("send DIS\n");
            rpl_send_DIS(&ipv6_buf->srcaddr);
        }

        if (byteorder_ntohs(rpl_dio_buf->rank) < ROOT_RANK) {
            DEBUGF("DIO with Rank < ROOT_RANK\n");
        }

        if (dio_dodag.mop != RPL_DEFAULT_MOP) {
            DEBUGF("Required MOP not supported\n");
        }

        if (dio_dodag.of == NULL) {
            DEBUGF("Required objective function not supported\n");
        }

        if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) {
            DEBUGF("Will join DODAG\n");
            rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));
        }
        else {
            DEBUGF("Cannot access DODAG because of DIO with infinite rank\n");
        }

        return;
    }

    if (rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) {
        /* "our" DODAG */
        if (RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) {
            if (my_dodag->my_rank == ROOT_RANK) {
                DEBUGF("[Warning] Inconsistent Dodag Version\n");
                my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
                trickle_reset_timer(&my_dodag->trickle);
            }
            else {
                DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
                my_dodag->version = dio_dodag.version;
                rpl_global_repair(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));
            }

            return;
        }
        else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
            /* lower version number detected -> send more DIOs */
            trickle_reset_timer(&my_dodag->trickle);
            return;
        }
    }

    /* version matches, DODAG matches */
    if (byteorder_ntohs(rpl_dio_buf->rank) == INFINITE_RANK) {
        trickle_reset_timer(&my_dodag->trickle);
    }

    /* We are root, all done!*/
    if (my_dodag->my_rank == ROOT_RANK) {
        if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) {
            trickle_increment_counter(&my_dodag->trickle);
        }

        return;
    }

    /*********************  Parent Handling *********************/

    rpl_parent_t *parent;
    parent = rpl_find_parent(my_dodag, &ipv6_buf->srcaddr);

    if (parent == NULL) {
        /* add new parent candidate */
        parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));

        if (parent == NULL) {
            return;
        }
    }
    else {
        /* DIO OK */
        trickle_increment_counter(&my_dodag->trickle);
    }

    /* update parent rank */
    parent->rank = byteorder_ntohs(rpl_dio_buf->rank);
    rpl_parent_update(my_dodag, parent);

    if (my_dodag->my_preferred_parent == NULL) {
        DEBUGF("My dodag has no preferred_parent yet - seems to be odd since I have a parent...\n");
    }
    else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
             (parent->dtsn != rpl_dio_buf->dtsn)) {
        rpl_delay_dao(my_dodag);
    }

    parent->dtsn = rpl_dio_buf->dtsn;

}
コード例 #9
0
ファイル: gnrc_ndp_internal.c プロジェクト: khhhh/RIOT
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type,
                                     ndp_opt_pi_t *pi_opt)
{
    ipv6_addr_t *prefix;
    gnrc_ipv6_netif_addr_t *netif_addr;

    if ((pi_opt->len != NDP_OPT_PI_LEN)) {
        DEBUG("ndp: invalid PI option received\n");
        return false;
    }
    if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) {
        /* else discard silently */
        return true;
    }
#ifdef MODULE_GNRC_SIXLOWPAN_ND
    if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
        (pi_opt->flags & NDP_OPT_PI_FLAGS_L)) {
        /* ignore: see https://tools.ietf.org/html/rfc6775#section-5.4 */
        return true;
    }
#endif
    prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix);
    if (((prefix == NULL) ||
         (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) &&
        (pi_opt->valid_ltime.u32 != 0)) {
        ipv6_addr_t pref_addr;

        if ((gnrc_netapi_get(iface, NETOPT_IPV6_IID, 0, &pref_addr.u64[1],
                             sizeof(eui64_t)) < 0)) {
            DEBUG("ndp: could not get IID from interface %d\n", iface);
            return false;
        }
        ipv6_addr_init_prefix(&pref_addr, &pi_opt->prefix, pi_opt->prefix_len);
        prefix = gnrc_ipv6_netif_add_addr(iface, &pref_addr,
                                          pi_opt->prefix_len,
                                          pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
        if (prefix == NULL) {
            DEBUG("ndp: could not add prefix to interface %d\n", iface);
            return false;
        }
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
        gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_get(iface), true);
#endif
    }
    netif_addr = gnrc_ipv6_netif_addr_get(prefix);
    if (pi_opt->valid_ltime.u32 == 0) {
        if (prefix != NULL) {
            gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr);
        }

        return true;
    }
    netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime);
    netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime);
    if (netif_addr->valid != UINT32_MAX) {
        xtimer_set_msg(&netif_addr->valid_timeout,
                       (byteorder_ntohl(pi_opt->valid_ltime) * SEC_IN_USEC),
                       &netif_addr->valid_timeout_msg, thread_getpid());
    }
    /* TODO: preferred lifetime for address auto configuration */
    /* on-link flag MUST stay set if it was */
    netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A;
    netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK);
    return true;
}
コード例 #10
0
ファイル: gnrc_ndp.c プロジェクト: Otmane123/RIOT
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);
        }
    }
コード例 #11
0
ファイル: gnrc_tcp_fsm.c プロジェクト: A-Paul/RIOT
/**
 * @brief FSM handling function for processing of an incomming TCP packet.
 *
 * @param[in,out] tcb      TCB holding the connection information.
 * @param[in]     in_pkt   Incomming packet.
 *
 * @returns   Zero on success.
 *            -ENOMEM if receive buffer could not be allocated.
 */
static int _fsm_rcvd_pkt(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *in_pkt)
{
    gnrc_pktsnip_t *out_pkt = NULL;  /* Outgoing packet */
    uint16_t seq_con = 0;            /* Sequence number consumption of outgoing packet */
    gnrc_pktsnip_t *snp = NULL;      /* Temporary packet snip */
    gnrc_tcp_tcb_t *lst = NULL;      /* Temporary pointer to TCB */
    uint16_t ctl = 0;                /* Control bits of the incomming packet */
    uint32_t seg_seq = 0;            /* Sequence number of the incomming packet*/
    uint32_t seg_ack = 0;            /* Acknowledgment number of the incomming packet */
    uint32_t seg_wnd = 0;            /* Receive window of the incomming packet */
    uint32_t seg_len = 0;            /* Segment length of the incomming packet */
    uint32_t pay_len = 0;            /* Payload length of the incomming packet */

    DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt()\n");
    /* Search for TCP header. */
    LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_TCP);
    tcp_hdr_t *tcp_hdr = (tcp_hdr_t *) snp->data;

    /* Parse packet options, return if they are malformed */
    if (_option_parse(tcb, tcp_hdr) < 0) {
        return 0;
    }

    /* Extract header values */
    ctl = byteorder_ntohs(tcp_hdr->off_ctl);
    seg_seq = byteorder_ntohl(tcp_hdr->seq_num);
    seg_ack = byteorder_ntohl(tcp_hdr->ack_num);
    seg_wnd = byteorder_ntohs(tcp_hdr->window);

    /* Extract network layer header */
#ifdef MODULE_GNRC_IPV6
    LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_IPV6);
    if (snp == NULL) {
        DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : incomming packet had no IPv6 header\n");
        return 0;
    }
    void *ip = snp->data;
#endif

    /* Handle state LISTEN */
    if (tcb->state == FSM_STATE_LISTEN) {
        /* 1) Check RST: if RST is set: return */
        if (ctl & MSK_RST) {
            return 0;
        }
        /* 2) Check ACK: if ACK is set: send RST with seq_no = ack_no and return */
        if (ctl & MSK_ACK) {
            _pkt_build_reset_from_pkt(&out_pkt, in_pkt);
            _pkt_send(tcb, out_pkt, 0, false);
            return 0;
        }
        /* 3) Check SYN: if SYN is set prepare for incomming connection */
        if (ctl & MSK_SYN) {
            uint16_t src = byteorder_ntohs(tcp_hdr->src_port);
            uint16_t dst = byteorder_ntohs(tcp_hdr->dst_port);

            /* Check if SYN request is handled by another connection */
            lst = _list_tcb_head;
            while (lst) {
                /* Compare port numbers and network layer adresses */
                if (lst->local_port == dst && lst->peer_port == src) {
#ifdef MODULE_GNRC_IPV6
                    if (snp->type == GNRC_NETTYPE_IPV6 && lst->address_family == AF_INET6) {
                        ipv6_addr_t *dst_addr = &((ipv6_hdr_t *)ip)->dst;
                        ipv6_addr_t *src_addr = &((ipv6_hdr_t *)ip)->src;

                        if (ipv6_addr_equal((ipv6_addr_t *)lst->local_addr, dst_addr) &&
                            ipv6_addr_equal((ipv6_addr_t *)lst->peer_addr, src_addr)) {
                            break;
                        }
                    }
#endif
                }
                lst = lst->next;
            }
            /* Return if connection is already handled (port and addresses match) */
            if (lst != NULL) {
                DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : Connection already handled\n");
                return 0;
            }

            /* SYN request is valid, fill TCB with connection information */
#ifdef MODULE_GNRC_IPV6
            if (snp->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) {
                memcpy(tcb->local_addr, &((ipv6_hdr_t *)ip)->dst, sizeof(ipv6_addr_t));
                memcpy(tcb->peer_addr, &((ipv6_hdr_t *)ip)->src, sizeof(ipv6_addr_t));

                /* In case peer_addr is link local: Store interface Id in tcb */
                if (ipv6_addr_is_link_local((ipv6_addr_t *) tcb->peer_addr)) {
                    gnrc_pktsnip_t *tmp = NULL;
                    LL_SEARCH_SCALAR(in_pkt, tmp, type, GNRC_NETTYPE_NETIF);
                    /* cppcheck-suppress knownConditionTrueFalse
                     * (reason: tmp *can* be != NULL after LL_SEARCH_SCALAR) */
                    if (tmp == NULL) {
                        DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() :\
                               incomming packet had no netif header\n");
                        return 0;
                    }
                    tcb->ll_iface = ((gnrc_netif_hdr_t *)tmp->data)->if_pid;
                }