/* Tx callback for keepalive messages */ static void keepalive_packet_sent(void *ptr, int status, int transmissions) { #ifdef TSCH_LINK_NEIGHBOR_CALLBACK TSCH_LINK_NEIGHBOR_CALLBACK(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions); #endif PRINTF("TSCH: KA sent to %u, st %d-%d\n", TSCH_LOG_ID_FROM_LINKADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)), status, transmissions); tsch_schedule_keepalive(); }
/* 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; }
/* Attempt to associate to a network form an incoming EB */ static int tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) { frame802154_t frame; struct ieee802154_ies ies; uint8_t hdrlen; int i; if(input_eb == NULL || tsch_packet_parse_eb(input_eb->payload, input_eb->len, &frame, &ies, &hdrlen, 0) == 0) { PRINTF("TSCH:! failed to parse EB (len %u)\n", input_eb->len); return 0; } current_asn = ies.ie_asn; tsch_join_priority = ies.ie_join_priority + 1; #if TSCH_JOIN_SECURED_ONLY if(frame.fcf.security_enabled == 0) { PRINTF("TSCH:! parse_eb: EB is not secured\n"); return 0; } #endif /* TSCH_JOIN_SECURED_ONLY */ #if TSCH_SECURITY_ENABLED if(!tsch_security_parse_frame(input_eb->payload, hdrlen, input_eb->len - hdrlen - tsch_security_mic_len(&frame), &frame, (linkaddr_t*)&frame.src_addr, ¤t_asn)) { PRINTF("TSCH:! parse_eb: failed to authenticate\n"); return 0; } #endif /* TSCH_SECURITY_ENABLED */ #if !TSCH_SECURITY_ENABLED if(frame.fcf.security_enabled == 1) { PRINTF("TSCH:! parse_eb: we do not support security, but EB is secured\n"); return 0; } #endif /* !TSCH_SECURITY_ENABLED */ #if TSCH_JOIN_MY_PANID_ONLY /* Check if the EB comes from the PAN ID we expect */ if(frame.src_pid != IEEE802154_PANID) { PRINTF("TSCH:! parse_eb: PAN ID %x != %x\n", frame.src_pid, IEEE802154_PANID); return 0; } #endif /* TSCH_JOIN_MY_PANID_ONLY */ /* There was no join priority (or 0xff) in the EB, do not join */ if(ies.ie_join_priority == 0xff) { PRINTF("TSCH:! parse_eb: no join priority\n"); return 0; } /* TSCH timeslot timing */ for(i = 0; i < tsch_ts_elements_count; i++) { if(ies.ie_tsch_timeslot_id == 0) { tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]); } else { tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]); } } /* TSCH hopping sequence */ if(ies.ie_channel_hopping_sequence_id == 0) { memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); } else { if(ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) { memcpy(tsch_hopping_sequence, ies.ie_hopping_sequence_list, ies.ie_hopping_sequence_len); ASN_DIVISOR_INIT(tsch_hopping_sequence_length, ies.ie_hopping_sequence_len); } else { PRINTF("TSCH:! parse_eb: hopping sequence too long (%u)\n", ies.ie_hopping_sequence_len); return 0; } } #if TSCH_CHECK_TIME_AT_ASSOCIATION > 0 /* Divide by 4k and multiply again to avoid integer overflow */ uint32_t expected_asn = 4096 * TSCH_CLOCK_TO_SLOTS(clock_time() / 4096, tsch_timing_timeslot_length); /* Expected ASN based on our current time*/ int32_t asn_threshold = TSCH_CHECK_TIME_AT_ASSOCIATION * 60ul * TSCH_CLOCK_TO_SLOTS(CLOCK_SECOND, tsch_timing_timeslot_length); int32_t asn_diff = (int32_t)current_asn.ls4b - expected_asn; if(asn_diff > asn_threshold) { PRINTF("TSCH:! EB ASN rejected %lx %lx %ld\n", current_asn.ls4b, expected_asn, asn_diff); return 0; } #endif #if TSCH_INIT_SCHEDULE_FROM_EB /* Create schedule */ if(ies.ie_tsch_slotframe_and_link.num_slotframes == 0) { #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL PRINTF("TSCH: parse_eb: no schedule, setting up minimal schedule\n"); tsch_schedule_create_minimal(); #else PRINTF("TSCH: parse_eb: no schedule\n"); #endif } else { /* First, empty current schedule */ tsch_schedule_remove_all_slotframes(); /* We support only 0 or 1 slotframe in this IE */ int num_links = ies.ie_tsch_slotframe_and_link.num_links; if(num_links <= FRAME802154E_IE_MAX_LINKS) { int i; struct tsch_slotframe *sf = tsch_schedule_add_slotframe( ies.ie_tsch_slotframe_and_link.slotframe_handle, ies.ie_tsch_slotframe_and_link.slotframe_size); for(i = 0; i < num_links; i++) { tsch_schedule_add_link(sf, ies.ie_tsch_slotframe_and_link.links[i].link_options, LINK_TYPE_ADVERTISING, &tsch_broadcast_address, ies.ie_tsch_slotframe_and_link.links[i].timeslot, ies.ie_tsch_slotframe_and_link.links[i].channel_offset); } } else { PRINTF("TSCH:! parse_eb: too many links in schedule (%u)\n", num_links); return 0; } } #endif /* TSCH_INIT_SCHEDULE_FROM_EB */ if(tsch_join_priority < TSCH_MAX_JOIN_PRIORITY) { struct tsch_neighbor *n; /* Add coordinator to list of neighbors, lock the entry */ n = tsch_queue_add_nbr((linkaddr_t *)&frame.src_addr); if(n != NULL) { tsch_queue_update_time_source((linkaddr_t *)&frame.src_addr); #ifdef TSCH_CALLBACK_JOINING_NETWORK TSCH_CALLBACK_JOINING_NETWORK(); #endif /* Set PANID */ frame802154_set_pan_id(frame.src_pid); /* Synchronize on EB */ tsch_slot_operation_sync(timestamp - tsch_timing[tsch_ts_tx_offset], ¤t_asn); /* Update global flags */ tsch_is_associated = 1; tsch_is_pan_secured = frame.fcf.security_enabled; /* Association done, schedule keepalive messages */ tsch_schedule_keepalive(); PRINTF("TSCH: association done, sec %u, PAN ID %x, asn-%x.%lx, jp %u, timeslot id %u, hopping id %u, slotframe len %u with %u links, from ", tsch_is_pan_secured, frame.src_pid, current_asn.ms1b, current_asn.ls4b, tsch_join_priority, ies.ie_tsch_timeslot_id, ies.ie_channel_hopping_sequence_id, ies.ie_tsch_slotframe_and_link.slotframe_size, ies.ie_tsch_slotframe_and_link.num_links); PRINTLLADDR((const uip_lladdr_t *)&frame.src_addr); PRINTF("\n"); return 1; } } PRINTF("TSCH:! did not associate.\n"); return 0; }