Beispiel #1
0
void gnrc_rpl_p2p_rdo_parse(gnrc_rpl_p2p_opt_rdo_t *rdo, gnrc_rpl_p2p_ext_t *p2p_ext)
{
    DEBUG("RPL: Route Discovery DIO option parsed\n");

    uint8_t addr_num = (rdo->length - GNRC_RPL_P2P_RDO_LEN)
                        / (sizeof(ipv6_addr_t) - p2p_ext->compr);
    if (addr_num >= GNRC_RPL_P2P_ADDR_VEC_NUMOF) {
        DEBUG("RPL: cannot parse RDO - too many hops\n");
        return;
    }

    p2p_ext->for_me = (gnrc_ipv6_netif_find_by_addr(NULL, &rdo->target) != KERNEL_PID_UNDEF);

    p2p_ext->reply = (rdo->compr_flags & (1 << GNRC_RPL_P2P_RDO_FLAGS_REPLY))
                      >> GNRC_RPL_P2P_RDO_FLAGS_REPLY;
    p2p_ext->hop_by_hop = (rdo->compr_flags & (1 << GNRC_RPL_P2P_RDO_FLAGS_HBH))
                           >> GNRC_RPL_P2P_RDO_FLAGS_HBH;
    p2p_ext->routes_numof = (rdo->compr_flags & (0x3 << GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM))
                             >> GNRC_RPL_P2P_RDO_FLAGS_ADDRNUM;
    p2p_ext->compr = rdo->compr_flags & GNRC_RPL_P2P_RDO_FLAGS_COMPR;
    p2p_ext->lifetime_enc = (rdo->lmn & (0x3 << GNRC_RPL_P2P_RDO_FLAGS_LIFETIME))
                             >> GNRC_RPL_P2P_RDO_FLAGS_LIFETIME;
    if (p2p_ext->lifetime_sec == INT8_MIN) {
        p2p_ext->lifetime_sec = gnrc_rpl_p2p_lifetime_lookup[p2p_ext->lifetime_enc];
    }
    p2p_ext->maxrank = rdo->lmn & GNRC_RPL_P2P_RDO_FLAGS_MAXRANK;
    p2p_ext->target = rdo->target;

    memset(&p2p_ext->addr_vec, 0, sizeof(ipv6_addr_t) * GNRC_RPL_P2P_ADDR_VEC_NUMOF);
    p2p_ext->addr_numof = 0;
    uint8_t *tmp = (uint8_t *) (rdo + 1);
    uint8_t *addr = NULL;
    uint8_t addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr;
    uint8_t i = 0;
    for (i = 0; i < addr_num; i++) {
        addr = ((uint8_t *) &p2p_ext->addr_vec[i]) + p2p_ext->compr;
        memcpy(addr, tmp, addr_len);
        tmp += addr_len;
        p2p_ext->addr_numof++;
    }

    if (!p2p_ext->for_me) {
        ipv6_addr_t *me = NULL;
        if(gnrc_ipv6_netif_find_by_prefix(&me, &p2p_ext->dodag->dodag_id) == KERNEL_PID_UNDEF) {
            DEBUG("RPL: no address configured\n");
            return;
        }
        addr = ((uint8_t *) &p2p_ext->addr_vec[i]) + p2p_ext->compr;
        memcpy(addr, ((uint8_t *) me) + p2p_ext->compr, addr_len);
        p2p_ext->addr_numof++;
    }
    else if (p2p_ext->reply) {
        p2p_ext->stop = true;
        p2p_ext->dro_ack = true;
        p2p_ext->dro_delay = GNRC_RPL_P2P_DRO_DELAY;
    }
}
Beispiel #2
0
static gnrc_rpl_dodag_t *_root_dodag_init(uint8_t instance_id, ipv6_addr_t *dodag_id, uint8_t mop)
{
    if (gnrc_rpl_pid == KERNEL_PID_UNDEF) {
        DEBUG("RPL: RPL thread not started\n");
        return NULL;
    }

    ipv6_addr_t *configured_addr;
    gnrc_ipv6_netif_addr_t *netif_addr = NULL;
    gnrc_rpl_instance_t *inst = NULL;
    gnrc_rpl_dodag_t *dodag = NULL;

    if (instance_id == 0) {
        DEBUG("RPL: instance id (%d) must be a positive number greater than zero\n", instance_id);
        return NULL;
    }

    if (gnrc_ipv6_netif_find_by_addr(&configured_addr, dodag_id) == KERNEL_PID_UNDEF) {
        DEBUG("RPL: no IPv6 address configured to match the given dodag id: %s\n",
              ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
        return NULL;
    }

    if ((netif_addr = gnrc_ipv6_netif_addr_get(configured_addr)) == NULL) {
        DEBUG("RPL: no netif address found for %s\n", ipv6_addr_to_str(addr_str, configured_addr,
                sizeof(addr_str)));
        return NULL;
    }

    if (gnrc_rpl_instance_add(instance_id, &inst)) {
        inst->of = (gnrc_rpl_of_t *) gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);
        inst->mop = mop;
        inst->min_hop_rank_inc = GNRC_RPL_DEFAULT_MIN_HOP_RANK_INCREASE;
        inst->max_rank_inc = GNRC_RPL_DEFAULT_MAX_RANK_INCREASE;
    }
    else if (inst == NULL) {
        DEBUG("RPL: could not allocate memory for a new instance with id %d", instance_id);
        return NULL;
    }
    else if (inst->mop != mop) {
        DEBUG("RPL: instance (%d) exists with another MOP", instance_id);
        return NULL;
    }

    if (!gnrc_rpl_dodag_add(inst, dodag_id, &dodag)) {
        DEBUG("RPL: DODAG with id %s exists or no memory left for a new DODAG",
                ipv6_addr_to_str(addr_str, dodag_id, sizeof(addr_str)));
        return NULL;
    }

    dodag->prefix_len = netif_addr->prefix_len;
    dodag->addr_preferred = netif_addr->preferred;
    dodag->addr_valid = netif_addr->valid;

    return dodag;
}
Beispiel #3
0
void *_udp_server(void *args)
{
    uint16_t port = (uint16_t) atoi(args);
    ipv6_addr_t server_addr = IPV6_ADDR_UNSPECIFIED;
    msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);

    if(conn_udp_create(&conn, &server_addr, sizeof(server_addr), AF_INET6, port) < 0) {
        return NULL;
    }

    server_running = true;
    printf("Success: started UDP server on port %" PRIu16 "\n", port);

    char *arg[4];
    char *cmd = "udp_send";
    char *port_str = "8888";

    arg[0] = cmd;
    arg[2] = port_str;
    char src_str[IPV6_ADDR_MAX_STR_LEN];

    while (1) {
        int res;
        ipv6_addr_t src;
        size_t src_len = sizeof(ipv6_addr_t);
        if ((res = conn_udp_recvfrom(&conn, server_buffer, sizeof(server_buffer),
                                     &src, &src_len, &port)) < 0) {
            puts("Error while receiving");
        }
        else if (res == 0) {
            puts("No data received");
        }
        else {
            server_buffer[res] = '\0';
            if (gnrc_rpl_instances[0].state && gnrc_rpl_instances[0].dodag.node_status == GNRC_RPL_ROOT_NODE) {
                printf("%s;%s\n", ipv6_addr_to_str(src_str, &src, sizeof(src_str)),
                                                   server_buffer);
                ipv6_addr_to_str(addr_str, &ipv6_addr_all_nodes_link_local, sizeof(addr_str));
                arg[1] = addr_str;
                arg[3] = src_str;
                udp_send(4, arg);
            }
            else {
                ipv6_addr_t payload;
                ipv6_addr_from_str(&payload, server_buffer);
                if ((gnrc_ipv6_netif_find_by_addr(NULL, &payload) != KERNEL_PID_UNDEF) && (!acked)) {
                    acked = true;
                    printf("diff: %llu\n", xtimer_now64() - time);
                }
            }
        }
    }

    return NULL;
}
Beispiel #4
0
/* functions for receiving */
static inline bool _pkt_not_for_me(kernel_pid_t *iface, ipv6_hdr_t *hdr)
{
    if (ipv6_addr_is_loopback(&hdr->dst)) {
        return false;
    }
    else if (*iface == KERNEL_PID_UNDEF) {
        *iface = gnrc_ipv6_netif_find_by_addr(NULL, &hdr->dst);
        return (*iface == KERNEL_PID_UNDEF);
    }
    else {
        return (gnrc_ipv6_netif_find_addr(*iface, &hdr->dst) == NULL);
    }
}
void _gnrc_rpl_send(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst,
        ipv6_addr_t *dodag_id)
{
    gnrc_pktsnip_t *hdr;
    ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR, ll_addr;
    kernel_pid_t iface = gnrc_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
    if (iface == KERNEL_PID_UNDEF) {
        DEBUG("RPL: no suitable interface found for this destination address\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    if (src == NULL) {
        ipv6_addr_t *tmp = NULL;
        if (dodag_id != NULL) {
            tmp = gnrc_ipv6_netif_match_prefix(iface, dodag_id);
        }
        else if (dodag_id == NULL) {
            tmp = gnrc_ipv6_netif_find_best_src_addr(iface, &all_RPL_nodes);
        }

        if (tmp == NULL) {
            DEBUG("RPL: no suitable src address found\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        memcpy(&ll_addr, tmp, sizeof(ll_addr));
        ipv6_addr_set_link_local_prefix(&ll_addr);
        src = &ll_addr;
    }

    if (dst == NULL) {
        dst = &all_RPL_nodes;
    }

    hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)src, sizeof(ipv6_addr_t), (uint8_t *)dst,
                            sizeof(ipv6_addr_t));

    if (hdr == NULL) {
        DEBUG("RPL: Send - no space left in packet buffer\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL,hdr)) {
        DEBUG("RPL: cannot send packet: no subscribers found.\n");
        gnrc_pktbuf_release(hdr);
    }

}
Beispiel #6
0
bool gnrc_conn6_set_local_addr(uint8_t *conn_addr, const ipv6_addr_t *addr)
{
    ipv6_addr_t *tmp;
    if (!ipv6_addr_is_unspecified(addr) &&
        !ipv6_addr_is_loopback(addr) &&
        gnrc_ipv6_netif_find_by_addr(&tmp, addr) == KERNEL_PID_UNDEF) {
        return false;
    }
    else if (ipv6_addr_is_loopback(addr) || ipv6_addr_is_unspecified(addr)) {
        ipv6_addr_set_unspecified((ipv6_addr_t *)conn_addr);
    }
    else {
        memcpy(conn_addr, addr, sizeof(ipv6_addr_t));
    }
    return true;
}
void gnrc_rpl_send(gnrc_pktsnip_t *pkt, kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst,
                   ipv6_addr_t *dodag_id)
{
    (void)dodag_id;
    gnrc_pktsnip_t *hdr;
    if (iface == KERNEL_PID_UNDEF) {
        if ((iface = gnrc_ipv6_netif_find_by_addr(NULL, &ipv6_addr_all_rpl_nodes))
            == KERNEL_PID_UNDEF) {
            DEBUG("RPL: no suitable interface found for this destination address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    if (src == NULL) {
        src = gnrc_ipv6_netif_match_prefix(iface, &ipv6_addr_link_local_prefix);

        if (src == NULL) {
            DEBUG("RPL: no suitable src address found\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    if (dst == NULL) {
        dst = (ipv6_addr_t *) &ipv6_addr_all_rpl_nodes;
    }

    hdr = gnrc_ipv6_hdr_build(pkt, src, dst);

    if (hdr == NULL) {
        DEBUG("RPL: Send - no space left in packet buffer\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    pkt = hdr;

    hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
    ((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface;
    LL_PREPEND(pkt, hdr);

    if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
        DEBUG("RPL: cannot send packet: no subscribers found.\n");
        gnrc_pktbuf_release(pkt);
    }
}
Beispiel #8
0
/* functions for receiving */
static inline bool _pkt_not_for_me(kernel_pid_t *iface, ipv6_hdr_t *hdr)
{
    if (ipv6_addr_is_loopback(&hdr->dst)) {
        return false;
    }
    else if ((!ipv6_addr_is_link_local(&hdr->dst)) ||
             (*iface == KERNEL_PID_UNDEF)) {
        kernel_pid_t if_pid = gnrc_ipv6_netif_find_by_addr(NULL, &hdr->dst);
        if (*iface == KERNEL_PID_UNDEF) {
            *iface = if_pid;    /* Use original interface for reply if
                                 * existent */
        }
        return (if_pid == KERNEL_PID_UNDEF);
    }
    else {
        return (gnrc_ipv6_netif_find_addr(*iface, &hdr->dst) == NULL);
    }
}
Beispiel #9
0
static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *payload;
    ipv6_addr_t *tmp;
    ipv6_hdr_t *hdr;
    /* get IPv6 snip and (if present) generic interface header */
    if (pkt->type == GNRC_NETTYPE_NETIF) {
        /* If there is already a netif header (routing protocols and
         * neighbor discovery might add them to preset sending interface) */
        iface = ((gnrc_netif_hdr_t *)pkt->data)->if_pid;
        /* seize payload as temporary variable */
        ipv6 = gnrc_pktbuf_start_write(pkt); /* write protect for later removal
                                              * in _send_unicast() */
        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to netif header, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
        pkt = ipv6;  /* Reset pkt from temporary variable */

        ipv6 = pkt->next;
    }
    else {
        ipv6 = pkt;
    }
    /* seize payload as temporary variable */
    payload = gnrc_pktbuf_start_write(ipv6);
    if (payload == NULL) {
        DEBUG("ipv6: unable to get write access to IPv6 header, dropping packet\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
    if (ipv6 != pkt) {      /* in case packet has netif header */
        pkt->next = payload;/* pkt is already write-protected so we can do that */
    }
    else {
        pkt = payload;      /* pkt is the IPv6 header so we just write-protected it */
    }
    ipv6 = payload;  /* Reset ipv6 from temporary variable */

    hdr = ipv6->data;
    payload = ipv6->next;

    if (ipv6_addr_is_multicast(&hdr->dst)) {
        _send_multicast(iface, pkt, ipv6, payload, prep_hdr);
    }
    else if ((ipv6_addr_is_loopback(&hdr->dst)) ||      /* dst is loopback address */
             ((iface == KERNEL_PID_UNDEF) && /* or dst registered to any local interface */
              ((iface = gnrc_ipv6_netif_find_by_addr(&tmp, &hdr->dst)) != KERNEL_PID_UNDEF)) ||
             ((iface != KERNEL_PID_UNDEF) && /* or dst registered to given interface */
              (gnrc_ipv6_netif_find_addr(iface, &hdr->dst) != NULL))) {
        uint8_t *rcv_data;
        gnrc_pktsnip_t *ptr = ipv6, *rcv_pkt;

        if (prep_hdr) {
            if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
                /* error on filling up header */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        rcv_pkt = gnrc_pktbuf_add(NULL, NULL, gnrc_pkt_len(ipv6), GNRC_NETTYPE_IPV6);

        if (rcv_pkt == NULL) {
            DEBUG("ipv6: error on generating loopback packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        rcv_data = rcv_pkt->data;

        /* "reverse" packet (by making it one snip as if received from NIC) */
        while (ptr != NULL) {
            memcpy(rcv_data, ptr->data, ptr->size);
            rcv_data += ptr->size;
            ptr = ptr->next;
        }

        gnrc_pktbuf_release(pkt);

        DEBUG("ipv6: packet is addressed to myself => loopback\n");

        if (gnrc_netapi_receive(gnrc_ipv6_pid, rcv_pkt) < 1) {
            DEBUG("ipv6: unable to deliver packet\n");
            gnrc_pktbuf_release(rcv_pkt);
        }
    }
    else {
        uint8_t l2addr_len = GNRC_IPV6_NC_L2_ADDR_MAX;
        uint8_t l2addr[l2addr_len];

        iface = _next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst, pkt);

        if (iface == KERNEL_PID_UNDEF) {
            DEBUG("ipv6: error determining next hop's link layer address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        if (prep_hdr) {
            if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
                /* error on filling up header */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        _send_unicast(iface, l2addr, l2addr_len, pkt);
    }
}
static inline bool _is_me(ipv6_addr_t *addr)
{
    ipv6_addr_t *res;

    return (gnrc_ipv6_netif_find_by_addr(&res, addr) != KERNEL_PID_UNDEF);
}
/** @todo allow target prefixes in target options to be of variable length */
bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, uint16_t len,
                    ipv6_addr_t *src)
{
    uint16_t l = 0;
    gnrc_rpl_opt_target_t *first_target = NULL;
    eui64_t iid;
    kernel_pid_t if_id = KERNEL_PID_UNDEF;

    if (!_gnrc_rpl_check_options_validity(msg_type, dodag, opt, len)) {
        return false;
    }

    while(l < len) {
        switch(opt->type) {
            case (GNRC_RPL_OPT_PAD1):
                DEBUG("RPL: PAD1 option parsed\n");
                l += 1;
                opt = (gnrc_rpl_opt_t *) (((uint8_t *) opt) + 1);
                continue;

            case (GNRC_RPL_OPT_PADN):
                DEBUG("RPL: PADN option parsed\n");
                break;

            case (GNRC_RPL_OPT_DODAG_CONF):
                DEBUG("RPL: DODAG CONF DIO option parsed\n");
                gnrc_rpl_opt_dodag_conf_t *dc = (gnrc_rpl_opt_dodag_conf_t *) opt;
                gnrc_rpl_of_t *of = gnrc_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp));
                if (of != NULL) {
                    dodag->instance->of = of;
                }
                else {
                    DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp));
                    dodag->instance->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);
                }
                dodag->dio_interval_doubl = dc->dio_int_doubl;
                dodag->dio_min = dc->dio_int_min;
                dodag->dio_redun = dc->dio_redun;
                dodag->instance->max_rank_inc = byteorder_ntohs(dc->max_rank_inc);
                dodag->instance->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc);
                dodag->default_lifetime = dc->default_lifetime;
                dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit);
                dodag->trickle.Imin = (1 << dodag->dio_min);
                dodag->trickle.Imax = dodag->dio_interval_doubl;
                dodag->trickle.k = dodag->dio_redun;
                break;

            case (GNRC_RPL_OPT_PREFIX_INFO):
                DEBUG("RPL: Prefix Information DIO option parsed\n");
                gnrc_rpl_opt_prefix_info_t *pi = (gnrc_rpl_opt_prefix_info_t *) opt;
                ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR;
                if_id = gnrc_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
                /* check for the auto address-configuration flag */
                if ((gnrc_netapi_get(if_id, NETOPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) < 0) &&
                        !(pi->LAR_flags & GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT)) {
                    break;
                }
                ipv6_addr_set_aiid(&pi->prefix, iid.uint8);
                gnrc_ipv6_netif_add_addr(if_id, &pi->prefix, pi->prefix_len, 0);

                break;

            case (GNRC_RPL_OPT_TARGET):
                DEBUG("RPL: RPL TARGET DAO option parsed\n");
                if_id = gnrc_ipv6_netif_find_by_prefix(NULL, &dodag->dodag_id);
                if (if_id == KERNEL_PID_UNDEF) {
                    DEBUG("RPL: no interface found for the configured DODAG id\n");
                    return false;
                }

                gnrc_rpl_opt_target_t *target = (gnrc_rpl_opt_target_t *) opt;
                if (first_target == NULL) {
                    first_target = target;
                }

                fib_add_entry(gnrc_ipv6_fib_table, if_id, target->target.u8,
                              sizeof(ipv6_addr_t), AF_INET6, src->u8,
                              sizeof(ipv6_addr_t), AF_INET6,
                              (dodag->default_lifetime * dodag->lifetime_unit) *
                              SEC_IN_MS);
                break;

            case (GNRC_RPL_OPT_TRANSIT):
                DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
                gnrc_rpl_opt_transit_t *transit = (gnrc_rpl_opt_transit_t *) opt;
                if (first_target == NULL) {
                    DEBUG("RPL: Encountered a RPL TRANSIT DAO option without \
a preceding RPL TARGET DAO option\n");
                    break;
                }

                do {
                    fib_update_entry(gnrc_ipv6_fib_table, first_target->target.u8,
                                     sizeof(ipv6_addr_t), src->u8,
                                     sizeof(ipv6_addr_t), AF_INET6,
                            (transit->path_lifetime * dodag->lifetime_unit * SEC_IN_MS));
                    first_target = (gnrc_rpl_opt_target_t *) (((uint8_t *) (first_target)) +
                        sizeof(gnrc_rpl_opt_t) + first_target->length);
                }
                while (first_target->type == GNRC_RPL_OPT_TARGET);

                first_target = NULL;
                break;

        }
        l += opt->length + sizeof(gnrc_rpl_opt_t);
        opt = (gnrc_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length);
    }
Beispiel #12
0
void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src)
{
    gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_mark(pkt, sizeof(icmpv6_hdr_t), GNRC_NETTYPE_ICMPV6);
    gnrc_pktsnip_t *dro_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_dro_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *rdo_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_opt_rdo_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *addr_snip = pkt;
    gnrc_rpl_instance_t *inst;
    gnrc_rpl_dodag_t *dodag;
    gnrc_rpl_p2p_ext_t *p2p_ext;
    gnrc_rpl_p2p_dro_t *dro;
    gnrc_rpl_p2p_opt_rdo_t *rdo;
    uint8_t *addr_vec;
    uint16_t flags;
    size_t addr_len;

    if (!rdo_snip || !dro_snip) {
        DEBUG("RPL-P2P: Error - No DRO or RDO received\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    dro = dro_snip->data;

    if ((inst = gnrc_rpl_instance_get(dro->instance_id)) == NULL) {
        DEBUG("RPL-P2P: Error - Instance (%d) does not exist\n", dro->instance_id);
        return;
    }

    dodag = &inst->dodag;

    if ((p2p_ext = gnrc_rpl_p2p_ext_get(dodag)) == NULL) {
        DEBUG("RPL-P2P: Error - No P2P-RPL DODAG extension found\n");
        return;
    }

    if (p2p_ext->for_me) {
        DEBUG("RPL-P2P: Ignore DRO\n");
        return;
    }

    flags = byteorder_ntohs(dro->flags_rev);
    p2p_ext->stop = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_STOP)) >> GNRC_RPL_P2P_DRO_FLAGS_STOP;
    p2p_ext->dro_ack = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_ACK)) >> GNRC_RPL_P2P_DRO_FLAGS_ACK;
    p2p_ext->dro_seq = (flags & (0x3 << GNRC_RPL_P2P_DRO_FLAGS_SEQ)) >> GNRC_RPL_P2P_DRO_FLAGS_SEQ;

    addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr;
    ipv6_addr_t addr = p2p_ext->dodag->dodag_id;
    ipv6_addr_t *me = NULL;
    addr_vec = addr_snip->data;

    rdo = rdo_snip->data;

    if (rdo->lmn > 0) {
        rdo->lmn--;
        memcpy(&addr.u8[p2p_ext->compr], &addr_vec[addr_len * rdo->lmn], addr_len);
    }

    if (gnrc_ipv6_netif_find_by_addr(&me, &addr) == dodag->iface) {
        gnrc_ipv6_nib_ft_add(&p2p_ext->target, IPV6_ADDR_BIT_LEN, src, dodag->iface,
                             p2p_ext->dodag->default_lifetime *
                             p2p_ext->dodag->lifetime_unit);

        if (p2p_ext->dodag->node_status != GNRC_RPL_ROOT_NODE) {
            if ((rdo_snip = gnrc_pktbuf_start_write(rdo_snip)) == NULL) {
                DEBUG("RPL-P2P: Error - Cannot allocate new RDO\n");
                return;
            }

            addr_snip->next = NULL;
            rdo_snip->next = addr_snip;
            dro_snip->next = rdo_snip;

            icmpv6_snip = gnrc_icmpv6_build(dro_snip, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO,
                                            sizeof(icmpv6_hdr_t));
            if (icmpv6_snip == NULL) {
                DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n");
                gnrc_pktbuf_release(pkt);
                return;
            }

            gnrc_rpl_send(icmpv6_snip, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id);
            return;
        }
    }

    gnrc_pktbuf_release(pkt);

    return;
}
void gnrc_rpl_recv_DIO(gnrc_rpl_dio_t *dio, kernel_pid_t iface, ipv6_addr_t *src, uint16_t len)
{
    gnrc_rpl_instance_t *inst = NULL;
    gnrc_rpl_dodag_t *dodag = NULL;

    if (!_gnrc_rpl_check_DIO_validity(dio, len)) {
        return;
    }

    len -= (sizeof(gnrc_rpl_dio_t) + sizeof(icmpv6_hdr_t));

    if (gnrc_rpl_instance_add(dio->instance_id, &inst)) {
        /* new instance and DODAG */

        if (byteorder_ntohs(dio->rank) == GNRC_RPL_INFINITE_RANK) {
            DEBUG("RPL: ignore INFINITE_RANK DIO when we are not yet part of this DODAG\n");
            gnrc_rpl_instance_remove(inst);
            return;
        }

        inst->mop = (dio->g_mop_prf >> GNRC_RPL_MOP_SHIFT) & GNRC_RPL_SHIFTED_MOP_MASK;
        inst->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);

        if (iface == KERNEL_PID_UNDEF) {
            iface = gnrc_ipv6_netif_find_by_addr(NULL, &ipv6_addr_all_rpl_nodes);
            assert(iface != KERNEL_PID_UNDEF);
        }

        gnrc_rpl_dodag_init(inst, &dio->dodag_id, iface, NULL);

        dodag = &inst->dodag;

        DEBUG("RPL: Joined DODAG (%s).\n",
               ipv6_addr_to_str(addr_str, &dio->dodag_id, sizeof(addr_str)));

        gnrc_rpl_parent_t *parent = NULL;

        if (!gnrc_rpl_parent_add_by_addr(dodag, src, &parent) && (parent == NULL)) {
            DEBUG("RPL: Could not allocate new parent.\n");
            gnrc_rpl_instance_remove(inst);
            return;
        }

        dodag->version = dio->version_number;
        dodag->grounded = dio->g_mop_prf >> GNRC_RPL_GROUNDED_SHIFT;
        dodag->prf = dio->g_mop_prf & GNRC_RPL_PRF_MASK;

        parent->rank = byteorder_ntohs(dio->rank);

        uint32_t included_opts = 0;
        if(!_parse_options(GNRC_RPL_ICMPV6_CODE_DIO, inst, (gnrc_rpl_opt_t *)(dio + 1), len,
                           src, &included_opts)) {
            DEBUG("RPL: Error encountered during DIO option parsing - remove DODAG\n");
            gnrc_rpl_instance_remove(inst);
            return;
        }

        if (!(included_opts & (((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF))) {
#ifndef GNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN
            DEBUG("RPL: DIO without DODAG_CONF option - remove DODAG and request new DIO\n");
            gnrc_rpl_instance_remove(inst);
            gnrc_rpl_send_DIS(NULL, src);
            return;
#else
            DEBUG("RPL: DIO without DODAG_CONF option - use default trickle parameters\n");
            gnrc_rpl_send_DIS(NULL, src);
#endif
        }

        /* if there was no netif_addr created manually or by a PIO, then leave this DODAG */
        if (!dodag->netif_addr) {
            ipv6_addr_t *configured_addr;

            if (!(configured_addr = gnrc_ipv6_netif_match_prefix(dodag->iface, &dodag->dodag_id))) {
                DEBUG("RPL: no IPv6 address configured to match the given dodag id: %s\n",
                      ipv6_addr_to_str(addr_str, &(dodag->dodag_id), sizeof(addr_str)));
                gnrc_rpl_instance_remove(inst);
                return;
            }

            if (!(dodag->netif_addr = gnrc_ipv6_netif_addr_get(configured_addr))) {
                DEBUG("RPL: no netif address found for %s\n",
                       ipv6_addr_to_str(addr_str, configured_addr, sizeof(addr_str)));
                gnrc_rpl_instance_remove(inst);
                return;
            }
        }

        gnrc_rpl_delay_dao(dodag);
        trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_INTERVAL,
                      GNRC_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min),
                      dodag->dio_interval_doubl, dodag->dio_redun);

        gnrc_rpl_parent_update(dodag, parent);
        return;
    }
    else if (inst == NULL) {
Beispiel #14
0
int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh)
{
    if (rh->seg_left == 0) {
        return EXT_RH_CODE_OK;
    }

    uint8_t n = (((rh->len * 8) - GNRC_RPL_SRH_PADDING(rh->pad_resv) -
                 (16 - GNRC_RPL_SRH_COMPRE(rh->compr))) /
                 (16 - GNRC_RPL_SRH_COMPRI(rh->compr))) + 1;
    ipv6_addr_t addr = ipv6->dst, tmp;
    uint8_t i, pref_elided, tmp_pref_elided, addr_len, compri_addr_len, tmp_addr_len, found_pos = 0;
    uint8_t *addr_vec = (uint8_t *) (rh + 1);
    bool found = false;

    DEBUG("RPL SRH: %u addresses in the routing header\n", (unsigned) n);

    if (rh->seg_left > n) {
        DEBUG("RPL SRH: number of segments left > number of addresses - discard\n");
        /* TODO ICMP Parameter Problem - Code 0 */
        return EXT_RH_CODE_ERROR;
    }

    rh->seg_left--;
    i = n - rh->seg_left;
    pref_elided = rh->seg_left ? GNRC_RPL_SRH_COMPRI(rh->compr) : GNRC_RPL_SRH_COMPRE(rh->compr);
    compri_addr_len = sizeof(ipv6_addr_t) - GNRC_RPL_SRH_COMPRI(rh->compr);
    addr_len = sizeof(ipv6_addr_t) - pref_elided;
    memcpy(&addr.u8[pref_elided], &addr_vec[(i - 1) * compri_addr_len], addr_len);

    if (ipv6_addr_is_multicast(&ipv6->dst) || ipv6_addr_is_multicast(&addr)) {
        DEBUG("RPL SRH: found a multicast address - discard\n");
        /* TODO discard the packet */
        return EXT_RH_CODE_ERROR;
    }

    /* check if multiple addresses of my interface exist */
    tmp_pref_elided = GNRC_RPL_SRH_COMPRI(rh->compr);
    tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided;
    tmp = ipv6->dst;
    for (uint8_t k = 0; k < n; k++) {
        if (k == n - 1) {
            tmp_pref_elided = GNRC_RPL_SRH_COMPRE(rh->compr);
            tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided;
        }
        memcpy(&tmp.u8[tmp_pref_elided], &addr_vec[k * compri_addr_len], tmp_addr_len);
        if (gnrc_ipv6_netif_find_by_addr(NULL, &tmp) != KERNEL_PID_UNDEF) {
            if (found && ((k - found_pos) > 1)) {
                DEBUG("RPL SRH: found multiple addresses that belong to me - discard\n");
                /* TODO send an ICMP Parameter Problem (Code 0) and discard the packet */
                return EXT_RH_CODE_ERROR;
            }
            found_pos = k;
            found = true;
        }
    }

    memcpy(&addr_vec[(i - 1) * compri_addr_len], &ipv6->dst.u8[pref_elided], addr_len);

    DEBUG("RPL SRH: Next hop: %s at position %d\n",
          ipv6_addr_to_str(addr_str, &addr, sizeof(addr_str)), i);

    ipv6->dst = addr;

    return EXT_RH_CODE_FORWARD;
}