gnrc_rpl_instance_t *gnrc_rpl_p2p_root_init(uint8_t instance_id, ipv6_addr_t *dodag_id, ipv6_addr_t *target, bool gen_inst_id) { if (gen_inst_id) { instance_id = gnrc_rpl_gen_instance_id(true); } gnrc_rpl_dodag_t *dodag = NULL; gnrc_rpl_instance_t *instance = gnrc_rpl_root_instance_init(instance_id, dodag_id, GNRC_RPL_P2P_MOP); if (!instance) { return NULL; } dodag = &instance->dodag; instance->max_rank_inc = 0; dodag->dtsn = 0; dodag->prf = 0; dodag->dio_interval_doubl = GNRC_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS; dodag->dio_min = GNRC_RPL_P2P_DEFAULT_DIO_INTERVAL_MIN; dodag->dio_redun = GNRC_RPL_P2P_DEFAULT_DIO_REDUNDANCY_CONSTANT; dodag->default_lifetime = GNRC_RPL_P2P_DEFAULT_LIFETIME; dodag->lifetime_unit = GNRC_RPL_P2P_LIFETIME_UNIT; dodag->version = 0; dodag->grounded = 1; dodag->node_status = GNRC_RPL_ROOT_NODE; dodag->my_rank = GNRC_RPL_ROOT_RANK; dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); p2p_ext->target = *target; p2p_ext->compr = GNRC_RPL_P2P_COMPR; p2p_ext->routes_numof = 0; p2p_ext->hop_by_hop = true; p2p_ext->reply = true; p2p_ext->lifetime_enc = GNRC_RPL_P2P_LIFETIME; p2p_ext->lifetime_sec = gnrc_rpl_p2p_lifetime_lookup[p2p_ext->lifetime_enc]; p2p_ext->maxrank = GNRC_RPL_P2P_MAX_RANK; p2p_ext->dro_delay = -1; trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_INTERVAL, GNRC_RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubl, dodag->dio_redun); return instance; }
/** @todo allow target prefixes in target options to be of variable length */ bool _parse_options(int msg_type, gnrc_rpl_instance_t *inst, gnrc_rpl_opt_t *opt, uint16_t len, ipv6_addr_t *src, uint32_t *included_opts) { uint16_t l = 0; gnrc_rpl_opt_target_t *first_target = NULL; gnrc_rpl_dodag_t *dodag = &inst->dodag; eui64_t iid; *included_opts = 0; ipv6_addr_t *me; if (!_gnrc_rpl_check_options_validity(msg_type, inst, opt, len)) { return false; } while(l < len) { switch(opt->type) { case (GNRC_RPL_OPT_PAD1): DEBUG("RPL: PAD1 option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PAD1; l += 1; opt = (gnrc_rpl_opt_t *) (((uint8_t *) opt) + 1); continue; case (GNRC_RPL_OPT_PADN): DEBUG("RPL: PADN option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PADN; break; case (GNRC_RPL_OPT_DODAG_CONF): DEBUG("RPL: DODAG CONF DIO option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_DODAG_CONF; dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; gnrc_rpl_opt_dodag_conf_t *dc = (gnrc_rpl_opt_dodag_conf_t *) opt; gnrc_rpl_of_t *of = gnrc_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp)); if (of != NULL) { inst->of = of; } else { DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp)); inst->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP); } dodag->dio_interval_doubl = dc->dio_int_doubl; dodag->dio_min = dc->dio_int_min; dodag->dio_redun = dc->dio_redun; inst->max_rank_inc = byteorder_ntohs(dc->max_rank_inc); inst->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc); dodag->default_lifetime = dc->default_lifetime; dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit); dodag->trickle.Imin = (1 << dodag->dio_min); dodag->trickle.Imax = dodag->dio_interval_doubl; dodag->trickle.k = dodag->dio_redun; break; case (GNRC_RPL_OPT_PREFIX_INFO): DEBUG("RPL: Prefix Information DIO option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_PREFIX_INFO; #ifndef GNRC_RPL_WITHOUT_PIO dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; #endif gnrc_rpl_opt_prefix_info_t *pi = (gnrc_rpl_opt_prefix_info_t *) opt; /* check for the auto address-configuration flag */ if ((gnrc_netapi_get(dodag->iface, NETOPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) < 0) && !(pi->LAR_flags & GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT)) { break; } ipv6_addr_set_aiid(&pi->prefix, iid.uint8); me = gnrc_ipv6_netif_add_addr(dodag->iface, &pi->prefix, pi->prefix_len, 0); if (me) { dodag->netif_addr = gnrc_ipv6_netif_addr_get(me); } break; case (GNRC_RPL_OPT_TARGET): DEBUG("RPL: RPL TARGET DAO option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TARGET; gnrc_rpl_opt_target_t *target = (gnrc_rpl_opt_target_t *) opt; if (first_target == NULL) { first_target = target; } uint32_t fib_dst_flags = 0; if (target->prefix_length < IPV6_ADDR_BIT_LEN) { fib_dst_flags = ((uint32_t)(target->prefix_length) << FIB_FLAG_NET_PREFIX_SHIFT); } DEBUG("RPL: adding fib entry %s/%d 0x%" PRIx32 "\n", ipv6_addr_to_str(addr_str, &(target->target), sizeof(addr_str)), target->prefix_length, fib_dst_flags); fib_add_entry(&gnrc_ipv6_fib_table, dodag->iface, target->target.u8, sizeof(ipv6_addr_t), fib_dst_flags, src->u8, sizeof(ipv6_addr_t), FIB_FLAG_RPL_ROUTE, (dodag->default_lifetime * dodag->lifetime_unit) * SEC_IN_MS); break; case (GNRC_RPL_OPT_TRANSIT): DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n"); *included_opts |= ((uint32_t) 1) << GNRC_RPL_OPT_TRANSIT; gnrc_rpl_opt_transit_t *transit = (gnrc_rpl_opt_transit_t *) opt; if (first_target == NULL) { DEBUG("RPL: Encountered a RPL TRANSIT DAO option without " "a preceding RPL TARGET DAO option\n"); break; } do { DEBUG("RPL: updating fib entry %s/%d\n", ipv6_addr_to_str(addr_str, &(first_target->target), sizeof(addr_str)), first_target->prefix_length); fib_update_entry(&gnrc_ipv6_fib_table, first_target->target.u8, sizeof(ipv6_addr_t), src->u8, sizeof(ipv6_addr_t), ((transit->e_flags & GNRC_RPL_OPT_TRANSIT_E_FLAG) ? 0x0 : FIB_FLAG_RPL_ROUTE), (transit->path_lifetime * dodag->lifetime_unit * SEC_IN_MS)); first_target = (gnrc_rpl_opt_target_t *) (((uint8_t *) (first_target)) + sizeof(gnrc_rpl_opt_t) + first_target->length); } while (first_target->type == GNRC_RPL_OPT_TARGET); first_target = NULL; break; #ifdef MODULE_GNRC_RPL_P2P case (GNRC_RPL_P2P_OPT_RDO): gnrc_rpl_p2p_rdo_parse((gnrc_rpl_p2p_opt_rdo_t *) opt, gnrc_rpl_p2p_ext_get(dodag)); break; #endif } l += opt->length + sizeof(gnrc_rpl_opt_t); opt = (gnrc_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length); } return true; }
void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src) { gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_mark(pkt, sizeof(icmpv6_hdr_t), GNRC_NETTYPE_ICMPV6); gnrc_pktsnip_t *dro_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_dro_t), GNRC_NETTYPE_UNDEF); gnrc_pktsnip_t *rdo_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_opt_rdo_t), GNRC_NETTYPE_UNDEF); gnrc_pktsnip_t *addr_snip = pkt; gnrc_rpl_instance_t *inst; gnrc_rpl_dodag_t *dodag; gnrc_rpl_p2p_ext_t *p2p_ext; gnrc_rpl_p2p_dro_t *dro; gnrc_rpl_p2p_opt_rdo_t *rdo; uint8_t *addr_vec; uint16_t flags; size_t addr_len; if (!rdo_snip || !dro_snip) { DEBUG("RPL-P2P: Error - No DRO or RDO received\n"); gnrc_pktbuf_release(pkt); return; } dro = dro_snip->data; if ((inst = gnrc_rpl_instance_get(dro->instance_id)) == NULL) { DEBUG("RPL-P2P: Error - Instance (%d) does not exist\n", dro->instance_id); return; } dodag = &inst->dodag; if ((p2p_ext = gnrc_rpl_p2p_ext_get(dodag)) == NULL) { DEBUG("RPL-P2P: Error - No P2P-RPL DODAG extension found\n"); return; } if (p2p_ext->for_me) { DEBUG("RPL-P2P: Ignore DRO\n"); return; } flags = byteorder_ntohs(dro->flags_rev); p2p_ext->stop = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_STOP)) >> GNRC_RPL_P2P_DRO_FLAGS_STOP; p2p_ext->dro_ack = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_ACK)) >> GNRC_RPL_P2P_DRO_FLAGS_ACK; p2p_ext->dro_seq = (flags & (0x3 << GNRC_RPL_P2P_DRO_FLAGS_SEQ)) >> GNRC_RPL_P2P_DRO_FLAGS_SEQ; addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr; ipv6_addr_t addr = p2p_ext->dodag->dodag_id; ipv6_addr_t *me = NULL; addr_vec = addr_snip->data; rdo = rdo_snip->data; if (rdo->lmn > 0) { rdo->lmn--; memcpy(&addr.u8[p2p_ext->compr], &addr_vec[addr_len * rdo->lmn], addr_len); } if (gnrc_ipv6_netif_find_by_addr(&me, &addr) == dodag->iface) { gnrc_ipv6_nib_ft_add(&p2p_ext->target, IPV6_ADDR_BIT_LEN, src, dodag->iface, p2p_ext->dodag->default_lifetime * p2p_ext->dodag->lifetime_unit); if (p2p_ext->dodag->node_status != GNRC_RPL_ROOT_NODE) { if ((rdo_snip = gnrc_pktbuf_start_write(rdo_snip)) == NULL) { DEBUG("RPL-P2P: Error - Cannot allocate new RDO\n"); return; } addr_snip->next = NULL; rdo_snip->next = addr_snip; dro_snip->next = rdo_snip; icmpv6_snip = gnrc_icmpv6_build(dro_snip, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO, sizeof(icmpv6_hdr_t)); if (icmpv6_snip == NULL) { DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } gnrc_rpl_send(icmpv6_snip, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id); return; } } gnrc_pktbuf_release(pkt); return; }
void gnrc_rpl_send_DIO(gnrc_rpl_instance_t *inst, ipv6_addr_t *destination) { if (inst == NULL) { DEBUG("RPL: Error - trying to send DIO without being part of a dodag.\n"); return; } gnrc_rpl_dodag_t *dodag = &inst->dodag; gnrc_pktsnip_t *pkt = NULL, *tmp; gnrc_rpl_dio_t *dio; #ifdef MODULE_GNRC_RPL_P2P gnrc_rpl_p2p_ext_t *p2p_ext = gnrc_rpl_p2p_ext_get(dodag); if (dodag->instance->mop == GNRC_RPL_P2P_MOP) { if (!p2p_ext->for_me) { if ((pkt = gnrc_rpl_p2p_rdo_build(pkt, p2p_ext)) == NULL) { return; } } dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; } #endif #ifndef GNRC_RPL_WITHOUT_PIO if (dodag->dio_opts & GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO) { if ((pkt = _dio_prefix_info_build(pkt, dodag)) == NULL) { return; } } #endif if (dodag->dio_opts & GNRC_RPL_REQ_DIO_OPT_DODAG_CONF) { if ((pkt = _dio_dodag_conf_build(pkt, dodag)) == NULL) { return; } dodag->dio_opts &= ~GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; } if ((tmp = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_rpl_dio_t), GNRC_NETTYPE_UNDEF)) == NULL) { DEBUG("RPL: Send DIO - no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } pkt = tmp; dio = pkt->data; dio->instance_id = inst->id; dio->version_number = dodag->version; /* a leaf node announces an INFINITE_RANK */ dio->rank = ((dodag->node_status == GNRC_RPL_LEAF_NODE) ? byteorder_htons(GNRC_RPL_INFINITE_RANK) : byteorder_htons(dodag->my_rank)); dio->g_mop_prf = (dodag->grounded << GNRC_RPL_GROUNDED_SHIFT) | (inst->mop << GNRC_RPL_MOP_SHIFT) | dodag->prf; dio->dtsn = dodag->dtsn; dio->flags = 0; dio->reserved = 0; dio->dodag_id = dodag->dodag_id; if ((tmp = gnrc_icmpv6_build(pkt, ICMPV6_RPL_CTRL, GNRC_RPL_ICMPV6_CODE_DIO, sizeof(icmpv6_hdr_t))) == NULL) { DEBUG("RPL: Send DIO - no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } pkt = tmp; gnrc_rpl_send(pkt, dodag->iface, NULL, destination, &dodag->dodag_id); }