Beispiel #1
0
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
{

    DEBUGF("Looking up the next hop to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));

    for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
        if (rpl_routing_table[i].used) {
            DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
        }

        if ((RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) && rpl_is_root()) {
            if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
                DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
                return &rpl_routing_table[i].address;
            }
        }
        else {
            if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
                DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
                return &rpl_routing_table[i].next_hop;
            }
        }
    }

    return (rpl_get_my_preferred_parent());
}
Beispiel #2
0
void table(char *unused)
{
    (void) unused;

    rpl_routing_entry_t *rtable;
    rtable = rpl_get_routing_table();
    printf("---------------------------\n");
    printf("OUTPUT\n");
    printf("---------------------------\n");

    for (int i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (rtable[i].used) {
            printf("%s\n", ipv6_addr_to_str(addr_str, (&rtable[i].address)));
            printf("entry %d lifetime %d\n", i, rtable[i].lifetime);

            if (!rpl_equal_id(&rtable[i].address, &rtable[i].next_hop)) {
                puts("multi-hop");
            }

            printf("--------------\n");
        }
    }

    printf("$\n");
}
Beispiel #3
0
Datei: rpl.c Projekt: hper/RIOT
void rpl_del_routing_entry(ipv6_addr_t *addr)
{
    for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (routing_table[i].used && rpl_equal_id(&routing_table[i].address, addr)) {
            memset(&routing_table[i], 0, sizeof(routing_table[i]));
            return;
        }
    }
}
Beispiel #4
0
rpl_dodag_t *rpl_get_dodag(ipv6_addr_t *id)
{
    for (int i = 0; i < RPL_MAX_DODAGS; i++) {
        if (dodags[i].used && (rpl_equal_id(&dodags[i].dodag_id, id))) {
            return &dodags[i];
        }
    }

    return NULL;
}
Beispiel #5
0
Datei: rpl.c Projekt: hper/RIOT
rpl_routing_entry_t *rpl_find_routing_entry(ipv6_addr_t *addr)
{
    for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (routing_table[i].used && rpl_equal_id(&routing_table[i].address, addr)) {
            return &routing_table[i];
        }
    }

    return NULL;
}
Beispiel #6
0
Datei: rpl.c Projekt: hper/RIOT
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
{
    for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (routing_table[i].used && rpl_equal_id(&routing_table[i].address, addr)) {
            return &routing_table[i].next_hop;
        }
    }

    return NULL;
}
Beispiel #7
0
void rpl_delete_parent(rpl_parent_t *parent)
{
    rpl_dodag_t *my_dodag = rpl_get_my_dodag();

    if ((my_dodag != NULL) && rpl_equal_id(&my_dodag->my_preferred_parent->addr,
                                           &parent->addr)) {
        my_dodag->my_preferred_parent = NULL;
    }

    memset(parent, 0, sizeof(*parent));
}
Beispiel #8
0
void rpl_del_routing_entry(ipv6_addr_t *addr)
{

    DEBUGF("Deleting routing entry %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));

    for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
        if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
            memset(&rpl_routing_table[i], 0, sizeof(rpl_routing_table[i]));
            return;
        }
    }
}
Beispiel #9
0
rpl_routing_entry_t *rpl_find_routing_entry(ipv6_addr_t *addr)
{

    DEBUGF("Finding routing entry %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));

    for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
        if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
            return &rpl_routing_table[i];
        }
    }

    return NULL;
}
Beispiel #10
0
rpl_parent_t *rpl_find_parent(ipv6_addr_t *address)
{
    rpl_parent_t *parent;
    rpl_parent_t *end;

    for (parent = &parents[0], end = parents + RPL_MAX_PARENTS; parent < end; parent++) {
        if ((parent->used) && (rpl_equal_id(address, &parent->addr))) {
            return parent;
        }
    }

    return NULL;
}
Beispiel #11
0
rpl_parent_t *rpl_find_preferred_parent(void)
{
    rpl_parent_t *best = NULL;
    rpl_dodag_t *my_dodag = rpl_get_my_dodag();

    if (my_dodag == NULL) {
        DEBUG("Not part of a dodag\n");
        return NULL;
    }

    for (uint8_t i = 0; i < RPL_MAX_PARENTS; i++) {
        if (parents[i].used) {
            if ((parents[i].rank == INFINITE_RANK) || (parents[i].lifetime <= 1)) {
                DEBUG("Infinite rank, bad parent\n");
                continue;
            }
            else if (best == NULL) {
                DEBUG("possible parent\n");
                best = &parents[i];
            }
            else {
                best = my_dodag->of->which_parent(best, &parents[i]);
            }
        }
    }

    if (best == NULL) {
        return NULL;
    }

    if (my_dodag->my_preferred_parent == NULL) {
        my_dodag->my_preferred_parent = best;
    }

    if (!rpl_equal_id(&my_dodag->my_preferred_parent->addr, &best->addr)) {
        if (my_dodag->mop != NO_DOWNWARD_ROUTES) {
            /* send DAO with ZERO_LIFETIME to old parent */
            send_DAO(&my_dodag->my_preferred_parent->addr, 0, false, 0);
        }

        my_dodag->my_preferred_parent = best;

        if (my_dodag->mop != NO_DOWNWARD_ROUTES) {
            delay_dao();
        }

        reset_trickletimer();
    }

    return best;
}
Beispiel #12
0
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
{
    DEBUGF("looking up the next hop to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
    for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (rpl_routing_table[i].used) {
            DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
        }
        if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
            DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
            return &rpl_routing_table[i].next_hop;
        }
    }

    return (rpl_get_my_preferred_parent());
}
Beispiel #13
0
void rpl_udp_loop(int argc, char **argv)
{
    (void) argc;
    (void) argv;

    rpl_routing_entry_t *rtable;

    rtable = rpl_get_routing_table();
    rpl_dodag_t *mydodag = rpl_get_my_dodag();

    if (mydodag == NULL) {
        return;
    }

    printf("---------------------------\n");
    printf("OUTPUT\n");
    printf("my rank: %d\n", mydodag->my_rank);

    if (!is_root) {
        printf("my preferred parent:\n");
        printf("%s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
                                        (&mydodag->my_preferred_parent->addr)));
        printf("parent lifetime: %d\n", mydodag->my_preferred_parent->lifetime);
    }

    printf("---------------------------$\n");

    for (int i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
        if (rtable[i].used) {
            printf("%s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
                                            (&rtable[i].address)));
            puts("next hop");
            printf("%s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
                                            (&rtable[i].next_hop)));
            printf("entry %d lifetime %d\n", i, rtable[i].lifetime);

            if (!rpl_equal_id(&rtable[i].address, &rtable[i].next_hop)) {
                puts("multi-hop");
            }

            printf("---------------------------$\n");
        }
    }

    printf("########################\n");
}
Beispiel #14
0
ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
{
    uint8_t route_length = RPL_MAX_SRH_PATH_LENGTH;
    ipv6_addr_t rev_route[route_length];
    ipv6_addr_t *actual_node;
    uint8_t counter = 0;
    uint8_t traceable;
    ipv6_srh_t *srh_header = (ipv6_srh_t *)(&srh_buffer);

    /* init source route with child */
    actual_node = &(act_ipv6_hdr->destaddr);
    DEBUGF("DESTINATION NODE: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));

    while (!(rpl_equal_id(actual_node, &my_address))) {
        /* set check variable - this is reversed, if a child/parent-relation is found in one iteration of the routing table */
        traceable = 0;

        for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
            if (rpl_routing_table[i].used && ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) {
                DEBUGF("[INFO] Found parent-child relation with P: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop));
                DEBUGF(" and C: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
                memcpy(&rev_route[counter], actual_node, sizeof(ipv6_addr_t));

                actual_node = &rpl_routing_table[i].next_hop;
                counter++;
                traceable = 1;

                if (counter > route_length) {
                    DEBUGF("[INFO] Both lengths are %d and %d\n", counter, route_length);
                    DEBUGF("Error with computing source routing header.\n");
                    return NULL;
                }
                break;
            }
        }

        if (traceable == 0) {
            DEBUGF("No route to destination.\n");
            return NULL;
        }
    }

    /* build real route based on reversed route. After building it starts with the node next to destination */
    if (counter > 1) {
        for (uint8_t i = 0; i < counter-1; i++) {
            memcpy(&srh_header->route[i], &rev_route[counter-i-2], sizeof(ipv6_addr_t));
        }
        srh_header->hdrextlen = sizeof(ipv6_addr_t)*(counter-1);
        memcpy(&(act_ipv6_hdr->destaddr), &rev_route[counter-1], sizeof(ipv6_addr_t));
        DEBUGF("Route size: %d\n", srh_header->hdrextlen);
    }
    else {
        srh_header->hdrextlen = 0;
    }

    /* actually build SRH-header */
    memcpy(&srh_header->nextheader, &(act_ipv6_hdr->nextheader), sizeof(uint8_t));
    srh_header->routing_type = 3;
    srh_header->segments_left = counter - 1;
    /* cmpri & cmpre are both 0, because by now there is only support for full addresses */
    srh_header->cmpri = 0;
    srh_header->cmpre = 0;
    /* since the route has exactly the length of its intermediate nodes, padding is zero. */
    srh_header->pad = 0;
    srh_header->reserved = 0;
    /* set the destination-address in ipv6-buf->destaddr, which is the pointer of child */
    return srh_header;
}
Beispiel #15
0
Datei: rpl.c Projekt: hper/RIOT
void recv_rpl_dio(void)
{
    ipv6_buf = get_rpl_ipv6_buf();

    rpl_dio_buf = get_rpl_dio_buf();
    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 */
            return;
        }

        dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid);

        if (dio_inst == NULL) {
            return;
        }
    }
    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.  */

        DEBUG("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 < (ipv6_buf->length - ICMPV6_HDR_LEN)) {
        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 + 2;
                break;
            }

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

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

            case (RPL_OPT_DODAG_CONF): {
                has_dodag_conf_opt = 1;

                if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) {
                    /* 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 =	rpl_opt_dodag_conf_buf->MaxRankIncrease;
                dio_dodag.minhoprankincrease = rpl_opt_dodag_conf_buf->MinHopRankIncrease;
                dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime;
                dio_dodag.lifetime_unit = rpl_opt_dodag_conf_buf->lifetime_unit;
                dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(rpl_opt_dodag_conf_buf->ocp);
                len += RPL_OPT_DODAG_CONF_LEN + 2;
                break;
            }

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

                len += RPL_OPT_PREFIX_INFO_LEN + 2;
                break;
            }

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

    /* handle packet content... */
    rpl_dodag_t *my_dodag = rpl_get_my_dodag();

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

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

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

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

        if (rpl_dio_buf->rank != INFINITE_RANK) {
            char addr_str[IPV6_MAX_ADDR_STR_LEN];
            DEBUG("Will join DODAG\n");
            printf("%s", ipv6_addr_to_str(addr_str, &dio_dodag.dodag_id));
            rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank);
        }
        else {
            DEBUG("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) {
                DEBUG("[Warning] Inconsistent Dodag Version\n");
                my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
                reset_trickletimer();
            }
            else {
                DEBUG("[Info] New Version of dodag %d\n", dio_dodag.version);
                rpl_global_repair(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank);
            }

            return;
        }
        else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
            /* ein Knoten hat noch eine kleinere Versionsnummer -> mehr DIOs senden */
            reset_trickletimer();
            return;
        }
    }

    /* version matches, DODAG matches */
    if (rpl_dio_buf->rank == INFINITE_RANK) {
        reset_trickletimer();
    }

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

        return;
    }

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

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

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

        if (parent == NULL) {
            return;
        }
    }
    else {
        /* DIO OK */
        trickle_increment_counter();
    }

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

    if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) {
        delay_dao();
    }

    parent->dtsn = rpl_dio_buf->dtsn;

}
Beispiel #16
0
Datei: rpl.c Projekt: hper/RIOT
void recv_rpl_dis(void)
{
    rpl_dodag_t *my_dodag = rpl_get_my_dodag();

    if (my_dodag == NULL) {
        return;
    }

    ipv6_buf = get_rpl_ipv6_buf();
    rpl_dis_buf = get_rpl_dis_buf();
    int len = DIS_BASE_LEN;

    while (len < (ipv6_buf->length - ICMPV6_HDR_LEN)) {
        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 + 2;
                break;
            }

            case (RPL_OPT_SOLICITED_INFO): {
                len += RPL_OPT_SOLICITED_INFO_LEN + 2;

                /* extract and check */
                if (rpl_opt_buf->length != RPL_OPT_SOLICITED_INFO_LEN) {
                    /* error malformed */
                    return;
                }

                rpl_opt_solicited_buf = get_rpl_opt_solicited_buf(len);

                if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_I_MASK) {
                    if (my_dodag->instance->id != rpl_opt_solicited_buf->rplinstanceid) {
                        return;
                    }
                }

                if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_D_MASK) {
                    if (!rpl_equal_id(&my_dodag->dodag_id, &rpl_opt_solicited_buf->dodagid)) {
                        return;
                    }
                }

                if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_V_MASK) {
                    if (my_dodag->version != rpl_opt_solicited_buf->version) {
                        return;
                    }
                }

                break;
            }

            default:
                return;
        }
    }

    send_DIO(&ipv6_buf->srcaddr);

}
Beispiel #17
0
void rpl_recv_DIS(void)
{
    ipv6_buf = get_rpl_ipv6_buf();
    rpl_dis_buf = get_rpl_dis_buf();
    int len = DIS_BASE_LEN;
    rpl_dodag_t *dodag, *end;
    uint8_t options_missing = 1;

    while (len < (NTOHS(ipv6_buf->length) - ICMPV6_HDR_LEN)) {
        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_SOLICITED_INFO): {
                options_missing = 0;
                len += RPL_OPT_SOLICITED_INFO_LEN;

                /* extract and check */
                if (rpl_opt_buf->length != RPL_OPT_SOLICITED_INFO_LEN) {
                    /* error malformed */
                    return;
                }

                rpl_opt_solicited_buf = get_rpl_opt_solicited_buf(len);

                for (dodag = rpl_dodags, end = dodag + RPL_MAX_DODAGS; dodag < end; dodag++) {
                    if (dodag->joined) {
                        if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_I_MASK) {
                            if (dodag->instance->id != rpl_opt_solicited_buf->rplinstanceid) {
                                continue;
                            }
                        }

                        if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_D_MASK) {
                            if (!rpl_equal_id(&dodag->dodag_id, &rpl_opt_solicited_buf->dodagid)) {
                                continue;
                            }
                        }

                        if (rpl_opt_solicited_buf->VID_Flags & RPL_DIS_V_MASK) {
                            if (dodag->version != rpl_opt_solicited_buf->version) {
                                continue;
                            }
                        }

                        rpl_send_DIO(dodag, &ipv6_buf->srcaddr);
                        trickle_reset_timer(&dodag->trickle);
                    }
                }

                break;
            }

            default:
                return;
        }
    }

    if (options_missing) {
        for (dodag = rpl_dodags, end = dodag + RPL_MAX_DODAGS; dodag < end; dodag++) {
            if (dodag->joined) {
                rpl_send_DIO(dodag, &ipv6_buf->srcaddr);
                trickle_reset_timer(&dodag->trickle);
            }
        }
    }
}
Beispiel #18
0
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;

}
Beispiel #19
0
void recv_rpl_dio(void)
{
    ipv6_buf = get_rpl_ipv6_buf();

    rpl_dio_buf = get_rpl_dio_buf();
    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) {
            /* Dieser Knoten ist schon Teil eines DODAGS -> kein beitritt zu anderer Instanz moeglich */
            return;
        }

        dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid);

        if(dio_inst == NULL) {
            return;
        }
    }
    else if(my_inst->id != dio_inst->id) {
        printf("Andere Instanz, wir haben %d es kam aber %d\n", my_inst->id, dio_inst->id);
        /* DIO von fremder Instanz ignorieren, Knoten können Momentan nur
         * einer Instanz beitreten und das wird die Instanz sein, der sie als
         * erstes beitreten. Danach kann die Instanz nicht mehr gewechselt
         * werden Unterstützung für mehrere Instanzen könnte in Zukunft
         * implementiert werden */
        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;
    /* So lange das Paket größer ist, als die DIO Größe + Größe der bisher
     * verarbeiteten Optionen, sind noch weitere Optionen zu bearbeiten */

    /* dabei müssen wir jedoch von der ipv6_buf->length die Größe des ICMP
     * Headers abziehen weil get_rpl_opt_buf die Paketlänge OHNE ipv6 und
     * icmpv6 header übergeben werden muss in ipv6_buf->length ist die
     * IPV6_HDR_LEN nicht enthalten, also muss nur noch die ICMPV6_HDR_LEN
     * abgezogen werden */

    while(len < (ipv6_buf->length - ICMPV6_HDR_LEN)) {
        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 + 2;
                break;
            }

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

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

            case(RPL_OPT_DODAG_CONF): {
                has_dodag_conf_opt = 1;

                if(rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) {
                    /* 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 =	rpl_opt_dodag_conf_buf->MaxRankIncrease;
                dio_dodag.minhoprankincrease = rpl_opt_dodag_conf_buf->MinHopRankIncrease;
                dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime;
                dio_dodag.lifetime_unit = rpl_opt_dodag_conf_buf->lifetime_unit;
                dio_dodag.of = rpl_get_of_for_ocp(rpl_opt_dodag_conf_buf->ocp);
                len += RPL_OPT_DODAG_CONF_LEN + 2;
                break;
            }

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

                len += RPL_OPT_PREFIX_INFO_LEN + 2;
                break;
            }

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

    /* handle packet content... */
    rpl_dodag_t *my_dodag = rpl_get_my_dodag();

    if(my_dodag == NULL) {
        if(!has_dodag_conf_opt) {
            puts("send DIS");
            send_DIS(&ipv6_buf->srcaddr);
            return;
        }

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

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

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

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

    if(rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) {
        /* Mein DODAG */
        if(RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) {
            if(my_dodag->my_rank == ROOT_RANK) {
                /* Jemand hat ein DIO mit einer höheren Version als der richtigen gesendet */
                /* Wir erhöhen diese Version noch einmal, und machen sie zur neuen */
                printf("[Warning] Inconsistent Dodag Version\n");
                my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
                reset_trickletimer();
            }
            else {
                printf("[Info] New Version of dodag %d\n", dio_dodag.version);
                rpl_global_repair(&dio_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank);
            }

            return;
        }
        else if(RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
            /* ein Knoten hat noch eine kleinere Versionsnummer -> mehr DIOs senden */
            reset_trickletimer();
            return;
        }
    }

    /* Version stimmt, DODAG stimmt */
    if(rpl_dio_buf->rank == INFINITE_RANK) {
        reset_trickletimer();
    }

    /* Wenn wir root sind, ist nichts weiter zu tun */
    if(my_dodag->my_rank == ROOT_RANK) {
        if(rpl_dio_buf->rank != INFINITE_RANK) {
            trickle_increment_counter();
        }

        return;
    }

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

    /* Ist Knoten bereits Parent? */
    rpl_parent_t *parent;
    parent = rpl_find_parent(&ipv6_buf->srcaddr);

    if(parent == NULL) {
        /* neuen möglichen Elternknoten hinzufuegen */
        parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, rpl_dio_buf->rank);

        if(parent == NULL) {
            return;
        }
    }
    else {
        /* DIO ok */
        trickle_increment_counter();
    }

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

    if(rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && (parent->dtsn != rpl_dio_buf->dtsn)) {
        delay_dao();
    }

    parent->dtsn = rpl_dio_buf->dtsn;

}