diff --git a/sys/net/routing/rpl/rpl.c b/sys/net/routing/rpl/rpl.c index 669ce66f19..6fda31163c 100644 --- a/sys/net/routing/rpl/rpl.c +++ b/sys/net/routing/rpl/rpl.c @@ -31,162 +31,40 @@ #include "sixlowpan.h" #include "net_help.h" +/* You can only run Storing Mode by now. Other unsupported modes lead to default (Storing Mode) */ +#if RPL_DEFAULT_MOP == RPL_STORING_MODE_NO_MC +#include "rpl_storing.h" +#else +#include "rpl_storing.h" +#endif + #define ENABLE_DEBUG (0) #if ENABLE_DEBUG #undef TRICKLE_TIMER_STACKSIZE #define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN) -#define DEBUG_ENABLED char addr_str[IPV6_MAX_ADDR_STR_LEN]; #endif #include "debug.h" -char rpl_process_buf[RPL_PROCESS_STACKSIZE]; /* global variables */ -char i_am_root = 0; -rpl_of_t *objective_functions[NUMBER_IMPLEMENTED_OFS]; -rpl_routing_entry_t routing_table[RPL_MAX_ROUTING_ENTRIES]; +rpl_of_t *rpl_objective_functions[NUMBER_IMPLEMENTED_OFS]; +rpl_routing_entry_t rpl_routing_table[RPL_MAX_ROUTING_ENTRIES]; unsigned int rpl_process_pid; -ipv6_addr_t my_address; -mutex_t rpl_send_mutex; mutex_t rpl_recv_mutex; -/* receive buffer without LL_HDR */ +mutex_t rpl_send_mutex; +msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE]; +char rpl_process_buf[RPL_PROCESS_STACKSIZE]; uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN]; -/* in send buffer we need space fpr LL_HDR */ -uint8_t rpl_send_buffer[BUFFER_SIZE]; -msg_t msg_queue[RPL_PKT_RECV_BUF_SIZE]; -/* SEND BUFFERS */ -static ipv6_hdr_t *ipv6_send_buf; -static icmpv6_hdr_t *icmp_send_buf; -static struct rpl_dio_t *rpl_send_dio_buf; -static struct rpl_dis_t *rpl_send_dis_buf; -static struct rpl_dao_t *rpl_send_dao_buf; -static struct rpl_dao_ack_t *rpl_send_dao_ack_buf; -static rpl_opt_dodag_conf_t *rpl_send_opt_dodag_conf_buf; -/* static struct rpl_opt_solicited_t * rpl_send_opt_solicited_buf; */ -static rpl_opt_target_t *rpl_send_opt_target_buf; -static rpl_opt_transit_t *rpl_send_opt_transit_buf; - -/* RECEIVE BUFFERS */ -static ipv6_hdr_t *ipv6_buf; -static struct rpl_dio_t *rpl_dio_buf; -static struct rpl_dis_t *rpl_dis_buf; -static struct rpl_dao_t *rpl_dao_buf; -static struct rpl_dao_ack_t *rpl_dao_ack_buf; -static rpl_opt_t *rpl_opt_buf; -static rpl_opt_dodag_conf_t *rpl_opt_dodag_conf_buf; -static rpl_opt_solicited_t *rpl_opt_solicited_buf; -static rpl_opt_target_t *rpl_opt_target_buf; -static rpl_opt_transit_t *rpl_opt_transit_buf; - -/* SEND BUFFERS */ -static ipv6_hdr_t *get_rpl_send_ipv6_buf(void) -{ - return ((ipv6_hdr_t *) &(rpl_send_buffer[0])); -} - -static uint8_t *get_rpl_send_payload_buf(uint8_t ext_len) -{ - return &(rpl_send_buffer[IPV6_HDR_LEN + ext_len]); -} - -static icmpv6_hdr_t *get_rpl_send_icmpv6_buf(uint8_t ext_len) -{ - return ((icmpv6_hdr_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ext_len])); -} - -static struct rpl_dio_t *get_rpl_send_dio_buf(void) -{ - return ((struct rpl_dio_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static struct rpl_dao_t *get_rpl_send_dao_buf(void) -{ - return ((struct rpl_dao_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static struct rpl_dao_ack_t *get_rpl_send_dao_ack_buf(void) -{ - return ((struct rpl_dao_ack_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static struct rpl_dis_t *get_rpl_send_dis_buf(void) -{ - return ((struct rpl_dis_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static rpl_opt_dodag_conf_t *get_rpl_send_opt_dodag_conf_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_dodag_conf_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_target_t *get_rpl_send_opt_target_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_target_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_transit_t *get_rpl_send_opt_transit_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_transit_t *) &(rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -/* RECEIVE BUFFERS */ -static ipv6_hdr_t *get_rpl_ipv6_buf(void) -{ - return ((ipv6_hdr_t *) &(rpl_buffer[0])); -} - -static struct rpl_dio_t *get_rpl_dio_buf(void) -{ - return ((struct rpl_dio_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static struct rpl_dao_t *get_rpl_dao_buf(void) -{ - return ((struct rpl_dao_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static struct rpl_dao_ack_t *get_rpl_dao_ack_buf(void) -{ - return ((struct rpl_dao_ack_t *) &(buffer[(LL_HDR_LEN + IPV6_HDR_LEN + ICMPV6_HDR_LEN)])); -} - -static struct rpl_dis_t *get_rpl_dis_buf(void) -{ - return ((struct rpl_dis_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); -} - -static rpl_opt_t *get_rpl_opt_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_dodag_conf_t *get_rpl_opt_dodag_conf_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_dodag_conf_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_solicited_t *get_rpl_opt_solicited_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_solicited_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_target_t *get_rpl_opt_target_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_target_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} - -static rpl_opt_transit_t *get_rpl_opt_transit_buf(uint8_t rpl_msg_len) -{ - return ((rpl_opt_transit_t *) &(rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); -} +/* IPv6 message buffer */ +ipv6_hdr_t *ipv6_buf; /* find implemented OF via objective code point */ rpl_of_t *rpl_get_of_for_ocp(uint16_t ocp) { for (uint16_t i = 0; i < NUMBER_IMPLEMENTED_OFS; i++) { - if (ocp == objective_functions[i]->ocp) { - return objective_functions[i]; + if (ocp == rpl_objective_functions[i]->ocp) { + return rpl_objective_functions[i]; } } @@ -197,7 +75,6 @@ uint8_t rpl_init(int if_id) { mutex_init(&rpl_send_mutex); mutex_init(&rpl_recv_mutex); - rpl_instances_init(); /* initialize routing table */ @@ -208,11 +85,12 @@ uint8_t rpl_init(int if_id) rpl_process, "rpl_process"); /* INSERT NEW OBJECTIVE FUNCTIONS HERE */ - objective_functions[0] = rpl_get_of0(); - objective_functions[1] = rpl_get_of_mrhof(); + rpl_objective_functions[0] = rpl_get_of0(); + rpl_objective_functions[1] = rpl_get_of_mrhof(); sixlowpan_lowpan_init_interface(if_id); /* need link local prefix to query _our_ corresponding address */ + ipv6_addr_t my_address; ipv6_addr_t ll_address; ipv6_addr_set_link_local_prefix(&ll_address); ipv6_net_if_get_best_src_addr(&my_address, &ll_address); @@ -224,297 +102,52 @@ uint8_t rpl_init(int if_id) etx_init_beaconing(&my_address); } + rpl_init_mode(&my_address); + return SIXLOWERROR_SUCCESS; } void rpl_init_root(void) { - rpl_instance_t *inst; - rpl_dodag_t *dodag; - - inst = rpl_new_instance(RPL_DEFAULT_INSTANCE); - - if (inst == NULL) { - DEBUGF("Error - No memory for another RPL instance\n"); - return; - } - - inst->id = RPL_DEFAULT_INSTANCE; - inst->joined = 1; - - dodag = rpl_new_dodag(RPL_DEFAULT_INSTANCE, &my_address); - - if (dodag != NULL) { - dodag->of = (struct rpl_of_t *) rpl_get_of_for_ocp(RPL_DEFAULT_OCP); - dodag->instance = inst; - dodag->mop = RPL_DEFAULT_MOP; - dodag->dtsn = 1; - dodag->prf = 0; - dodag->dio_interval_doubling = DEFAULT_DIO_INTERVAL_DOUBLINGS; - dodag->dio_min = DEFAULT_DIO_INTERVAL_MIN; - dodag->dio_redundancy = DEFAULT_DIO_REDUNDANCY_CONSTANT; - dodag->maxrankincrease = 0; - dodag->minhoprankincrease = (uint16_t)DEFAULT_MIN_HOP_RANK_INCREASE; - dodag->default_lifetime = (uint8_t)RPL_DEFAULT_LIFETIME; - dodag->lifetime_unit = RPL_LIFETIME_UNIT; - dodag->version = RPL_COUNTER_INIT; - dodag->grounded = RPL_GROUNDED; - dodag->node_status = (uint8_t) ROOT_NODE; - dodag->my_rank = RPL_ROOT_RANK; - dodag->joined = 1; - dodag->my_preferred_parent = NULL; - } - else { - DEBUGF("Error - could not generate DODAG\n"); - return; - } - - i_am_root = 1; - start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy); - DEBUGF("ROOT INIT FINISHED\n"); - -} - - -void send_DIO(ipv6_addr_t *destination) -{ - DEBUGF("Send DIO\n"); - mutex_lock(&rpl_send_mutex); - rpl_dodag_t *mydodag; - icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); - - mydodag = rpl_get_my_dodag(); - - if (mydodag == NULL) { - DEBUGF("Error - trying to send DIO without being part of a dodag.\n"); - mutex_unlock(&rpl_send_mutex); - return; - } - - icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; - icmp_send_buf->code = ICMP_CODE_DIO; - - rpl_send_dio_buf = get_rpl_send_dio_buf(); - memset(rpl_send_dio_buf, 0, sizeof(*rpl_send_dio_buf)); - - DEBUGF("Sending DIO with "); - rpl_send_dio_buf->rpl_instanceid = mydodag->instance->id; - DEBUG("instance %02X ", rpl_send_dio_buf->rpl_instanceid); - rpl_send_dio_buf->version_number = mydodag->version; - rpl_send_dio_buf->rank = mydodag->my_rank; - DEBUG("rank %04X\n", rpl_send_dio_buf->rank); - rpl_send_dio_buf->g_mop_prf = (mydodag->grounded << RPL_GROUNDED_SHIFT) | (mydodag->mop << RPL_MOP_SHIFT) | mydodag->prf; - rpl_send_dio_buf->dtsn = mydodag->dtsn; - rpl_send_dio_buf->flags = 0; - rpl_send_dio_buf->reserved = 0; - rpl_send_dio_buf->dodagid = mydodag->dodag_id; - - int opt_hdr_len = 0; - /* DODAG configuration option */ - rpl_send_opt_dodag_conf_buf = get_rpl_send_opt_dodag_conf_buf(DIO_BASE_LEN); - rpl_send_opt_dodag_conf_buf->type = RPL_OPT_DODAG_CONF; - rpl_send_opt_dodag_conf_buf->length = RPL_OPT_DODAG_CONF_LEN; - rpl_send_opt_dodag_conf_buf->flags_a_pcs = 0; - rpl_send_opt_dodag_conf_buf->DIOIntDoubl = mydodag->dio_interval_doubling; - rpl_send_opt_dodag_conf_buf->DIOIntMin = mydodag->dio_min; - rpl_send_opt_dodag_conf_buf->DIORedun = mydodag->dio_redundancy; - rpl_send_opt_dodag_conf_buf->MaxRankIncrease = mydodag->maxrankincrease; - rpl_send_opt_dodag_conf_buf->MinHopRankIncrease = mydodag->minhoprankincrease; - rpl_send_opt_dodag_conf_buf->ocp = mydodag->of->ocp; - rpl_send_opt_dodag_conf_buf->reserved = 0; - rpl_send_opt_dodag_conf_buf->default_lifetime = mydodag->default_lifetime; - rpl_send_opt_dodag_conf_buf->lifetime_unit = mydodag->lifetime_unit; - - opt_hdr_len += RPL_OPT_LEN + RPL_OPT_DODAG_CONF_LEN; - - uint16_t plen = ICMPV6_HDR_LEN + DIO_BASE_LEN + opt_hdr_len; - rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); - mutex_unlock(&rpl_send_mutex); -} - -void send_DIS(ipv6_addr_t *destination) -{ - DEBUGF("Send DIS\n"); - mutex_lock(&rpl_send_mutex); - icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); - - icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; - icmp_send_buf->code = ICMP_CODE_DIS; - - rpl_send_dis_buf = get_rpl_send_dis_buf(); - - uint16_t plen = ICMPV6_HDR_LEN + DIS_BASE_LEN; - rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); - mutex_unlock(&rpl_send_mutex); -} - - -void send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index) -{ - if (i_am_root) { - return; - } - - DEBUGF("Send DAO\n"); - mutex_lock(&rpl_send_mutex); - rpl_dodag_t *my_dodag; - - if ((my_dodag = rpl_get_my_dodag()) == NULL) { - DEBUGF("send_DAO: I have no my_dodag\n"); - mutex_unlock(&rpl_send_mutex); - return; - } - - if (destination == NULL) { - if (my_dodag->my_preferred_parent == NULL) { - DEBUGF("send_DAO: my_dodag has no my_preferred_parent\n"); - mutex_unlock(&rpl_send_mutex); - return; - } - - destination = &my_dodag->my_preferred_parent->addr; - } - - if (default_lifetime) { - lifetime = my_dodag->default_lifetime; - } - - icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); - - icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; - icmp_send_buf->code = ICMP_CODE_DAO; - - rpl_send_dao_buf = get_rpl_send_dao_buf(); - memset(rpl_send_dao_buf, 0, sizeof(*rpl_send_dao_buf)); - rpl_send_dao_buf->rpl_instanceid = my_dodag->instance->id; - rpl_send_dao_buf->k_d_flags = 0x00; - rpl_send_dao_buf->dao_sequence = my_dodag->dao_seq; - DEBUGF("Send DAO with instance %04X and sequence %04X to %s\n", - __FILE__, __LINE__, - rpl_send_dao_buf->rpl_instanceid, rpl_send_dao_buf->dao_sequence, - ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - uint16_t opt_len = 0; - rpl_send_opt_target_buf = get_rpl_send_opt_target_buf(DAO_BASE_LEN); - /* add all targets from routing table as targets */ - uint8_t entries = 0; - uint8_t continue_index = 0; - - for (uint8_t i = start_index; i < RPL_MAX_ROUTING_ENTRIES; i++) { - if (routing_table[i].used) { - rpl_send_opt_target_buf->type = RPL_OPT_TARGET; - rpl_send_opt_target_buf->length = RPL_OPT_TARGET_LEN; - rpl_send_opt_target_buf->flags = 0x00; - rpl_send_opt_target_buf->prefix_length = RPL_DODAG_ID_LEN; - memcpy(&rpl_send_opt_target_buf->target, &routing_table[i].address, sizeof(ipv6_addr_t)); - opt_len += RPL_OPT_TARGET_LEN + 2; - rpl_send_opt_transit_buf = get_rpl_send_opt_transit_buf(DAO_BASE_LEN + opt_len); - rpl_send_opt_transit_buf->type = RPL_OPT_TRANSIT; - rpl_send_opt_transit_buf->length = RPL_OPT_TRANSIT_LEN; - rpl_send_opt_transit_buf->e_flags = 0x00; - rpl_send_opt_transit_buf->path_control = 0x00; /* not used */ - rpl_send_opt_transit_buf->path_sequence = 0x00; /* not used */ - rpl_send_opt_transit_buf->path_lifetime = lifetime; - opt_len += RPL_OPT_TRANSIT_LEN + 2; - rpl_send_opt_target_buf = get_rpl_send_opt_target_buf(DAO_BASE_LEN + opt_len); - entries++; - } - - /* Split DAO, so packages don't get too big. - * The value 5 is based on experience. */ - if (entries >= 5) { - continue_index = i + 1; - break; - } - } - - /* add own address */ - rpl_send_opt_target_buf->type = RPL_OPT_TARGET; - rpl_send_opt_target_buf->length = RPL_OPT_TARGET_LEN; - rpl_send_opt_target_buf->flags = 0x00; - rpl_send_opt_target_buf->prefix_length = RPL_DODAG_ID_LEN; - memcpy(&rpl_send_opt_target_buf->target, &my_address, sizeof(ipv6_addr_t)); - opt_len += RPL_OPT_TARGET_LEN + 2; - - rpl_send_opt_transit_buf = get_rpl_send_opt_transit_buf(DAO_BASE_LEN + opt_len); - rpl_send_opt_transit_buf->type = RPL_OPT_TRANSIT; - rpl_send_opt_transit_buf->length = RPL_OPT_TRANSIT_LEN; - rpl_send_opt_transit_buf->e_flags = 0x00; - rpl_send_opt_transit_buf->path_control = 0x00; - rpl_send_opt_transit_buf->path_sequence = 0x00; - rpl_send_opt_transit_buf->path_lifetime = lifetime; - opt_len += RPL_OPT_TRANSIT_LEN + 2; - - uint16_t plen = ICMPV6_HDR_LEN + DAO_BASE_LEN + opt_len; - rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); - mutex_unlock(&rpl_send_mutex); - - if (continue_index > 1) { - send_DAO(destination, lifetime, default_lifetime, continue_index); - } -} - -void send_DAO_ACK(ipv6_addr_t *destination) -{ - DEBUGF("Send DAO ACK to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - rpl_dodag_t *my_dodag; - my_dodag = rpl_get_my_dodag(); - - if (my_dodag == NULL) { - return; - } - - mutex_lock(&rpl_send_mutex); - icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); - - icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; - icmp_send_buf->code = ICMP_CODE_DAO_ACK; - - rpl_send_dao_ack_buf = get_rpl_send_dao_ack_buf(); - rpl_send_dao_ack_buf->rpl_instanceid = my_dodag->instance->id; - rpl_send_dao_ack_buf->d_reserved = 0; - rpl_send_dao_ack_buf->dao_sequence = my_dodag->dao_seq; - rpl_send_dao_ack_buf->status = 0; - - uint16_t plen = ICMPV6_HDR_LEN + DAO_ACK_LEN; - rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); - mutex_unlock(&rpl_send_mutex); + rpl_init_root_mode(); } void rpl_process(void) { msg_t m_recv; - msg_init_queue(msg_queue, RPL_PKT_RECV_BUF_SIZE); + msg_init_queue(rpl_msg_queue, RPL_PKT_RECV_BUF_SIZE); while (1) { msg_receive(&m_recv); + mutex_lock(&rpl_recv_mutex); uint8_t *code; code = ((uint8_t *)m_recv.content.ptr); /* differentiate packet types */ ipv6_buf = ipv6_get_buf(); memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN); - DEBUGF("Reveived RPL information of type %04X and length %u\n", *code, NTOHS(ipv6_buf->length)); + DEBUGF("Received RPL information of type %04X and length %u\n", *code, NTOHS(ipv6_buf->length)); switch (*code) { case (ICMP_CODE_DIS): { - recv_rpl_dis(); + recv_rpl_DIS(); mutex_unlock(&rpl_recv_mutex); break; } case (ICMP_CODE_DIO): { - recv_rpl_dio(); + recv_rpl_DIO(); mutex_unlock(&rpl_recv_mutex); break; } case (ICMP_CODE_DAO): { - recv_rpl_dao(); + recv_rpl_DAO(); mutex_unlock(&rpl_recv_mutex); break; } case (ICMP_CODE_DAO_ACK): { - recv_rpl_dao_ack(); + recv_rpl_DAO_ACK(); mutex_unlock(&rpl_recv_mutex); break; } @@ -526,478 +159,92 @@ void rpl_process(void) } } +/**************************************************************/ +/* General RPL-send & -receive functions. Call mode-functions */ +/**************************************************************/ -void recv_rpl_dio(void) +void send_DIO(ipv6_addr_t *destination) { - DEBUGF("Received DIO with "); - ipv6_buf = get_rpl_ipv6_buf(); + DEBUGF("Send DIO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - rpl_dio_buf = get_rpl_dio_buf(); - DEBUG("instance %04X ", rpl_dio_buf->rpl_instanceid); - DEBUG("rank %04X\n", rpl_dio_buf->rank); - int len = DIO_BASE_LEN; + mutex_lock(&rpl_send_mutex); + send_DIO_mode(destination); + mutex_unlock(&rpl_send_mutex); +} - rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid); - rpl_instance_t *my_inst = rpl_get_my_instance(); +void send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index) +{ + DEBUG("Send DAO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - 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; - } + mutex_lock(&rpl_send_mutex); + send_DAO_mode(destination, lifetime, default_lifetime, start_index); + mutex_unlock(&rpl_send_mutex); +} - dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid); +void send_DIS(ipv6_addr_t *destination) +{ + DEBUGF("Send DIS to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - 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. */ + mutex_lock(&rpl_send_mutex); + send_DIS_mode(destination); + mutex_unlock(&rpl_send_mutex); +} - /* At the moment, nodes can only join one instance, this is - * the instance they join first. - * Instances cannot be switched later on. */ +void send_DAO_ACK(ipv6_addr_t *destination) +{ + DEBUGF("Send DAO ACK to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); - DEBUGF("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id); - return; - } + mutex_lock(&rpl_send_mutex); + send_DAO_ACK_mode(destination); + mutex_unlock(&rpl_send_mutex); +} - rpl_dodag_t dio_dodag; - memset(&dio_dodag, 0, sizeof(dio_dodag)); +void recv_rpl_DIO(void) +{ + DEBUGF("DIO received\n"); - 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; + recv_rpl_DIO_mode(); +} - uint8_t has_dodag_conf_opt = 0; +void recv_rpl_DAO(void) +{ + DEBUGF("DAO received\n"); - /* 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); + recv_rpl_DAO_mode(); +} - switch (rpl_opt_buf->type) { +void recv_rpl_DIS(void) +{ + DEBUGF("DIS received\n"); - 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) { - 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 = 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: - DEBUGF("[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) { - DEBUGF("send DIS\n"); - send_DIS(&ipv6_buf->srcaddr); - } - - if (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 (rpl_dio_buf->rank != INFINITE_RANK) { - DEBUGF("Will join DODAG\n"); - rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, 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); - reset_trickletimer(); - } - else { - DEBUGF("[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 (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)) { - delay_dao(); - } - - parent->dtsn = rpl_dio_buf->dtsn; + recv_rpl_DIS_mode(); } -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 < (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 + 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); - -} - -void recv_rpl_dao(void) -{ - DEBUGF("Received DAO with "); - rpl_dodag_t *my_dodag = rpl_get_my_dodag(); - - if (my_dodag == NULL) { - DEBUG("[Error] got DAO although not a DODAG\n"); - return; - } - - ipv6_buf = get_rpl_ipv6_buf(); - rpl_dao_buf = get_rpl_dao_buf(); - DEBUG("instance %04X ", rpl_dao_buf->rpl_instanceid); - DEBUG("sequence %04X\n", rpl_dao_buf->dao_sequence); - - int len = DAO_BASE_LEN; - uint8_t increment_seq = 0; - - 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 + 2; - break; - } - - case (RPL_OPT_DAG_METRIC_CONTAINER): { - len += rpl_opt_buf->length + 2; - break; - } - - case (RPL_OPT_TARGET): { - rpl_opt_target_buf = get_rpl_opt_target_buf(len); - - if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { - DEBUGF("prefixes are not supported yet\n"); - break; - } - - len += rpl_opt_target_buf->length + 2; - rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); - - if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { - DEBUGF("[Error] - no transit information for target option type = %d\n", rpl_opt_transit_buf->type); - break; - } - - len += rpl_opt_transit_buf->length + 2; - /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ - - DEBUGF("%s, %d: Adding routing information: Target: %s, Source: %s, Lifetime: %u\n", - __FILE__, __LINE__, - ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_opt_target_buf->target), - ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->srcaddr), - (rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit)); - rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); - increment_seq = 1; - break; - } - - case (RPL_OPT_TRANSIT): { - len += rpl_opt_buf->length + 2; - break; - } - - case (RPL_OPT_TARGET_DESC): { - len += rpl_opt_buf->length + 2; - break; - } - - default: - return; - } - } - - send_DAO_ACK(&ipv6_buf->srcaddr); - - if (increment_seq) { - RPL_COUNTER_INCREMENT(my_dodag->dao_seq); - delay_dao(); - } -} - -void recv_rpl_dao_ack(void) +void recv_rpl_DAO_ACK(void) { DEBUGF("DAO ACK received\n"); - rpl_dodag_t *my_dodag = rpl_get_my_dodag(); - - if (my_dodag == NULL) { - return; - } - - rpl_dao_ack_buf = get_rpl_dao_ack_buf(); - - if (rpl_dao_ack_buf->rpl_instanceid != my_dodag->instance->id) { - return; - } - - if (rpl_dao_ack_buf->status != 0) { - return; - } - - dao_ack_received(); + recv_rpl_dao_ack_mode(); } -void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header) -{ - uint8_t *p_ptr; - ipv6_send_buf = get_rpl_send_ipv6_buf(); - p_ptr = get_rpl_send_payload_buf(ipv6_ext_hdr_len); - uint16_t packet_length = 0; +/**************************************************************/ +/**************************************************************/ - ipv6_send_buf->version_trafficclass = IPV6_VER; - ipv6_send_buf->trafficclass_flowlabel = 0; - ipv6_send_buf->flowlabel = 0; - ipv6_send_buf->nextheader = next_header; - ipv6_send_buf->hoplimit = MULTIHOP_HOPLIMIT; - ipv6_send_buf->length = HTONS(p_len); - - memcpy(&(ipv6_send_buf->destaddr), destination, 16); - ipv6_net_if_get_best_src_addr(&(ipv6_send_buf->srcaddr), &(ipv6_send_buf->destaddr)); - - icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); - icmp_send_buf->checksum = icmpv6_csum(ipv6_send_buf, icmp_send_buf); - - /* The packet was "assembled" in rpl.c. Therefore rpl_send_buf was used. - * Therefore memcpy is not needed because the payload is at the - * right memory location already. */ - - if (p_ptr != payload) { - memcpy(p_ptr, payload, p_len); - } - - packet_length = IPV6_HDR_LEN + p_len; - - if (ipv6_addr_is_multicast(&ipv6_send_buf->destaddr)) { - ipv6_send_packet(ipv6_send_buf); - } - else { - /* find appropriate next hop before sending */ - ipv6_addr_t *next_hop = rpl_get_next_hop(&ipv6_send_buf->destaddr); - - if (next_hop == NULL) { - if (i_am_root) { - DEBUGF("[Error] destination unknown: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_send_buf->destaddr)); - return; - } - else { - next_hop = rpl_get_my_preferred_parent(); - - if (next_hop == NULL) { - DEBUGF("[Error] no preferred parent, dropping package\n"); - return; - } - } - } - - ipv6_send_packet(ipv6_send_buf); - } - - (void) packet_length; -} +/******************************************************************************/ +/* Routing related functions are obsolete and will be replaced in near future */ +/******************************************************************************/ 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 (routing_table[i].used) { - DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &routing_table[i].address)); + 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 (routing_table[i].used && rpl_equal_id(&routing_table[i].address, addr)) { - DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &routing_table[i].next_hop)); - return &routing_table[i].next_hop; + 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; } } @@ -1014,11 +261,11 @@ void rpl_add_routing_entry(ipv6_addr_t *addr, ipv6_addr_t *next_hop, uint16_t li } for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) { - if (!routing_table[i].used) { - memcpy(&routing_table[i].address, addr, sizeof(ipv6_addr_t)); - memcpy(&routing_table[i].next_hop, next_hop, sizeof(ipv6_addr_t)); - routing_table[i].lifetime = lifetime; - routing_table[i].used = 1; + if (!rpl_routing_table[i].used) { + memcpy(&rpl_routing_table[i].address, addr, sizeof(ipv6_addr_t)); + memcpy(&rpl_routing_table[i].next_hop, next_hop, sizeof(ipv6_addr_t)); + rpl_routing_table[i].lifetime = lifetime; + rpl_routing_table[i].used = 1; break; } } @@ -1027,8 +274,8 @@ void rpl_add_routing_entry(ipv6_addr_t *addr, ipv6_addr_t *next_hop, uint16_t li 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])); + 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; } } @@ -1037,8 +284,8 @@ void rpl_del_routing_entry(ipv6_addr_t *addr) 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]; + if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) { + return &rpl_routing_table[i]; } } @@ -1048,12 +295,15 @@ rpl_routing_entry_t *rpl_find_routing_entry(ipv6_addr_t *addr) void rpl_clear_routing_table(void) { for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) { - memset(&routing_table[i], 0, sizeof(routing_table[i])); + memset(&rpl_routing_table[i], 0, sizeof(rpl_routing_table[i])); } } rpl_routing_entry_t *rpl_get_routing_table(void) { - return routing_table; + return rpl_routing_table; } + +/******************************************************************************/ +/******************************************************************************/ diff --git a/sys/net/routing/rpl/rpl.h b/sys/net/routing/rpl/rpl.h index 7ab6ef1a9d..680694e3a3 100644 --- a/sys/net/routing/rpl/rpl.h +++ b/sys/net/routing/rpl/rpl.h @@ -10,12 +10,18 @@ * @defgroup net_rpl RPL * @ingroup net * @brief Routing Protocol for Low power and Lossy Networks + * + * Header which includes all core RPL-functions. Normally it shouldn't be necessary to + * modify this file. + * * @{ * * @file rpl.h - * @brief RPL header + * @brief RPL header. Declaration of global variables and functions needed for + * core functionality of RPL. * - * @author Eric Engel + * @author Eric Engel + * @author Fabian Brandt */ #ifndef __RPL_H @@ -35,25 +41,224 @@ #define RPL_PKT_RECV_BUF_SIZE 16 #define RPL_PROCESS_STACKSIZE KERNEL_CONF_STACKSIZE_DEFAULT +/* global variables */ +extern rpl_of_t *rpl_objective_functions[NUMBER_IMPLEMENTED_OFS]; +extern rpl_routing_entry_t rpl_routing_table[RPL_MAX_ROUTING_ENTRIES]; +extern unsigned int rpl_process_pid; + +/* needed for receiving messages with ICMP-code 155. Received via IPC from ipv6.c */ +extern mutex_t rpl_recv_mutex; + +/* needed for sending RPL-messages */ +extern mutex_t rpl_send_mutex; + +extern msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE]; +extern char rpl_process_buf[RPL_PROCESS_STACKSIZE]; +extern uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN]; + +/** + * @brief Initialization of RPL. + * + * This function initializes all basic RPL resources such as mutex for send/receive, + * corresponding objective functions and sixlowpan (including own address). Calls + * initialization for mode as specified by PL_DEFAULT_MOP in rpl_structs.h. + * + * @param[in] if_id ID of the interface, which correspond to the network under RPL-control + * + * @return 1 if initialization was successful + * @return 0 if initialization was not successful + * + */ uint8_t rpl_init(int if_id); -void rpl_init_root(void); + +/** + * @brief Get entry point for default objective function. + * + * This function is obsolete in rpl.h and will be moved shortly. + * + * @param[in] ocp Objective code point for desired objective function + * + * @return Implementation of objective function + * + * */ rpl_of_t *rpl_get_of_for_ocp(uint16_t ocp); +/** + * @brief Initialization of RPL-root. + * + * This function initializes all RPL resources to act as a root node. + * Because the root has different features in different modes, the core + * initialization just calls the root-initialization of the chosen mode + * + */ +void rpl_init_root(void); + +/** + * @brief Sends a DIO-message to a given destination + * + * This function sends a DIO message to a given destination. Because nodes can act + * differently in different modes, this function just sets the mutex and call the DIO + * sending function of the chosen mode. + * + * @param[in] destination IPv6-address of the destination of the DIO. Should be a direct neighbor. + * + */ void send_DIO(ipv6_addr_t *destination); -void send_DIS(ipv6_addr_t *destination); + +/** + * @brief Sends a DAO-message to a given destination + * + * This function sends a DAO message to a given destination. Because nodes can act + * differently in different modes, this function just sets the mutex and call the DAO + * sending function of the chosen mode. + * + * @param[in] destination IPv6-address of the destination of the DAO. Should be the preferred parent. + * @param[in] lifetime Lifetime of the node. Reflect the estimated time of presence in the network. + * @param[in] default_lifetime If true, param lifetime is ignored and lifetime is dodag default-lifetime + * @param[in] start_index Describes whether a DAO must be split because of too many routing entries. + * + */ void send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index); + +/** + * @brief Sends a DIS-message to a given destination + * + * This function sends a DIS message to a given destination or multicast-address. Because nodes can act + * differently in different modes, this function just sets the mutex and call the DIS + * sending function of the chosen mode. + * + * @param[in] destination IPv6-address of the destination of the DIS. Should be a direct neighbor or multicast-address. + * + */ +void send_DIS(ipv6_addr_t *destination); + +/** + * @brief Sends a DAO acknowledgment-message to a given destination + * + * This function sends a DAO_ACK message to a given destination. Because nodes can act + * differently in different modes, this function just sets the mutex and call the DAO_ACK + * sending function of the chosen mode. + * + * @param[in] destination IPv6-address of the destination of the DAO_ACK. Should be a direct neighbor. + * + */ void send_DAO_ACK(ipv6_addr_t *destination); + +/** + * @brief Receives a DIO message + * + * This function handles receiving a DIO message. Because nodes can act differently in different modes, + * this function just calls the receiving function of the chosen mode. + * + */ +void recv_rpl_DIO(void); + +/** + * @brief Receives a DAO message + * + * This function handles receiving a DAO message. Because nodes can act differently in different modes, + * this function just calls the receiving function of the chosen mode. + * + */ +void recv_rpl_DAO(void); + +/** + * @brief Receives a DIS message + * + * This function handles receiving a DIS message. Because nodes can act differently in different modes, + * this function just calls the receiving function of the chosen mode. + * + */ +void recv_rpl_DIS(void); + +/** + * @brief Receives a DAO acknowledgment message + * + * This function handles receiving a DAO_ACK message. Because nodes can act differently in different modes, + * this function just calls the receiving function of the chosen mode. + * + */ +void recv_rpl_DAO_ACK(void); + +/** + * @brief Initialization of RPl-root. + * + * This function initializes all RPL resources especially for root purposes. + * corresponding objective functions and sixlowpan (including own address). It also register mutexes for + * sending and receiving RPL-based messages. Both are necessary because of parallel access from different + * layers/modules of RIOT. May change with future structure changes. + * + */ void rpl_process(void); -void recv_rpl_dio(void); -void recv_rpl_dis(void); -void recv_rpl_dao(void); -void recv_rpl_dao_ack(void); -void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header); + +/** + * @brief Returns next hop from routing table. + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * @param[in] addr Destination address + * + * @return Next hop address + * + * */ ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr); + +/** + * @brief Adds routing entry to routing table + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * @param[in] addr Destination address + * @param[in] next_hop Next hop address + * @param[in] lifetime Lifetime of the entry + * + * */ void rpl_add_routing_entry(ipv6_addr_t *addr, ipv6_addr_t *next_hop, uint16_t lifetime); + +/** + * @brief Deletes routing entry to routing table + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * @param[in] addr Destination address + * + * */ void rpl_del_routing_entry(ipv6_addr_t *addr); + +/** + * @brief Finds routing entry for a given destination. + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * @param[in] addr Destination address + * + * @return Routing entry address + * + * */ rpl_routing_entry_t *rpl_find_routing_entry(ipv6_addr_t *addr); + +/** + * @brief Clears routing table. + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * */ void rpl_clear_routing_table(void); + +/** + * @brief Returns routing table + * + * @deprecated This function is obsolete and will be removed shortly. This will be replaced with a + * common routing information base. + * + * @return Routing table + * + * */ rpl_routing_entry_t *rpl_get_routing_table(void); /** @} */ diff --git a/sys/net/routing/rpl/rpl_config.h b/sys/net/routing/rpl/rpl_config.h index f4b4695b09..5f659145ef 100644 --- a/sys/net/routing/rpl/rpl_config.h +++ b/sys/net/routing/rpl/rpl_config.h @@ -19,10 +19,10 @@ #define RPL_CONFIG_H_INCLUDED /* Default values */ -#define NO_DOWNWARD_ROUTES 0x00 -#define NON_STORING_MODE 0x01 -#define STORING_MODE_NO_MC 0x02 -#define STORING_MODE_MC 0x03 +#define RPL_NO_DOWNWARD_ROUTES 0x00 +#define RPL_NON_STORING_MODE 0x01 +#define RPL_STORING_MODE_NO_MC 0x02 +#define RPL_STORING_MODE_MC 0x03 /* ICMP type */ #define RPL_SEQUENCE_WINDOW 16 @@ -92,7 +92,7 @@ static inline bool RPL_COUNTER_GREATER_THAN(uint8_t A,uint8_t B) /* RPL Constants and Variables */ -#define RPL_DEFAULT_MOP STORING_MODE_NO_MC +#define RPL_DEFAULT_MOP RPL_STORING_MODE_NO_MC #define BASE_RANK 0 #define INFINITE_RANK 0xFFFF #define RPL_DEFAULT_INSTANCE 0 diff --git a/sys/net/routing/rpl/rpl_dodag.c b/sys/net/routing/rpl/rpl_dodag.c index dc82eec46e..2e72c3640c 100644 --- a/sys/net/routing/rpl/rpl_dodag.c +++ b/sys/net/routing/rpl/rpl_dodag.c @@ -267,14 +267,14 @@ rpl_parent_t *rpl_find_preferred_parent(void) } if (!rpl_equal_id(&my_dodag->my_preferred_parent->addr, &best->addr)) { - if (my_dodag->mop != NO_DOWNWARD_ROUTES) { + if (my_dodag->mop != RPL_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) { + if (my_dodag->mop != RPL_NO_DOWNWARD_ROUTES) { delay_dao(); } diff --git a/sys/net/routing/rpl/rpl_storing.c b/sys/net/routing/rpl/rpl_storing.c new file mode 100644 index 0000000000..2dafbca46a --- /dev/null +++ b/sys/net/routing/rpl/rpl_storing.c @@ -0,0 +1,855 @@ +/** + * RPL storing mode implementation + * + * Copyright (C) 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + * + * @ingroup rpl + * @{ + * @file rpl_storing.c + * @brief RPL Storing mode functions + * @author Fabian Brandt + * @} + */ + +#include "rpl_storing.h" +#include "msg.h" +#include "trickle.h" + +#include "sixlowpan.h" +#include "net_help.h" + +#define ENABLE_DEBUG (0) +#if ENABLE_DEBUG +#undef TRICKLE_TIMER_STACKSIZE +#define DEBUG_ENABLED +char addr_str[IPV6_MAX_ADDR_STR_LEN]; +#endif +#include "debug.h" + +/* global variables */ +char i_am_root = 0; +ipv6_addr_t my_address; + +/* in send buffer we need space fpr LL_HDR */ +uint8_t rpl_send_buffer[BUFFER_SIZE]; + +/* SEND BUFFERS */ +static icmpv6_hdr_t *icmp_send_buf; +static struct rpl_dis_t *rpl_send_dis_buf; +static struct rpl_dao_ack_t *rpl_send_dao_ack_buf; +static ipv6_hdr_t *ipv6_send_buf; +static struct rpl_dio_t *rpl_send_dio_buf; +static struct rpl_dao_t *rpl_send_dao_buf; +static rpl_opt_dodag_conf_t *rpl_send_opt_dodag_conf_buf; +static rpl_opt_target_t *rpl_send_opt_target_buf; +static rpl_opt_transit_t *rpl_send_opt_transit_buf; + +/* RECEIVE BUFFERS */ +ipv6_hdr_t *ipv6_buf; +static struct rpl_dio_t *rpl_dio_buf; +static struct rpl_dao_t *rpl_dao_buf; +static struct rpl_dao_ack_t *rpl_dao_ack_buf; +static rpl_opt_dodag_conf_t *rpl_opt_dodag_conf_buf; +static rpl_opt_target_t *rpl_opt_target_buf; +static rpl_opt_transit_t *rpl_opt_transit_buf; +static struct rpl_dis_t *rpl_dis_buf; +static rpl_opt_t *rpl_opt_buf; +static rpl_opt_solicited_t *rpl_opt_solicited_buf; + +/* SEND BUFFERS */ +static icmpv6_hdr_t *get_rpl_send_icmpv6_buf(uint8_t ext_len) +{ + return ((icmpv6_hdr_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ext_len])); +} + +static struct rpl_dao_ack_t *get_rpl_send_dao_ack_buf(void) +{ + return ((struct rpl_dao_ack_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static struct rpl_dis_t *get_rpl_send_dis_buf(void) +{ + return ((struct rpl_dis_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static ipv6_hdr_t *get_rpl_send_ipv6_buf(void) +{ + return ((ipv6_hdr_t *) & (rpl_send_buffer[0])); +} + +static uint8_t *get_rpl_send_payload_buf(uint8_t ext_len) +{ + return &(rpl_send_buffer[IPV6_HDR_LEN + ext_len]); +} + +static struct rpl_dio_t *get_rpl_send_dio_buf(void) +{ + return ((struct rpl_dio_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static struct rpl_dao_t *get_rpl_send_dao_buf(void) +{ + return ((struct rpl_dao_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static rpl_opt_dodag_conf_t *get_rpl_send_opt_dodag_conf_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_dodag_conf_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static rpl_opt_target_t *get_rpl_send_opt_target_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_target_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static rpl_opt_transit_t *get_rpl_send_opt_transit_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_transit_t *) & (rpl_send_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + + +/* RECEIVE BUFFERS */ +static ipv6_hdr_t *get_rpl_ipv6_buf(void) +{ + return ((ipv6_hdr_t *) & (rpl_buffer[0])); +} + +static rpl_opt_target_t *get_rpl_opt_target_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_target_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static rpl_opt_transit_t *get_rpl_opt_transit_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_transit_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static rpl_opt_dodag_conf_t *get_rpl_opt_dodag_conf_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_dodag_conf_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static struct rpl_dio_t *get_rpl_dio_buf(void) +{ + return ((struct rpl_dio_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static struct rpl_dao_t *get_rpl_dao_buf(void) +{ + return ((struct rpl_dao_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static struct rpl_dao_ack_t *get_rpl_dao_ack_buf(void) +{ + return ((struct rpl_dao_ack_t *) & (buffer[(LL_HDR_LEN + IPV6_HDR_LEN + ICMPV6_HDR_LEN)])); +} + +static struct rpl_dis_t *get_rpl_dis_buf(void) +{ + return ((struct rpl_dis_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN])); +} + +static rpl_opt_t *get_rpl_opt_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +static rpl_opt_solicited_t *get_rpl_opt_solicited_buf(uint8_t rpl_msg_len) +{ + return ((rpl_opt_solicited_t *) & (rpl_buffer[IPV6_HDR_LEN + ICMPV6_HDR_LEN + rpl_msg_len])); +} + +void rpl_init_mode(ipv6_addr_t *init_address) +{ + memcpy(&my_address, init_address, sizeof(ipv6_addr_t)); +} + +void rpl_init_root_mode(void) +{ + rpl_instance_t *inst; + rpl_dodag_t *dodag; + + inst = rpl_new_instance(RPL_DEFAULT_INSTANCE); + + if (inst == NULL) { + DEBUGF("Error - No memory for another RPL instance\n"); + return; + } + + inst->id = RPL_DEFAULT_INSTANCE; + inst->joined = 1; + + dodag = rpl_new_dodag(RPL_DEFAULT_INSTANCE, &my_address); + + if (dodag != NULL) { + dodag->of = (struct rpl_of_t *) rpl_get_of_for_ocp(RPL_DEFAULT_OCP); + dodag->instance = inst; + dodag->mop = RPL_DEFAULT_MOP; + dodag->dtsn = 1; + dodag->prf = 0; + dodag->dio_interval_doubling = DEFAULT_DIO_INTERVAL_DOUBLINGS; + dodag->dio_min = DEFAULT_DIO_INTERVAL_MIN; + dodag->dio_redundancy = DEFAULT_DIO_REDUNDANCY_CONSTANT; + dodag->maxrankincrease = 0; + dodag->minhoprankincrease = (uint16_t)DEFAULT_MIN_HOP_RANK_INCREASE; + dodag->default_lifetime = (uint8_t)RPL_DEFAULT_LIFETIME; + dodag->lifetime_unit = RPL_LIFETIME_UNIT; + dodag->version = RPL_COUNTER_INIT; + dodag->grounded = RPL_GROUNDED; + dodag->node_status = (uint8_t) ROOT_NODE; + dodag->my_rank = RPL_ROOT_RANK; + dodag->joined = 1; + dodag->my_preferred_parent = NULL; + } + else { + DEBUGF("Error - could not generate DODAG\n"); + return; + } + + i_am_root = 1; + start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy); + DEBUGF("ROOT INIT FINISHED\n"); + +} + +void send_DIO_mode(ipv6_addr_t *destination) +{ + rpl_dodag_t *mydodag; + icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); + + mydodag = rpl_get_my_dodag(); + + if (mydodag == NULL) { + DEBUGF("Error - trying to send DIO without being part of a dodag.\n"); + return; + } + + icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; + icmp_send_buf->code = ICMP_CODE_DIO; + + rpl_send_dio_buf = get_rpl_send_dio_buf(); + memset(rpl_send_dio_buf, 0, sizeof(*rpl_send_dio_buf)); + + DEBUGF("Sending DIO with "); + rpl_send_dio_buf->rpl_instanceid = mydodag->instance->id; + DEBUG("instance %02X ", rpl_send_dio_buf->rpl_instanceid); + rpl_send_dio_buf->version_number = mydodag->version; + rpl_send_dio_buf->rank = mydodag->my_rank; + DEBUG("rank %04X\n", rpl_send_dio_buf->rank); + rpl_send_dio_buf->g_mop_prf = (mydodag->grounded << RPL_GROUNDED_SHIFT) | (mydodag->mop << RPL_MOP_SHIFT) | mydodag->prf; + rpl_send_dio_buf->dtsn = mydodag->dtsn; + rpl_send_dio_buf->flags = 0; + rpl_send_dio_buf->reserved = 0; + rpl_send_dio_buf->dodagid = mydodag->dodag_id; + + int opt_hdr_len = 0; + /* DODAG configuration option */ + rpl_send_opt_dodag_conf_buf = get_rpl_send_opt_dodag_conf_buf(DIO_BASE_LEN); + rpl_send_opt_dodag_conf_buf->type = RPL_OPT_DODAG_CONF; + rpl_send_opt_dodag_conf_buf->length = RPL_OPT_DODAG_CONF_LEN; + rpl_send_opt_dodag_conf_buf->flags_a_pcs = 0; + rpl_send_opt_dodag_conf_buf->DIOIntDoubl = mydodag->dio_interval_doubling; + rpl_send_opt_dodag_conf_buf->DIOIntMin = mydodag->dio_min; + rpl_send_opt_dodag_conf_buf->DIORedun = mydodag->dio_redundancy; + rpl_send_opt_dodag_conf_buf->MaxRankIncrease = mydodag->maxrankincrease; + rpl_send_opt_dodag_conf_buf->MinHopRankIncrease = mydodag->minhoprankincrease; + rpl_send_opt_dodag_conf_buf->ocp = mydodag->of->ocp; + rpl_send_opt_dodag_conf_buf->reserved = 0; + rpl_send_opt_dodag_conf_buf->default_lifetime = mydodag->default_lifetime; + rpl_send_opt_dodag_conf_buf->lifetime_unit = mydodag->lifetime_unit; + + opt_hdr_len += RPL_OPT_LEN + RPL_OPT_DODAG_CONF_LEN; + + uint16_t plen = ICMPV6_HDR_LEN + DIO_BASE_LEN + opt_hdr_len; + rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); +} + +void send_DAO_mode(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index) +{ + if (i_am_root) { + return; + } + + rpl_dodag_t *my_dodag; + + if ((my_dodag = rpl_get_my_dodag()) == NULL) { + DEBUGF("send_DAO: I have no my_dodag\n"); + return; + } + + if (destination == NULL) { + if (my_dodag->my_preferred_parent == NULL) { + DEBUGF("send_DAO: my_dodag has no my_preferred_parent\n"); + return; + } + + destination = &my_dodag->my_preferred_parent->addr; + } + + if (default_lifetime) { + lifetime = my_dodag->default_lifetime; + } + + icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); + + icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; + icmp_send_buf->code = ICMP_CODE_DAO; + + rpl_send_dao_buf = get_rpl_send_dao_buf(); + memset(rpl_send_dao_buf, 0, sizeof(*rpl_send_dao_buf)); + rpl_send_dao_buf->rpl_instanceid = my_dodag->instance->id; + rpl_send_dao_buf->k_d_flags = 0x00; + rpl_send_dao_buf->dao_sequence = my_dodag->dao_seq; + uint16_t opt_len = 0; + rpl_send_opt_target_buf = get_rpl_send_opt_target_buf(DAO_BASE_LEN); + /* add all targets from routing table as targets */ + uint8_t entries = 0; + uint8_t continue_index = 0; + + for (uint8_t i = start_index; i < RPL_MAX_ROUTING_ENTRIES; i++) { + if (rpl_get_routing_table()[i].used) { + rpl_send_opt_target_buf->type = RPL_OPT_TARGET; + rpl_send_opt_target_buf->length = RPL_OPT_TARGET_LEN; + rpl_send_opt_target_buf->flags = 0x00; + rpl_send_opt_target_buf->prefix_length = RPL_DODAG_ID_LEN; + memcpy(&rpl_send_opt_target_buf->target, &rpl_get_routing_table()[i].address, sizeof(ipv6_addr_t)); + opt_len += RPL_OPT_TARGET_LEN + 2; + rpl_send_opt_transit_buf = get_rpl_send_opt_transit_buf(DAO_BASE_LEN + opt_len); + rpl_send_opt_transit_buf->type = RPL_OPT_TRANSIT; + rpl_send_opt_transit_buf->length = RPL_OPT_TRANSIT_LEN; + rpl_send_opt_transit_buf->e_flags = 0x00; + rpl_send_opt_transit_buf->path_control = 0x00; /* not used */ + rpl_send_opt_transit_buf->path_sequence = 0x00; /* not used */ + rpl_send_opt_transit_buf->path_lifetime = lifetime; + opt_len += RPL_OPT_TRANSIT_LEN + 2; + rpl_send_opt_target_buf = get_rpl_send_opt_target_buf(DAO_BASE_LEN + opt_len); + entries++; + } + + /* Split DAO, so packages don't get too big. + * The value 5 is based on experience. */ + if (entries >= 5) { + continue_index = i + 1; + break; + } + } + + /* add own address */ + rpl_send_opt_target_buf->type = RPL_OPT_TARGET; + rpl_send_opt_target_buf->length = RPL_OPT_TARGET_LEN; + rpl_send_opt_target_buf->flags = 0x00; + rpl_send_opt_target_buf->prefix_length = RPL_DODAG_ID_LEN; + memcpy(&rpl_send_opt_target_buf->target, &my_address, sizeof(ipv6_addr_t)); + opt_len += RPL_OPT_TARGET_LEN + 2; + + rpl_send_opt_transit_buf = get_rpl_send_opt_transit_buf(DAO_BASE_LEN + opt_len); + rpl_send_opt_transit_buf->type = RPL_OPT_TRANSIT; + rpl_send_opt_transit_buf->length = RPL_OPT_TRANSIT_LEN; + rpl_send_opt_transit_buf->e_flags = 0x00; + rpl_send_opt_transit_buf->path_control = 0x00; + rpl_send_opt_transit_buf->path_sequence = 0x00; + rpl_send_opt_transit_buf->path_lifetime = lifetime; + opt_len += RPL_OPT_TRANSIT_LEN + 2; + + uint16_t plen = ICMPV6_HDR_LEN + DAO_BASE_LEN + opt_len; + rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); + + if (continue_index > 1) { + send_DAO(destination, lifetime, default_lifetime, continue_index); + } +} + +void send_DIS_mode(ipv6_addr_t *destination) +{ + icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); + + icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; + icmp_send_buf->code = ICMP_CODE_DIS; + + rpl_send_dis_buf = get_rpl_send_dis_buf(); + + uint16_t plen = ICMPV6_HDR_LEN + DIS_BASE_LEN; + rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); +} + +void send_DAO_ACK_mode(ipv6_addr_t *destination) +{ + rpl_dodag_t *my_dodag; + my_dodag = rpl_get_my_dodag(); + + if (my_dodag == NULL) { + return; + } + + icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); + + icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL; + icmp_send_buf->code = ICMP_CODE_DAO_ACK; + + rpl_send_dao_ack_buf = get_rpl_send_dao_ack_buf(); + rpl_send_dao_ack_buf->rpl_instanceid = my_dodag->instance->id; + rpl_send_dao_ack_buf->d_reserved = 0; + rpl_send_dao_ack_buf->dao_sequence = my_dodag->dao_seq; + rpl_send_dao_ack_buf->status = 0; + + uint16_t plen = ICMPV6_HDR_LEN + DAO_ACK_LEN; + rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6); +} + +void recv_rpl_DIO_mode(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", 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 + 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) { + 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 = 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: + DEBUGF("[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) { + DEBUGF("send DIS\n"); + send_DIS(&ipv6_buf->srcaddr); + } + + if (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 (rpl_dio_buf->rank != INFINITE_RANK) { + DEBUGF("Will join DODAG\n"); + rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, 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); + reset_trickletimer(); + } + else { + DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent...\n"); + 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 (my_dodag->my_preferred_parent == NULL) { + DEBUG("%s, %d: my dodag has no preferred_parent yet - seems to be odd since I have a parent...\n", __FILE__, __LINE__); + } + else 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; + +} + +void recv_rpl_DAO_mode(void) +{ + rpl_dodag_t *my_dodag = rpl_get_my_dodag(); + + if (my_dodag == NULL) { + DEBUG("[Error] got DAO although not a DODAG\n"); + return; + } + + ipv6_buf = get_rpl_ipv6_buf(); + rpl_dao_buf = get_rpl_dao_buf(); + DEBUG("instance %04X ", rpl_dao_buf->rpl_instanceid); + DEBUG("sequence %04X\n", rpl_dao_buf->dao_sequence); + + int len = DAO_BASE_LEN; + uint8_t increment_seq = 0; + + 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 + 2; + break; + } + + case (RPL_OPT_DAG_METRIC_CONTAINER): { + len += rpl_opt_buf->length + 2; + break; + } + + case (RPL_OPT_TARGET): { + rpl_opt_target_buf = get_rpl_opt_target_buf(len); + + if (rpl_opt_target_buf->prefix_length != RPL_DODAG_ID_LEN) { + DEBUGF("prefixes are not supported yet\n"); + break; + } + + len += rpl_opt_target_buf->length + 2; + rpl_opt_transit_buf = get_rpl_opt_transit_buf(len); + + if (rpl_opt_transit_buf->type != RPL_OPT_TRANSIT) { + DEBUGF("[Error] - no transit information for target option type = %d\n", rpl_opt_transit_buf->type); + break; + } + + len += rpl_opt_transit_buf->length + 2; + /* route lifetime seconds = (DAO lifetime) * (Unit Lifetime) */ + + DEBUG("Adding routing information: Target: %s, Source: %s, Lifetime: %u\n", + ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_opt_target_buf->target), + ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->srcaddr), + (rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit)); + rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); + increment_seq = 1; + break; + } + + case (RPL_OPT_TRANSIT): { + len += rpl_opt_buf->length + 2; + break; + } + + case (RPL_OPT_TARGET_DESC): { + len += rpl_opt_buf->length + 2; + break; + } + + default: + return; + } + } + + send_DAO_ACK(&ipv6_buf->srcaddr); + + if (increment_seq) { + RPL_COUNTER_INCREMENT(my_dodag->dao_seq); + delay_dao(); + } +} + +void recv_rpl_DIS_mode(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 < (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 + 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); + +} + +void recv_rpl_dao_ack_mode(void) +{ + rpl_dodag_t *my_dodag = rpl_get_my_dodag(); + + if (my_dodag == NULL) { + return; + } + + rpl_dao_ack_buf = get_rpl_dao_ack_buf(); + + if (rpl_dao_ack_buf->rpl_instanceid != my_dodag->instance->id) { + return; + } + + if (rpl_dao_ack_buf->status != 0) { + return; + } + + dao_ack_received(); + +} + +/* obligatory for each mode. normally not modified */ +void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header) +{ + uint8_t *p_ptr; + ipv6_send_buf = get_rpl_send_ipv6_buf(); + p_ptr = get_rpl_send_payload_buf(ipv6_ext_hdr_len); + + ipv6_send_buf->version_trafficclass = IPV6_VER; + ipv6_send_buf->trafficclass_flowlabel = 0; + ipv6_send_buf->flowlabel = 0; + ipv6_send_buf->nextheader = next_header; + ipv6_send_buf->hoplimit = MULTIHOP_HOPLIMIT; + ipv6_send_buf->length = HTONS(p_len); + + memcpy(&(ipv6_send_buf->destaddr), destination, 16); + ipv6_net_if_get_best_src_addr(&(ipv6_send_buf->srcaddr), &(ipv6_send_buf->destaddr)); + + icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len); + icmp_send_buf->checksum = icmpv6_csum(ipv6_send_buf, icmp_send_buf); + + /* The packet was "assembled" in rpl_%mode%.c. Therefore rpl_send_buf was used. + * Therefore memcpy is not needed because the payload is at the + * right memory location already. */ + + if (p_ptr != payload) { + memcpy(p_ptr, payload, p_len); + } + + if (ipv6_addr_is_multicast(&ipv6_send_buf->destaddr)) { + ipv6_send_packet(ipv6_send_buf); + } + else { + /* find appropriate next hop before sending */ + ipv6_addr_t *next_hop = rpl_get_next_hop(&ipv6_send_buf->destaddr); + + if (next_hop == NULL) { + if (i_am_root) { + DEBUGF("[Error] destination unknown: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_send_buf->destaddr)); + return; + } + else { + next_hop = rpl_get_my_preferred_parent(); + + if (next_hop == NULL) { + DEBUGF("[Error] no preferred parent, dropping package\n"); + return; + } + } + } + + ipv6_send_packet(ipv6_send_buf); + } + +} diff --git a/sys/net/routing/rpl/rpl_storing.h b/sys/net/routing/rpl/rpl_storing.h new file mode 100644 index 0000000000..63ec276a4e --- /dev/null +++ b/sys/net/routing/rpl/rpl_storing.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup net_rpl RPL + * @ingroup net + * @brief Routing Protocol for Low power and Lossy Networks + * + * Header which includes all mode related RPL-functions. All functions are mandatory for any + * RPL-mode. Describes receiving and sending of all RPL-related messages and special initialization behavior. + * + * @{ + * + * @file rpl_mode.h + * @brief RPL storing-mode header + * + * @author Eric Engel + * @author Fabian Brandt + */ + +#ifndef __RPL_SM_H +#define __RPL_SM_H + +#include "rpl_structs.h" +#include "rpl_config.h" +#include "rpl.h" + +/** + * @brief Initialization of RPL-root. + * + * This function initializes all RPL resources especially for root purposes. Initializes a new DODAG and sets + * itself as root. Starts trickle-timer so sending DIOs starts and other can join the DODAG. + * + */ +void rpl_init_root_mode(void); + +/** + * @brief Initialization of RPL storing mode. + * + * This function initializes all basic RPL mode resources. For this mode this includes only acquiring the own + * address. + * + * @param[in] my_ipv6_address Own IPv6 address as assigned by RPL core-initialization. + * + */ +void rpl_init_mode(ipv6_addr_t *my_ipv6_address); + +/** + * @brief Sends a DIO-message to a given destination + * + * This function sends a DIO message to a given destination. This is triggered by the trickle-timer. + * + * @param[in] destination IPv6-address of the destination of the DIO. Should be a direct neighbor or multicast address. + * + */ +void send_DIO_mode(ipv6_addr_t *destination); + +/** + * @brief Sends a DAO-message to a given destination + * + * This function sends a DAO message to a given destination. + * + * @param[in] destination IPv6-address of the destination of the DAO. Should be the proffered parent. + * @param[in] lifetime Lifetime of the node. Reflect the estimated time of presence in the network. + * @param[in] default_lifetime If true, param lifetime is ignored and lifetime is DODAG default-lifetime + * @param[in] start_index Describes whether a DAO must be split because of too many routing entries. + * + */ +void send_DAO_mode(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index); + +/** + * @brief Sends a DIS-message to a given destination + * + * This function sends a DIS message to a given destination. + * + * @param[in] destination IPv6-address of the destination of the DIS. Should be a direct neighbor. + * + */ +void send_DIS_mode(ipv6_addr_t *destination); + +/** + * @brief Sends a DAO acknowledgment-message to a given destination + * + * This function sends a DAO_ACK message to a given destination. + * + * @param[in] destination IPv6-address of the destination of the DAO_ACK. Should be a direct neighbor. + * + */ +void send_DAO_ACK_mode(ipv6_addr_t *destination); + +/** + * @brief Receives a DIO message + * + * This function handles receiving a DIO message in any mode . + * + */ +void recv_rpl_DIO_mode(void); + +/** + * @brief Receives a DAO message + * + * This function handles receiving a DAO message in any mode. + * + */ +void recv_rpl_DAO_mode(void); + +/** + * @brief Receives a DIS message + * + * This function handles receiving a DIS message in any mode. + * + */ +void recv_rpl_DIS_mode(void); + +/** + * @brief Receives a DAO acknowledgment message + * + * This function handles receiving a DAO_ACK message in any mode. + * + */ +void recv_rpl_dao_ack_mode(void); + +/** + * @brief Sends a RPL message to a given destination + * + * This function sends any RPl related messages to a given destination. This implementation should be equal + * for all modes and therefore should not be altered. Every mode related RPL-sending function calls this for + * relaying it in lower layers to sixlowpan. Because send-functions are wrapped by a mutex in rpl.c, the same + * mutex applies here. + * + * @param[in] destination IPv6-address of the destination of the message. + * @param[in] payload Payload of the message. + * @param[in] len Length of the message + * @param[in] next_header Index to next header in message. + * + */ +void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header); + +#endif /* __RPL_SM_H */ +/** @} */