/* Prepare and send a keepalive message */ static void keepalive_send() { if(tsch_is_associated) { struct tsch_neighbor *n = tsch_queue_get_time_source(); /* Simply send an empty packet */ packetbuf_clear(); packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &n->addr); NETSTACK_LLSEC.send(keepalive_packet_sent, NULL); PRINTF("TSCH: sending KA to %u\n", TSCH_LOG_ID_FROM_LINKADDR(&n->addr)); } }
/* Update TSCH time source */ int tsch_queue_update_time_source(const linkaddr_t *new_addr) { if(!tsch_is_locked()) { if(!tsch_is_coordinator) { struct tsch_neighbor *old_time_src = tsch_queue_get_time_source(); struct tsch_neighbor *new_time_src = NULL; if(new_addr != NULL) { /* Get/add neighbor, return 0 in case of failure */ new_time_src = tsch_queue_add_nbr(new_addr); if(new_time_src == NULL) { return 0; } } if(new_time_src != old_time_src) { PRINTF("TSCH: update time source: %u -> %u\n", TSCH_LOG_ID_FROM_LINKADDR(old_time_src ? &old_time_src->addr : NULL), TSCH_LOG_ID_FROM_LINKADDR(new_time_src ? &new_time_src->addr : NULL)); /* Update time source */ if(new_time_src != NULL) { new_time_src->is_time_source = 1; /* (Re)set keep-alive timeout */ tsch_set_ka_timeout(TSCH_KEEPALIVE_TIMEOUT); /* Start sending keepalives */ tsch_schedule_keepalive(); } else { /* Stop sending keepalives */ tsch_set_ka_timeout(0); } if(old_time_src != NULL) { old_time_src->is_time_source = 0; } #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src); #endif } return 1; } } return 0; }
/* Update TSCH time source */ int tsch_queue_update_time_source(const linkaddr_t *new_addr) { if(!tsch_is_locked()) { if(!tsch_is_coordinator) { struct tsch_neighbor *old_time_src = tsch_queue_get_time_source(); struct tsch_neighbor *new_time_src = NULL; if(new_addr != NULL) { /* Get/add neighbor, return 0 in case of failure */ new_time_src = tsch_queue_add_nbr(new_addr); if(new_time_src == NULL) { return 0; } } if(new_time_src != old_time_src) { PRINTF("TSCH: update time source: %u -> %u\n", TSCH_LOG_ID_FROM_LINKADDR(old_time_src ? &old_time_src->addr : NULL), TSCH_LOG_ID_FROM_LINKADDR(new_time_src ? &new_time_src->addr : NULL)); /* Update time source */ if(new_time_src != NULL) { new_time_src->is_time_source = 1; } if(old_time_src != NULL) { old_time_src->is_time_source = 0; } #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src); #endif } return 1; } } return 0; }
/*---------------------------------------------------------------------------*/ static void eb_input(struct input_packet *current_input) { /* PRINTF("TSCH: EB received\n"); */ frame802154_t frame; /* Verify incoming EB (does its ASN match our Rx time?), * and update our join priority. */ struct ieee802154_ies eb_ies; if(tsch_packet_parse_eb(current_input->payload, current_input->len, &frame, &eb_ies, NULL, 1)) { /* PAN ID check and authentication done at rx time */ #if TSCH_AUTOSELECT_TIME_SOURCE if(!tsch_is_coordinator) { /* Maintain EB received counter for every neighbor */ struct eb_stat *stat = (struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, &frame.src_addr); if(stat == NULL) { stat = (struct eb_stat *)nbr_table_add_lladdr(eb_stats, &frame.src_addr); } if(stat != NULL) { stat->rx_count++; stat->jp = eb_ies.join_priority; best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count); } /* Select best time source */ struct eb_stat *best_stat = NULL; stat = nbr_table_head(eb_stats); while(stat != NULL) { /* Is neighbor eligible as a time source? */ if(stat->rx_count > best_neighbor_eb_count / 2) { if(best_stat == NULL || stat->jp < best_stat->jp) { best_stat = stat; } } stat = nbr_table_next(eb_stats, stat); } /* Update time source */ if(best_stat != NULL) { tsch_queue_update_time_source(nbr_table_get_lladdr(eb_stats, best_stat)); tsch_join_priority = best_stat->jp + 1; } } #endif struct tsch_neighbor *n = tsch_queue_get_time_source(); /* Did the EB come from our time source? */ if(n != NULL && linkaddr_cmp((linkaddr_t *)&frame.src_addr, &n->addr)) { /* Check for ASN drift */ int32_t asn_diff = ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn); if(asn_diff != 0) { /* We disagree with our time source's ASN -- leave the network */ PRINTF("TSCH:! ASN drifted by %ld, leaving the network\n", asn_diff); tsch_disassociate(); } if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) { /* Join priority unacceptable. Leave network. */ PRINTF("TSCH:! EB JP too high %u, leaving the network\n", eb_ies.ie_join_priority); tsch_disassociate(); } else { #if TSCH_AUTOSELECT_TIME_SOURCE /* Update join priority */ if(tsch_join_priority != eb_ies.ie_join_priority + 1) { PRINTF("TSCH: update JP from EB %u -> %u\n", tsch_join_priority, eb_ies.ie_join_priority + 1); tsch_join_priority = eb_ies.ie_join_priority + 1; } #endif /* TSCH_AUTOSELECT_TIME_SOURCE */ } } } }