/* 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; }
/* 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)); } }
/* Removes a link from slotframe. Return 1 if success, 0 if failure */ int tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l) { if(slotframe != NULL && l != NULL && l->slotframe_handle == slotframe->handle) { if(tsch_get_lock()) { uint8_t link_options; linkaddr_t addr; /* Save link option and addr in local variables as we need them * after freeing the link */ link_options = l->link_options; linkaddr_copy(&addr, &l->addr); /* The link to be removed is scheduled as next, set it to NULL * to abort the next link operation */ if(l == current_link) { current_link = NULL; } PRINTF("TSCH-schedule: remove_link %u %u %u %u %u\n", slotframe->handle, l->link_options, l->timeslot, l->channel_offset, TSCH_LOG_ID_FROM_LINKADDR(&l->addr)); list_remove(slotframe->links_list, l); memb_free(&link_memb, l); /* Release the lock before we update the neighbor (will take the lock) */ tsch_release_lock(); /* This was a tx link to this neighbor, update counters */ if(link_options & LINK_OPTION_TX) { struct tsch_neighbor *n = tsch_queue_add_nbr(&addr); if(n != NULL) { n->tx_links_count--; if(!(link_options & LINK_OPTION_SHARED)) { n->dedicated_tx_links_count--; } } } return 1; } else { PRINTF("TSCH-schedule:! remove_link memb_alloc couldn't take lock\n"); } } return 0; }
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ static void send_packet(mac_callback_t sent, void *ptr) { int ret = MAC_TX_DEFERRED; int packet_count_before; int hdr_len = 0; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(!tsch_is_associated) { if(!tsch_is_initialized) { PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n"); } else { PRINTF("TSCH:! not associated, drop outgoing packet\n"); } ret = MAC_TX_ERR; mac_call_sent_callback(sent, ptr, ret, 1); return; } /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity in framer-802154.c. */ if(++tsch_packet_seqno == 0) { tsch_packet_seqno++; } /* Ask for ACK if we are sending anything other than broadcast */ if(!linkaddr_cmp(addr, &linkaddr_null)) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); } else { /* Broadcast packets shall be added to broadcast queue * The broadcast address in Contiki is linkaddr_null which is equal * to tsch_eb_address */ addr = &tsch_broadcast_address; } packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno); #if TSCH_SECURITY_ENABLED if(tsch_is_pan_secured) { /* Set security level, key id and index */ packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); } #endif /* TSCH_SECURITY_ENABLED */ packet_count_before = tsch_queue_packet_count(addr); if((hdr_len = NETSTACK_FRAMER.create()) < 0) { PRINTF("TSCH:! can't send packet due to framer error\n"); ret = MAC_TX_ERR; } else { struct tsch_packet *p; /* Enqueue packet */ p = tsch_queue_add_packet(addr, sent, ptr); if(p == NULL) { PRINTF("TSCH:! can't send packet !tsch_queue_add_packet\n"); ret = MAC_TX_ERR; } else { p->header_len = hdr_len; PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), tsch_packet_seqno, packet_count_before, tsch_queue_packet_count(addr), p->header_len, queuebuf_datalen(p->qb)); } } if(ret != MAC_TX_DEFERRED) { mac_call_sent_callback(sent, ptr, ret, 1); } }
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ static void send_packet(mac_callback_t sent, void *ptr) { int ret = MAC_TX_DEFERRED; int packet_count_before; int hdr_len = 0; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(!tsch_is_associated) { if(!tsch_is_initialized) { PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n"); } else { PRINTF("TSCH:! not associated, drop outgoing packet\n"); } ret = MAC_TX_ERR; mac_call_sent_callback(sent, ptr, ret, 1); return; } /* Ask for ACK if we are sending anything other than broadcast */ if(!linkaddr_cmp(addr, &linkaddr_null)) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); } else { /* Broadcast packets shall be added to broadcast queue * The broadcast address in Contiki is linkaddr_null which is equal * to tsch_eb_address */ addr = &tsch_broadcast_address; } packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); #if LLSEC802154_ENABLED if(tsch_is_pan_secured) { /* Set security level, key id and index */ packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); } #endif /* LLSEC802154_ENABLED */ packet_count_before = tsch_queue_packet_count(addr); #if !NETSTACK_CONF_BRIDGE_MODE /* * In the Contiki stack, the source address of a frame is set at the RDC * layer. Since TSCH doesn't use any RDC protocol and bypasses the layer to * transmit a frame, it should set the source address by itself. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #endif if((hdr_len = NETSTACK_FRAMER.create()) < 0) { PRINTF("TSCH:! can't send packet due to framer error\n"); ret = MAC_TX_ERR; } else { struct tsch_packet *p; /* Enqueue packet */ p = tsch_queue_add_packet(addr, sent, ptr); if(p == NULL) { PRINTF("TSCH:! can't send packet to %u with seqno %u, queue %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), packet_count_before, tsch_queue_packet_count(addr)); ret = MAC_TX_ERR; } else { p->header_len = hdr_len; PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), packet_count_before, tsch_queue_packet_count(addr), p->header_len, queuebuf_datalen(p->qb)); (void)packet_count_before; /* Discard "variable set but unused" warning in case of TSCH_LOG_LEVEL of 0 */ } } if(ret != MAC_TX_DEFERRED) { mac_call_sent_callback(sent, ptr, ret, 1); } }