void *beaconing(void *arg) { (void) arg; xtimer_t status_timer; msg_t msg; msg_t update_msg; kernel_pid_t mypid = thread_getpid(); /* initialize message queue */ msg_init_queue(_beac_msg_q, Q_SZ); /* start periodic timer */ update_msg.type = MSG_UPDATE_EVENT; xtimer_set_msg(&status_timer, UPDATE_INTERVAL, &update_msg, mypid); while(1) { msg_receive(&msg); switch (msg.type) { case MSG_UPDATE_EVENT: xtimer_set_msg(&status_timer, UPDATE_INTERVAL, &update_msg, mypid); send_update(initial_pos, p_buf); break; default: break; } } /* never reached */ return NULL; }
/* start sending beacons */ void beaconing_start(void) { uint8_t remaining_beacons = DOW_BEACONING_COUNT; bool end_beaconing = false; /* register for RX */ gnrc_netreg_entry_t _ne; _ne.target.pid = sched_active_pid; _ne.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL; gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &_ne); /* schedule beacon */ msg_t beacon_msg; beacon_msg.type = DOW_MSG_BEACON; xtimer_t beacon_timer; beacon_timer.target = beacon_timer.long_target = 0; /* let's delay the first beacon by DOW_BEACONING_WAIT */ uint32_t tmp = DOW_BEACONING_PERIOD + DOW_BEACONING_WAIT; xtimer_set_msg(&beacon_timer, tmp, &beacon_msg, sched_active_pid); tmp -= DOW_BEACONING_WAIT; uint32_t start = xtimer_now().ticks32; while (1) { msg_t m; msg_receive(&m); switch (m.type) { case DOW_MSG_BEACON: LOG_DEBUG("beaconing: ready to send next beacon\n"); beaconing_send(); tmp = DOW_BEACONING_PERIOD; /* check if we need to do further beaconing */ if (--remaining_beacons > 0) { xtimer_set_msg(&beacon_timer, tmp, &beacon_msg, sched_active_pid); } else { beacon_msg.type = DOW_MSG_BEACON_END; tmp = 2 * DOW_BEACONING_WAIT - (xtimer_now().ticks32 - start); LOG_INFO("beaconing: end beaconing period in %" PRIu32 \ " seconds\n", (tmp / US_PER_SEC)); xtimer_set_msg(&beacon_timer, tmp, &beacon_msg, sched_active_pid); } break; case DOW_MSG_BEACON_END: LOG_INFO("beaconing: end beaconing\n"); end_beaconing = true; break; case GNRC_NETAPI_MSG_TYPE_RCV: LOG_DEBUG("beaconing: received packet, assume that it is a beacon\n"); _handle_beacon((gnrc_pktsnip_t *)m.content.ptr); break; default: LOG_WARNING("beaconing: didn't expect message type %X\n", m.type); break; } if (end_beaconing) { break; } } gnrc_netreg_unregister(GNRC_NETTYPE_UNDEF, &_ne); }
kernel_pid_t gnrc_rpl_init(kernel_pid_t if_pid) { /* check if RPL was initialized before */ if (gnrc_rpl_pid == KERNEL_PID_UNDEF) { _instance_id = 0; /* start the event loop */ gnrc_rpl_pid = thread_create(_stack, sizeof(_stack), GNRC_RPL_PRIO, THREAD_CREATE_STACKTEST, _event_loop, NULL, "RPL"); if (gnrc_rpl_pid == KERNEL_PID_UNDEF) { DEBUG("RPL: could not start the event loop\n"); return KERNEL_PID_UNDEF; } _me_reg.demux_ctx = ICMPV6_RPL_CTRL; _me_reg.target.pid = gnrc_rpl_pid; /* register interest in all ICMPv6 packets */ gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_reg); gnrc_rpl_of_manager_init(); xtimer_set_msg(&_lt_timer, _lt_time, &_lt_msg, gnrc_rpl_pid); #ifdef MODULE_NETSTATS_RPL memset(&gnrc_rpl_netstats, 0, sizeof(gnrc_rpl_netstats)); #endif } /* register all_RPL_nodes multicast address */ gnrc_ipv6_netif_add_addr(if_pid, &ipv6_addr_all_rpl_nodes, IPV6_ADDR_BIT_LEN, 0); gnrc_rpl_send_DIS(NULL, (ipv6_addr_t *) &ipv6_addr_all_rpl_nodes); return gnrc_rpl_pid; }
/** * @brief Sends @ref GNRC_NETAPI_MSG_TYPE_SND delayed. * * @param[in] t Timer for the delay. * @param[in] msg Msg for the timer. * @param[in] interval Delay interval. * @param[in] pkt Packet to send delayed. */ static inline void _send_delayed(xtimer_t *t, msg_t *msg, uint32_t interval, gnrc_pktsnip_t *pkt) { xtimer_remove(t); msg->type = GNRC_NETAPI_MSG_TYPE_SND; msg->content.ptr = (char *) pkt; xtimer_set_msg(t, interval, msg, gnrc_ipv6_pid); }
int main(void) { gnrc_netreg_entry_t ne; uint8_t cpuid[CPUID_LEN]; cpuid_get(cpuid); conn_test_id = djb2_hash(cpuid, CPUID_LEN); random_init(conn_test_id); ne.pid = thread_create(_stack, sizeof(_stack), THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, _listener, NULL, "listener"); ne.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL; gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &ne); puts("Connectivity Test program!"); printf("MY ID: %08lX\n", (unsigned long) conn_test_id); unsigned res = CONN_TEST_CHAN; if (gnrc_netapi_set(CONN_TEST_NETIF, NETOPT_CHANNEL, 0, (uint16_t *)&res, sizeof(uint16_t)) < 0) { puts("main: error setting channel"); } unsigned int addr_len = 8; if (gnrc_netapi_set(CONN_TEST_NETIF, NETOPT_SRC_LEN, 0, (uint16_t *)&addr_len, sizeof(uint16_t)) < 0) { printf("main: error setting addressing mode\n"); } xtimer_set_msg(&ct_timer, (SEC_IN_USEC * 3) + (random_uint32() & 0x001FFFFF), &ct_m, ne.pid); char line_buf[SHELL_DEFAULT_BUFSIZE]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); return 0; }
/* router-only functions from net/gnrc/sixlowpan/nd.h */ void gnrc_sixlowpan_nd_opt_abr_handle(kernel_pid_t iface, ndp_rtr_adv_t *rtr_adv, int sicmpv6_size, sixlowpan_nd_opt_abr_t *abr_opt) { uint16_t opt_offset = 0; uint8_t *buf = (uint8_t *)(rtr_adv + 1); gnrc_sixlowpan_nd_router_abr_t *abr; timex_t t = { 0, 0 }; if (_is_me(&abr_opt->braddr)) { return; } /* validity and version was checked in previously called * gnrc_sixlowpan_nd_router_abr_older() */ abr = _get_abr(&abr_opt->braddr); if (abr == NULL) { return; } abr->ltime = byteorder_ntohs(abr_opt->ltime); if (abr->ltime == 0) { abr->ltime = GNRC_SIXLOWPAN_ND_BORDER_ROUTER_DEFAULT_LTIME; return; } sicmpv6_size -= sizeof(ndp_rtr_adv_t); while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_PI: _add_prefix(iface, abr, (ndp_opt_pi_t *)opt); case NDP_OPT_6CTX: _add_ctx(abr, (sixlowpan_nd_opt_6ctx_t *)opt); default: break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } abr->version = (uint32_t)byteorder_ntohs(abr_opt->vlow); abr->version |= ((uint32_t)byteorder_ntohs(abr_opt->vhigh)) << 16; abr->addr.u64[0] = abr_opt->braddr.u64[0]; abr->addr.u64[1] = abr_opt->braddr.u64[1]; memset(abr->ctxs, 0, sizeof(abr->ctxs)); abr->prfs = NULL; t.seconds = abr->ltime * 60; xtimer_remove(&abr->ltimer); abr->ltimer_msg.type = GNRC_SIXLOWPAN_ND_MSG_ABR_TIMEOUT; abr->ltimer_msg.content.ptr = (char *) abr; xtimer_set_msg(&abr->ltimer, (uint32_t) timex_uint64(t), &abr->ltimer_msg, gnrc_ipv6_pid); }
static inline void _reschedule_rtr_sol(gnrc_ipv6_netif_t *iface, uint32_t delay) { xtimer_remove(&iface->rtr_sol_timer); iface->rtr_sol_msg.type = GNRC_NDP_MSG_RTR_SOL_RETRANS; iface->rtr_sol_msg.content.ptr = iface; xtimer_set_msg(&iface->rtr_sol_timer, delay, &iface->rtr_sol_msg, gnrc_ipv6_pid); }
kernel_pid_t gnrc_rpl_init(kernel_pid_t if_pid) { /* check if RPL was initialized before */ if (gnrc_rpl_pid == KERNEL_PID_UNDEF) { /* start the event loop */ gnrc_rpl_pid = thread_create(_stack, sizeof(_stack), GNRC_RPL_PRIO, CREATE_STACKTEST, _event_loop, NULL, "RPL"); if (gnrc_rpl_pid == KERNEL_PID_UNDEF) { DEBUG("RPL: could not start the event loop\n"); return KERNEL_PID_UNDEF; } _me_reg.demux_ctx = ICMPV6_RPL_CTRL; _me_reg.pid = gnrc_rpl_pid; /* register interest in all ICMPv6 packets */ gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_reg); gnrc_rpl_of_manager_init(); xtimer_set_msg(&_lt_timer, _lt_time, &_lt_msg, gnrc_rpl_pid); } /* register all_RPL_nodes multicast address */ ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR; gnrc_ipv6_netif_add_addr(if_pid, &all_RPL_nodes, IPV6_ADDR_BIT_LEN, 0); gnrc_rpl_send_DIS(NULL, &all_RPL_nodes); return gnrc_rpl_pid; }
static inline void _rtr_sol_reschedule(gnrc_ipv6_netif_t *iface, uint32_t sec_delay) { xtimer_remove(&iface->rtr_sol_timer); iface->rtr_sol_msg.type = GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL; iface->rtr_sol_msg.content.ptr = (char *) iface; xtimer_set_msg(&iface->rtr_sol_timer, sec_delay * SEC_IN_USEC, &iface->rtr_sol_msg, gnrc_ipv6_pid); }
/** * @brief Restarts timewait timer. * * @param[in,out] tcb TCB holding the timer struct to reset. * * @return Zero on success. */ static int _restart_timewait_timer(gnrc_tcp_tcb_t *tcb) { xtimer_remove(&tcb->tim_tout); tcb->msg_tout.type = MSG_TYPE_TIMEWAIT; tcb->msg_tout.content.ptr = (void *)tcb; xtimer_set_msg(&tcb->tim_tout, 2 * GNRC_TCP_MSL, &tcb->msg_tout, gnrc_tcp_pid); return 0; }
void gnrc_sixlowpan_nd_rtr_sol_reschedule(gnrc_ipv6_nc_t *nce, uint32_t sec_delay) { assert(nce != NULL); assert(sec_delay != 0U); gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(nce->iface); xtimer_remove(&iface->rtr_sol_timer); iface->rtr_sol_msg.type = GNRC_SIXLOWPAN_ND_MSG_MC_RTR_SOL; iface->rtr_sol_msg.content.ptr = (char *) iface; xtimer_set_msg(&iface->rtr_sol_timer, sec_delay * SEC_IN_USEC, &iface->rtr_sol_msg, gnrc_ipv6_pid); }
void _update_lifetime(void) { uint32_t now = xtimer_now(); uint16_t now_sec = now / SEC_IN_USEC; gnrc_rpl_parent_t *parent; gnrc_rpl_instance_t *inst; for (uint8_t i = 0; i < GNRC_RPL_PARENTS_NUMOF; ++i) { parent = &gnrc_rpl_parents[i]; if (parent->state != 0) { if ((int32_t)(parent->lifetime - now_sec) <= GNRC_RPL_LIFETIME_UPDATE_STEP) { gnrc_rpl_dodag_t *dodag = parent->dodag; gnrc_rpl_parent_remove(parent); gnrc_rpl_parent_update(dodag, NULL); continue; } else if ((int32_t)(parent->lifetime - now_sec) <= (GNRC_RPL_LIFETIME_UPDATE_STEP * 2)) { gnrc_rpl_send_DIS(parent->dodag->instance, &parent->addr); } } } for (int i = 0; i < GNRC_RPL_INSTANCES_NUMOF; ++i) { inst = &gnrc_rpl_instances[i]; if (inst->state != 0) { if ((inst->cleanup > 0) && (inst->dodag.parents == NULL) && (inst->dodag.my_rank == GNRC_RPL_INFINITE_RANK)) { inst->cleanup -= GNRC_RPL_LIFETIME_UPDATE_STEP; if (inst->cleanup <= 0) { /* no parents - delete this instance and DODAG */ gnrc_rpl_instance_remove(inst); continue; } } if (inst->dodag.dao_time > GNRC_RPL_LIFETIME_UPDATE_STEP) { inst->dodag.dao_time -= GNRC_RPL_LIFETIME_UPDATE_STEP; } else { _dao_handle_send(&inst->dodag); } } } #ifdef MODULE_GNRC_RPL_P2P gnrc_rpl_p2p_update(); #endif xtimer_set_msg(&_lt_timer, _lt_time, &_lt_msg, gnrc_rpl_pid); }
void gnrc_gomach_set_timeout(gnrc_netif_t *netif, gnrc_gomach_timeout_type_t type, uint32_t offset) { assert(netif); gnrc_gomach_timeout_t *timeout; if ((timeout = _gomach_acquire_timeout(netif, type))) { timeout->expired = false; timeout->msg.type = GNRC_GOMACH_EVENT_TIMEOUT_TYPE; timeout->msg.content.ptr = (void *) timeout; xtimer_set_msg(&(timeout->timer), offset, &(timeout->msg), netif->pid); } else { DEBUG("[GoMacH]: Cannot set timeout, too many concurrent timeouts\n"); } }
int main(void) { msg_t m, tmsg; xtimer_t t; int64_t offset = -1000; tmsg.type = 44; for (int i = 0; i < 10; i++) { xtimer_set_msg(&t, SEC_IN_USEC + offset, &tmsg, sched_active_pid); if (xtimer_msg_receive_timeout(&m, SEC_IN_USEC) < 0) { puts("Timeout!"); } else { printf("Message received: %" PRIu16 "\n", m.type); } offset = (offset < 0) ? 1000 : -1000; } return 0; }
/* sets an entry to stale if its l2addr differs from the given one or creates it stale if it * does not exist */ static void _stale_nc(kernel_pid_t iface, ipv6_addr_t *ipaddr, uint8_t *l2addr, int l2addr_len) { if (l2addr_len != -ENOTSUP) { gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, ipaddr); if (nc_entry == NULL) { #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* tentative type see https://tools.ietf.org/html/rfc6775#section-6.3 */ gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); if ((ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { if ((nc_entry = gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len, GNRC_IPV6_NC_STATE_STALE | GNRC_IPV6_NC_TYPE_TENTATIVE)) != NULL) { xtimer_set_msg(&nc_entry->type_timeout, (GNRC_SIXLOWPAN_ND_TENTATIVE_NCE_LIFETIME * SEC_IN_USEC), &nc_entry->type_timeout_msg, gnrc_ipv6_pid); } return; } #endif gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len, GNRC_IPV6_NC_STATE_STALE); } #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* unreachable set in gnrc_ndp_retrans_nbr_sol() will just be staled */ else if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_UNREACHABLE) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } #endif else if (((uint16_t)l2addr_len != nc_entry->l2_addr_len) || (memcmp(l2addr, nc_entry->l2_addr, l2addr_len) != 0)) { /* if entry exists but l2 address differs: set */ nc_entry->l2_addr_len = (uint16_t)l2addr_len; memcpy(nc_entry->l2_addr, l2addr, l2addr_len); gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } } }
void gnrc_lwmac_set_timeout(gnrc_netif_t *netif, gnrc_lwmac_timeout_type_t type, uint32_t offset) { assert(netif); gnrc_lwmac_timeout_t *timeout; if ((timeout = _lwmac_acquire_timeout(netif, type))) { DEBUG("[LWMAC] Set timeout %s in %" PRIu32 " us\n", lwmac_timeout_names[type], offset); timeout->expired = false; timeout->msg.type = GNRC_LWMAC_EVENT_TIMEOUT_TYPE; timeout->msg.content.ptr = (void *) timeout; xtimer_set_msg(&(timeout->timer), offset, &(timeout->msg), netif->pid); } else { DEBUG("[LWMAC] Cannot set timeout %s, too many concurrent timeouts\n", lwmac_timeout_names[type]); } }
static void _send_rtr_adv(gnrc_ipv6_netif_t *iface, ipv6_addr_t *dst) { bool fin; uint32_t interval; mutex_lock(&iface->mutex); fin = (iface->adv_ltime == 0); assert((iface->min_adv_int != 0) && (iface->max_adv_int != 0)); interval = genrand_uint32_range(iface->min_adv_int, iface->max_adv_int); if (!fin && !((iface->flags | GNRC_IPV6_NETIF_FLAGS_ROUTER) && (iface->flags | GNRC_IPV6_NETIF_FLAGS_RTR_ADV))) { DEBUG("ndp rtr: interface %" PRIkernel_pid " is not an advertising interface\n", iface->pid); return; } if (iface->rtr_adv_count > 1) { /* regard for off-by-one error */ iface->rtr_adv_count--; if (!fin && (interval > GNRC_NDP_MAX_INIT_RTR_ADV_INT)) { interval = GNRC_NDP_MAX_INIT_RTR_ADV_INT; } } if (!fin || (iface->rtr_adv_count > 1)) { /* regard for off-by-one-error */ /* reset timer for next router advertisement */ xtimer_remove(&iface->rtr_adv_timer); iface->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS; iface->rtr_adv_msg.content.ptr = (char *) iface; xtimer_set_msg(&iface->rtr_adv_timer, interval * SEC_IN_USEC, &iface->rtr_adv_msg, gnrc_ipv6_pid); } mutex_unlock(&iface->mutex); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { ipv6_addr_t *src = &iface->addrs[i].addr; if (!ipv6_addr_is_unspecified(src) && ipv6_addr_is_link_local(src) && !gnrc_ipv6_netif_addr_is_non_unicast(src)) { /* send one for every link local address (ideally there is only one) */ gnrc_ndp_internal_send_rtr_adv(iface->pid, src, dst, fin); } } }
static void *_listener(void *unused) { msg_init_queue(_listener_mq, 8); msg_t msg; while (1) { msg_receive(&msg); gnrc_pktsnip_t *snip = NULL; switch (msg.type) { case GNRC_NETAPI_MSG_TYPE_RCV: { gnrc_pktsnip_t *pkt = (gnrc_pktsnip_t *)msg.content.ptr; snip = pkt; while (snip != NULL) { if (snip->type == GNRC_NETTYPE_NETIF) { //gnrc_netif_hdr_print(snip->data); } else if (snip->type == GNRC_NETTYPE_UNDEF) { printf("ID: %08lX\n", (unsigned long) ((conn_test_payload_t*)snip->data)->id); } snip = snip->next; } gnrc_pktbuf_release(pkt); break; } case CONN_TEST_SEND: _send(0, NULL); xtimer_set_msg(&ct_timer, (SEC_IN_USEC * 3) + (random_uint32() & 0x001FFFFF), &ct_m, sched_active_pid); break; default: puts("UNEXPECTED MESSAGE TYPE!"); } } return NULL; }
void _update_lifetime(void) { uint64_t now = xtimer_now64(); gnrc_rpl_parent_t *parent; for (uint8_t i = 0; i < GNRC_RPL_PARENTS_NUMOF; ++i) { parent = &gnrc_rpl_parents[i]; if (parent->state != 0) { if ((int64_t)(parent->lifetime - now) <= (int64_t) (GNRC_RPL_LIFETIME_UPDATE_STEP * SEC_IN_USEC)) { gnrc_rpl_dodag_t *dodag = parent->dodag; gnrc_rpl_parent_remove(parent); gnrc_rpl_parent_update(dodag, NULL); continue; } else if ((int64_t)(parent->lifetime - now) <= (int64_t) (GNRC_RPL_LIFETIME_UPDATE_STEP * SEC_IN_USEC * 2)) { gnrc_rpl_send_DIS(parent->dodag, &parent->addr); } } } xtimer_set_msg(&_lt_timer, _lt_time, &_lt_msg, gnrc_rpl_pid); }
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type, ipv6_addr_t *addr, sixlowpan_nd_opt_ar_t *ar_opt, uint8_t *sl2a, size_t sl2a_len) { eui64_t eui64; gnrc_ipv6_netif_t *ipv6_iface; gnrc_ipv6_nc_t *nc_entry; uint8_t status = 0; (void)sl2a; (void)sl2a_len; if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } if (gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, &eui64, sizeof(eui64)) < 0) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } ipv6_iface = gnrc_ipv6_netif_get(iface); nc_entry = gnrc_ipv6_nc_get(iface, addr); switch (icmpv6_type) { case ICMPV6_NBR_ADV: if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { DEBUG("6lo nd: interface not a 6LoWPAN interface\n"); return 0; } if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) { /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */ return 0; } /* we expect the sender to be already in neighbor cache, if not we * ignore it */ if (nc_entry == NULL) { DEBUG("6lo nd: sending router not in neighbor cache\n"); return 0; } switch (ar_opt->status) { case SIXLOWPAN_ND_STATUS_SUCCESS: DEBUG("6lo nd: address registration successful\n"); mutex_lock(&ipv6_iface->mutex); /* reschedule 1 minute before lifetime expires */ gnrc_ndp_internal_reset_nbr_sol_timer(nc_entry, SEC_IN_USEC * 60 * (uint32_t)(byteorder_ntohs(ar_opt->ltime) -1), GNRC_NDP_MSG_NBR_SOL_RETRANS, gnrc_ipv6_pid); mutex_unlock(&ipv6_iface->mutex); break; case SIXLOWPAN_ND_STATUS_DUP: DEBUG("6lo nd: address registration determined duplicated\n"); /* TODO: handle DAD failed case */ gnrc_ipv6_netif_remove_addr(iface, &ipv6->dst); /* address should not be used anymore */ break; case SIXLOWPAN_ND_STATUS_NC_FULL: DEBUG("6lo nd: neighbor cache on router is full\n"); gnrc_ipv6_nc_remove(iface, &ipv6->src); /* try to find another router */ gnrc_sixlowpan_nd_init(ipv6_iface); break; default: DEBUG("6lo nd: unknown status for registration received\n"); break; } break; #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER case ICMPV6_NBR_SOL: if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && !(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) { DEBUG("6lo nd: interface not a 6LoWPAN or forwarding interface\n"); return 0; } if ((ar_opt->status != 0) || ipv6_addr_is_unspecified(&ipv6->src)) { /* discard silently */ return 0; } /* TODO multihop DAD */ if ((nc_entry != NULL) && ((gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) && ((nc_entry->eui64.uint64.u64 != 0) && (ar_opt->eui64.uint64.u64 != nc_entry->eui64.uint64.u64))) { /* there is already another node with this address */ DEBUG("6lo nd: duplicate address detected\n"); status = SIXLOWPAN_ND_STATUS_DUP; } else if ((nc_entry != NULL) && (ar_opt->ltime.u16 == 0)) { gnrc_ipv6_nc_remove(iface, &ipv6->src); /* TODO, notify routing protocol */ } else if (ar_opt->ltime.u16 != 0) { /* TODO: multihop DAD behavior */ uint16_t reg_ltime; if (nc_entry == NULL) { if ((nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len, GNRC_IPV6_NC_STATE_STALE)) == NULL) { DEBUG("6lo nd: neighbor cache is full\n"); return SIXLOWPAN_ND_STATUS_NC_FULL; } nc_entry->eui64 = ar_opt->eui64; } nc_entry->flags &= ~GNRC_IPV6_NC_TYPE_MASK; nc_entry->flags |= GNRC_IPV6_NC_TYPE_REGISTERED; reg_ltime = byteorder_ntohs(ar_opt->ltime); /* TODO: notify routing protocol */ xtimer_set_msg(&nc_entry->type_timeout, (reg_ltime * 60 * SEC_IN_USEC), &nc_entry->type_timeout_msg, gnrc_ipv6_pid); } break; #endif default: break; } return status; }
tftp_state _tftp_send(gnrc_pktsnip_t *buf, tftp_context_t *ctxt, size_t len) { network_uint16_t src_port, dst_port; gnrc_pktsnip_t *udp, *ip; assert(len <= TFTP_DEFAULT_DATA_SIZE); /* down-size the packet to it's used size */ if (len > TFTP_DEFAULT_DATA_SIZE) { DEBUG("tftp: can't reallocate to bigger packet, buffer overflowed\n"); gnrc_pktbuf_release(buf); if (ctxt->stop_cb) { ctxt->stop_cb(TFTP_INTERN_ERROR, "buffer overflowed"); } return TS_FAILED; } else if (gnrc_pktbuf_realloc_data(buf, len) != 0) { assert(false); DEBUG("tftp: failed to reallocate data snippet\n"); gnrc_pktbuf_release(buf); /* inform the user that we can't reallocate */ if (ctxt->stop_cb) { ctxt->stop_cb(TFTP_INTERN_ERROR, "no reallocate"); } return TS_FAILED; } /* allocate UDP header, set source port := destination port */ src_port.u16 = ctxt->src_port; dst_port.u16 = ctxt->dst_port; udp = gnrc_udp_hdr_build(buf, src_port.u16, dst_port.u16); if (udp == NULL) { DEBUG("tftp: error unable to allocate UDP header\n"); gnrc_pktbuf_release(buf); if (ctxt->stop_cb) { ctxt->stop_cb(TFTP_INTERN_ERROR, "no udp allocate"); } return TS_FAILED; } /* allocate IPv6 header */ ip = gnrc_ipv6_hdr_build(udp, NULL, &(ctxt->peer)); if (ip == NULL) { DEBUG("tftp: error unable to allocate IPv6 header\n"); gnrc_pktbuf_release(udp); if (ctxt->stop_cb) { ctxt->stop_cb(TFTP_INTERN_ERROR, "no ip allocate"); } return TS_FAILED; } /* send packet */ if (gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip) == 0) { /* if send failed inform the user */ DEBUG("tftp: error unable to locate UDP thread\n"); gnrc_pktbuf_release(ip); if (ctxt->stop_cb) { ctxt->stop_cb(TFTP_INTERN_ERROR, "no dispatch send"); } return TS_FAILED; } /* only set timeout if enabled for this block */ if (ctxt->block_timeout) { ctxt->timer_msg.type = TFTP_TIMEOUT_MSG; xtimer_set_msg(&(ctxt->timer), ctxt->block_timeout, &(ctxt->timer_msg), thread_getpid()); DEBUG("tftp: set timeout %" PRIu32 " ms\n", ctxt->block_timeout / MS_IN_USEC); } return TS_BUSY; }
bool gnrc_ndp_internal_pi_opt_handle(kernel_pid_t iface, uint8_t icmpv6_type, ndp_opt_pi_t *pi_opt) { ipv6_addr_t *prefix; gnrc_ipv6_netif_addr_t *netif_addr; if ((pi_opt->len != NDP_OPT_PI_LEN)) { DEBUG("ndp: invalid PI option received\n"); return false; } if (icmpv6_type != ICMPV6_RTR_ADV || ipv6_addr_is_link_local(&pi_opt->prefix)) { /* else discard silently */ return true; } #ifdef MODULE_GNRC_SIXLOWPAN_ND if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (pi_opt->flags & NDP_OPT_PI_FLAGS_L)) { /* ignore: see https://tools.ietf.org/html/rfc6775#section-5.4 */ return true; } #endif prefix = gnrc_ipv6_netif_find_addr(iface, &pi_opt->prefix); if (((prefix == NULL) || (gnrc_ipv6_netif_addr_get(prefix)->prefix_len != pi_opt->prefix_len)) && (pi_opt->valid_ltime.u32 != 0)) { ipv6_addr_t pref_addr; if ((gnrc_netapi_get(iface, NETOPT_IPV6_IID, 0, &pref_addr.u64[1], sizeof(eui64_t)) < 0)) { DEBUG("ndp: could not get IID from interface %d\n", iface); return false; } ipv6_addr_init_prefix(&pref_addr, &pi_opt->prefix, pi_opt->prefix_len); prefix = gnrc_ipv6_netif_add_addr(iface, &pref_addr, pi_opt->prefix_len, pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); if (prefix == NULL) { DEBUG("ndp: could not add prefix to interface %d\n", iface); return false; } #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER gnrc_sixlowpan_nd_router_set_rtr_adv(gnrc_ipv6_netif_get(iface), true); #endif } netif_addr = gnrc_ipv6_netif_addr_get(prefix); if (pi_opt->valid_ltime.u32 == 0) { if (prefix != NULL) { gnrc_ipv6_netif_remove_addr(iface, &netif_addr->addr); } return true; } netif_addr->valid = byteorder_ntohl(pi_opt->valid_ltime); netif_addr->preferred = byteorder_ntohl(pi_opt->pref_ltime); if (netif_addr->valid != UINT32_MAX) { xtimer_set_msg(&netif_addr->valid_timeout, (byteorder_ntohl(pi_opt->valid_ltime) * SEC_IN_USEC), &netif_addr->valid_timeout_msg, thread_getpid()); } /* TODO: preferred lifetime for address auto configuration */ /* on-link flag MUST stay set if it was */ netif_addr->flags &= ~NDP_OPT_PI_FLAGS_A; netif_addr->flags |= (pi_opt->flags & NDP_OPT_PI_FLAGS_MASK); return true; }
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size) { uint8_t *buf = (uint8_t *)(rtr_adv + 1); gnrc_ipv6_nc_t *nc_entry = NULL; gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; #ifdef MODULE_GNRC_SIXLOWPAN_ND uint32_t next_rtr_sol = 0; #endif int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; uint16_t opt_offset = 0; if (!ipv6_addr_is_link_local(&ipv6->src) || ipv6_addr_is_multicast(&ipv6->src) || (ipv6->hl != 255) || (rtr_adv->code != 0) || (icmpv6_size < sizeof(ndp_rtr_adv_t))) { DEBUG("ndp: router advertisement was invalid\n"); /* ipv6 releases */ return; } /* get source from default router list */ nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); if (nc_entry == NULL) { /* not in default router list */ /* create default router list entry */ nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0, GNRC_IPV6_NC_IS_ROUTER); if (nc_entry == NULL) { DEBUG("ndp: error on default router list entry creation\n"); return; } } else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } /* set router life timer */ if (rtr_adv->ltime.u16 != 0) { uint16_t ltime = byteorder_ntohs(rtr_adv->ltime); #ifdef MODULE_GNRC_SIXLOWPAN_ND next_rtr_sol = ltime; #endif xtimer_set_msg(&nc_entry->rtr_timeout, (ltime * SEC_IN_USEC), &nc_entry->rtr_timeout_msg, thread_getpid()); } /* set current hop limit from message if available */ if (rtr_adv->cur_hl != 0) { if_entry->cur_hl = rtr_adv->cur_hl; } /* set flags from message */ if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) & GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK; /* set reachable time from message if it is not the same as the random base * value */ if ((rtr_adv->reach_time.u32 != 0) && (if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) { _set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time)); } /* set retransmission timer from message */ if (rtr_adv->retrans_timer.u32 != 0) { if_entry->retrans_timer = timex_set(0, byteorder_ntohl(rtr_adv->retrans_timer)); timex_normalize(&if_entry->retrans_timer); } mutex_unlock(&if_entry->mutex); sicmpv6_size -= sizeof(ndp_rtr_adv_t); /* parse options */ while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_SL2A: if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt, l2src)) < 0) { /* -ENOTSUP can not happen */ /* invalid source link-layer address option */ return; } break; case NDP_OPT_MTU: if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) { /* invalid MTU option */ return; } break; case NDP_OPT_PI: if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) { /* invalid prefix information option */ return; } #ifdef MODULE_GNRC_SIXLOWPAN_ND uint32_t valid_ltime = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime); if ((valid_ltime != 0) && (valid_ltime < next_rtr_sol)) { next_rtr_sol = valid_ltime; } #endif break; #ifdef MODULE_GNRC_SIXLOWPAN_ND case NDP_OPT_6CTX: if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type, (sixlowpan_nd_opt_6ctx_t *)opt)) { /* invalid 6LoWPAN context option */ return; } uint16_t ltime = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime); if ((ltime != 0) && (ltime < (next_rtr_sol / 60))) { next_rtr_sol = ltime * 60; } break; #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER case NDP_OPT_ABR: gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size, (sixlowpan_nd_opt_abr_t *)opt); break; #endif } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); #if ENABLE_DEBUG if (sicmpv6_size < 0) { DEBUG("ndp: Option parsing out of sync.\n"); } #endif } #if ENABLE_DEBUG && defined(MODULE_GNRC_SIXLOWPAN_ND) if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) { DEBUG("ndp: Router advertisement did not contain any source address information\n"); } #endif _stale_nc(iface, &ipv6->src, l2src, l2src_len); /* stop multicast router solicitation retransmission timer */ xtimer_remove(&if_entry->rtr_sol_timer); #ifdef MODULE_GNRC_SIXLOWPAN_ND if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { /* 3/4 of the time should be "well before" enough the respective timeout * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */ next_rtr_sol *= 3; next_rtr_sol = (next_rtr_sol > 4) ? (next_rtr_sol >> 2) : 1; /* according to https://tools.ietf.org/html/rfc6775#section-5.3: * "In all cases, the RS retransmissions are terminated when an RA is * received." * Hence, reset router solicitation counter and reset timer. */ if_entry->rtr_sol_count = 0; gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol); gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr, &nc_entry->ipv6_addr); if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { gnrc_ipv6_netif_set_rtr_adv(if_entry, true); } }
void gnrc_ndp_rtr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_rtr_sol_t *rtr_sol, size_t icmpv6_size) { gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) { int sicmpv6_size = (int)icmpv6_size, l2src_len = 0; uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX]; uint16_t opt_offset = 0; uint8_t *buf = (uint8_t *)(rtr_sol + 1); /* check validity */ if ((ipv6->hl != 255) || (rtr_sol->code != 0) || (icmpv6_size < sizeof(ndp_rtr_sol_t))) { DEBUG("ndp: router solicitation was invalid\n"); return; } sicmpv6_size -= sizeof(ndp_rtr_sol_t); while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_SL2A: if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_sol->type, opt, l2src)) < 0) { /* -ENOTSUP can not happen */ /* invalid source link-layer address option */ return; } break; default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); #if ENABLE_DEBUG if (sicmpv6_size < 0) { DEBUG("ndp: Option parsing out of sync.\n"); } #endif } _stale_nc(iface, &ipv6->src, l2src, l2src_len); /* send delayed */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) { uint32_t delay; uint32_t ms = GNRC_NDP_MAX_RTR_ADV_DELAY; #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { ms = GNRC_SIXLOWPAN_ND_MAX_RTR_ADV_DELAY; } #endif delay = genrand_uint32_range(0, ms); xtimer_remove(&if_entry->rtr_adv_timer); #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* in case of a 6LBR we have to check if the interface is actually * the 6lo interface */ if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); if (nc_entry != NULL) { if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_SIXLOWPAN_DELAY; if_entry->rtr_adv_msg.content.ptr = (char *) nc_entry; xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg, gnrc_ipv6_pid); } } #elif defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER) if (ipv6_addr_is_unspecified(&ipv6->src)) { /* either multicast, if source unspecified */ if_entry->rtr_adv_msg.type = GNRC_NDP_MSG_RTR_ADV_RETRANS; if_entry->rtr_adv_msg.content.ptr = (char *) if_entry; xtimer_set_msg(&if_entry->rtr_adv_timer, delay, &if_entry->rtr_adv_msg, gnrc_ipv6_pid); } else { /* or unicast, if source is known */ /* XXX: can't just use GNRC_NETAPI_MSG_TYPE_SND, since the next retransmission * must also be set. */ gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src); xtimer_set_msg(&nc_entry->rtr_adv_timer, delay, &nc_entry->rtr_adv_msg, gnrc_ipv6_pid); } #endif } } /* otherwise ignore silently */ }
/* Event/Message loop for gcoap _pid thread. */ static void *_event_loop(void *arg) { msg_t msg_rcvd; (void)arg; msg_init_queue(_msg_queue, GCOAP_MSG_QUEUE_SIZE); sock_udp_ep_t local; memset(&local, 0, sizeof(sock_udp_ep_t)); local.family = AF_INET6; local.netif = SOCK_ADDR_ANY_NETIF; local.port = GCOAP_PORT; int res = sock_udp_create(&_sock, &local, NULL, 0); if (res < 0) { DEBUG("gcoap: cannot create sock: %d\n", res); return 0; } while(1) { res = msg_try_receive(&msg_rcvd); if (res > 0) { switch (msg_rcvd.type) { case GCOAP_MSG_TYPE_TIMEOUT: { gcoap_request_memo_t *memo = (gcoap_request_memo_t *)msg_rcvd.content.ptr; /* no retries remaining */ if ((memo->send_limit == GCOAP_SEND_LIMIT_NON) || (memo->send_limit == 0)) { _expire_request(memo); } /* reduce retries remaining, double timeout and resend */ else { memo->send_limit--; unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit; uint32_t timeout = ((uint32_t)COAP_ACK_TIMEOUT << i) * US_PER_SEC; uint32_t variance = ((uint32_t)COAP_ACK_VARIANCE << i) * US_PER_SEC; timeout = random_uint32_range(timeout, timeout + variance); ssize_t bytes = sock_udp_send(&_sock, memo->msg.data.pdu_buf, memo->msg.data.pdu_len, &memo->remote_ep); if (bytes > 0) { xtimer_set_msg(&memo->response_timer, timeout, &memo->timeout_msg, _pid); } else { DEBUG("gcoap: sock resend failed: %d\n", (int)bytes); _expire_request(memo); } } break; } default: break; } } _listen(&_sock); } return 0; }