Contiki-NG
tsch.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, SICS Swedish ICT.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * IEEE 802.15.4 TSCH MAC implementation.
36  * Does not use any RDC layer. Should be used with nordc.
37  * \author
38  * Simon Duquennoy <simonduq@sics.se>
39  * Beshr Al Nahas <beshr@sics.se>
40  *
41  */
42 
43 /**
44  * \addtogroup tsch
45  * @{
46 */
47 
48 #include "contiki.h"
49 #include "dev/radio.h"
50 #include "net/netstack.h"
51 #include "net/packetbuf.h"
52 #include "net/queuebuf.h"
53 #include "net/nbr-table.h"
54 #include "net/link-stats.h"
56 #include "net/mac/tsch/tsch.h"
57 #include "net/mac/mac-sequence.h"
58 #include "lib/random.h"
59 #include "net/routing/routing.h"
60 #include <inttypes.h>
61 
62 #if TSCH_WITH_SIXTOP
64 #endif
65 
66 #if FRAME802154_VERSION < FRAME802154_IEEE802154_2015
67 #error TSCH: FRAME802154_VERSION must be at least FRAME802154_IEEE802154_2015
68 #endif
69 
70 /* Log configuration */
71 #include "sys/log.h"
72 #define LOG_MODULE "TSCH"
73 #define LOG_LEVEL LOG_LEVEL_MAC
74 
75 /* The address of the last node we received an EB from (other than our time source).
76  * Used for recovery */
77 static linkaddr_t last_eb_nbr_addr;
78 /* The join priority advertised by last_eb_nbr_addr */
79 static uint8_t last_eb_nbr_jp;
80 
81 /* Let TSCH select a time source with no help of an upper layer.
82  * We do so using statistics from incoming EBs */
83 #if TSCH_AUTOSELECT_TIME_SOURCE
84 int best_neighbor_eb_count;
85 struct eb_stat {
86  int rx_count;
87  int jp;
88 };
89 NBR_TABLE(struct eb_stat, eb_stats);
90 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
91 
92 /* TSCH channel hopping sequence */
93 uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
94 struct tsch_asn_divisor_t tsch_hopping_sequence_length;
95 
96 /* Default TSCH timeslot timing (in micro-second) */
97 static const uint16_t *tsch_default_timing_us;
98 /* TSCH timeslot timing (in micro-second) */
99 uint16_t tsch_timing_us[tsch_ts_elements_count];
100 /* TSCH timeslot timing (in rtimer ticks) */
101 rtimer_clock_t tsch_timing[tsch_ts_elements_count];
102 
103 #if LINKADDR_SIZE == 8
104 /* 802.15.4 broadcast MAC address */
105 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
106 /* Address used for the EB virtual neighbor queue */
107 const linkaddr_t tsch_eb_address = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
108 #else /* LINKADDR_SIZE == 8 */
109 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff } };
110 const linkaddr_t tsch_eb_address = { { 0, 0 } };
111 #endif /* LINKADDR_SIZE == 8 */
112 
113 /* Is TSCH started? */
114 int tsch_is_started = 0;
115 /* Has TSCH initialization failed? */
116 int tsch_is_initialized = 0;
117 /* Are we coordinator of the TSCH network? */
118 int tsch_is_coordinator = 0;
119 /* Are we associated to a TSCH network? */
120 int tsch_is_associated = 0;
121 /* Total number of associations since boot */
122 int tsch_association_count = 0;
123 /* Is the PAN running link-layer security? */
124 int tsch_is_pan_secured = LLSEC802154_ENABLED;
125 /* The current Absolute Slot Number (ASN) */
126 struct tsch_asn_t tsch_current_asn;
127 /* Device rank or join priority:
128  * For PAN coordinator: 0 -- lower is better */
129 uint8_t tsch_join_priority;
130 /* The current TSCH sequence number, used for unicast data frames only */
131 static uint8_t tsch_packet_seqno;
132 /* Current period for EB output */
133 static clock_time_t tsch_current_eb_period;
134 /* Current period for keepalive output */
135 static clock_time_t tsch_current_ka_timeout;
136 
137 /* For scheduling keepalive messages */
138 enum tsch_keepalive_status {
139  KEEPALIVE_SCHEDULING_UNCHANGED,
140  KEEPALIVE_SCHEDULE_OR_STOP,
141  KEEPALIVE_SEND_IMMEDIATELY,
142 };
143 /* Should we send or schedule a keepalive? */
144 static volatile enum tsch_keepalive_status keepalive_status;
145 
146 /* timer for sending keepalive messages */
147 static struct ctimer keepalive_timer;
148 
149 /* Statistics on the current session */
150 unsigned long tx_count;
151 unsigned long rx_count;
152 unsigned long sync_count;
153 int32_t min_drift_seen;
154 int32_t max_drift_seen;
155 
156 /* TSCH processes and protothreads */
157 PT_THREAD(tsch_scan(struct pt *pt));
158 PROCESS(tsch_process, "main process");
159 PROCESS(tsch_send_eb_process, "send EB process");
160 PROCESS(tsch_pending_events_process, "pending events process");
161 
162 /* Other function prototypes */
163 static void packet_input(void);
164 
165 /* Getters and setters */
166 
167 /*---------------------------------------------------------------------------*/
168 void
170 {
171  if(tsch_is_coordinator != enable) {
172  tsch_is_associated = 0;
173  }
174  tsch_is_coordinator = enable;
175  tsch_set_eb_period(TSCH_EB_PERIOD);
176  tsch_roots_set_self_to_root(tsch_is_coordinator ? 1 : 0);
177 }
178 /*---------------------------------------------------------------------------*/
179 void
181 {
182  tsch_is_pan_secured = LLSEC802154_ENABLED && enable;
183 }
184 /*---------------------------------------------------------------------------*/
185 void
187 {
188  tsch_join_priority = jp;
189 }
190 /*---------------------------------------------------------------------------*/
191 void
192 tsch_set_ka_timeout(uint32_t timeout)
193 {
194  tsch_current_ka_timeout = timeout;
196 }
197 /*---------------------------------------------------------------------------*/
198 void
199 tsch_set_eb_period(uint32_t period)
200 {
201  tsch_current_eb_period = MIN(period, TSCH_MAX_EB_PERIOD);
202 }
203 /*---------------------------------------------------------------------------*/
204 static void
205 tsch_reset(void)
206 {
207  int i;
208  frame802154_set_pan_id(0xffff);
209  /* First make sure pending packet callbacks are sent etc */
210  process_post_synch(&tsch_pending_events_process, PROCESS_EVENT_POLL, NULL);
211  /* Reset neighbor queues */
213  /* Remove unused neighbors */
216  /* Initialize global variables */
217  tsch_join_priority = 0xff;
218  TSCH_ASN_INIT(tsch_current_asn, 0, 0);
219  current_link = NULL;
220  /* Reset timeslot timing to defaults */
221  tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING;
222  for(i = 0; i < tsch_ts_elements_count; i++) {
223  tsch_timing_us[i] = tsch_default_timing_us[i];
224  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
225  }
226 #ifdef TSCH_CALLBACK_LEAVING_NETWORK
227  TSCH_CALLBACK_LEAVING_NETWORK();
228 #endif
229  linkaddr_copy(&last_eb_nbr_addr, &linkaddr_null);
230 #if TSCH_AUTOSELECT_TIME_SOURCE
231  struct eb_stat *stat;
232  best_neighbor_eb_count = 0;
233  /* Remove all nbr stats */
234  stat = nbr_table_head(eb_stats);
235  while(stat != NULL) {
236  nbr_table_remove(eb_stats, stat);
237  stat = nbr_table_next(eb_stats, stat);
238  }
239 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
240  tsch_set_eb_period(TSCH_EB_PERIOD);
241  keepalive_status = KEEPALIVE_SCHEDULING_UNCHANGED;
242 }
243 /* TSCH keep-alive functions */
244 
245 /*---------------------------------------------------------------------------*/
246 /* Resynchronize to last_eb_nbr.
247  * Return non-zero if this function schedules the next keepalive.
248  * Return zero otherwise.
249  */
250 static int
251 resynchronize(const linkaddr_t *original_time_source_addr)
252 {
253  const struct tsch_neighbor *current_time_source = tsch_queue_get_time_source();
254  const linkaddr_t *ts_addr = tsch_queue_get_nbr_address(current_time_source);
255  if(ts_addr != NULL && !linkaddr_cmp(ts_addr, original_time_source_addr)) {
256  /* Time source has already been changed (e.g. by RPL). Let's see if it works. */
257  LOG_INFO("time source has been changed to ");
258  LOG_INFO_LLADDR(ts_addr);
259  LOG_INFO_("\n");
260  return 0;
261  }
262  /* Switch time source to the last neighbor we received an EB from */
263  if(linkaddr_cmp(&last_eb_nbr_addr, &linkaddr_null)) {
264  LOG_WARN("not able to re-synchronize, received no EB from other neighbors\n");
265  if(sync_count == 0) {
266  /* We got no synchronization at all in this session, leave the network */
268  }
269  return 0;
270  } else {
271  LOG_WARN("re-synchronizing on ");
272  LOG_WARN_LLADDR(&last_eb_nbr_addr);
273  LOG_WARN_("\n");
274  /* We simply pick the last neighbor we receiver sync information from */
275  tsch_queue_update_time_source(&last_eb_nbr_addr);
276  tsch_join_priority = last_eb_nbr_jp + 1;
277  linkaddr_copy(&last_eb_nbr_addr, &linkaddr_null);
278  /* Try to get in sync ASAP */
280  return 1;
281  }
282 }
283 
284 /*---------------------------------------------------------------------------*/
285 /* Tx callback for keepalive messages */
286 static void
287 keepalive_packet_sent(void *ptr, int status, int transmissions)
288 {
289  int schedule_next_keepalive = 1;
290  /* Update neighbor link statistics */
291  link_stats_packet_sent(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
292  /* Call RPL callback if RPL is enabled */
293 #ifdef TSCH_CALLBACK_KA_SENT
294  TSCH_CALLBACK_KA_SENT(status, transmissions);
295 #endif /* TSCH_CALLBACK_KA_SENT */
296  LOG_INFO("KA sent to ");
297  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
298  LOG_INFO_(", st %d-%d\n", status, transmissions);
299 
300  /* We got no ack, try to resynchronize */
301  if(status == MAC_TX_NOACK) {
302  schedule_next_keepalive = !resynchronize(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
303  }
304 
305  if(schedule_next_keepalive) {
307  }
308 }
309 /*---------------------------------------------------------------------------*/
310 /* Prepare and send a keepalive message */
311 static void
312 keepalive_send(void *ptr)
313 {
314  /* If not here from a timer callback, the timer must be stopped */
315  ctimer_stop(&keepalive_timer);
316 
317  if(tsch_is_associated) {
319  if(n != NULL) {
320  linkaddr_t *destination = tsch_queue_get_nbr_address(n);
321  /* Simply send an empty packet */
322  packetbuf_clear();
323  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, destination);
324  NETSTACK_MAC.send(keepalive_packet_sent, NULL);
325  LOG_INFO("sending KA to ");
326  LOG_INFO_LLADDR(destination);
327  LOG_INFO_("\n");
328  } else {
329  LOG_ERR("no timesource - KA not sent\n");
330  }
331  }
332 }
333 /*---------------------------------------------------------------------------*/
334 void
336 {
337  if(immediate) {
338  /* send as soon as possible */
339  keepalive_status = KEEPALIVE_SEND_IMMEDIATELY;
340  } else if(keepalive_status != KEEPALIVE_SEND_IMMEDIATELY) {
341  /* send based on the tsch_current_ka_timeout */
342  keepalive_status = KEEPALIVE_SCHEDULE_OR_STOP;
343  }
344  process_poll(&tsch_pending_events_process);
345 }
346 /*---------------------------------------------------------------------------*/
347 static void
348 tsch_keepalive_process_pending(void)
349 {
350  if(keepalive_status != KEEPALIVE_SCHEDULING_UNCHANGED) {
351  /* first, save and reset the old status */
352  enum tsch_keepalive_status scheduled_status = keepalive_status;
353  keepalive_status = KEEPALIVE_SCHEDULING_UNCHANGED;
354 
355  if(!tsch_is_coordinator && tsch_is_associated) {
356  switch(scheduled_status) {
357  case KEEPALIVE_SEND_IMMEDIATELY:
358  /* always send, and as soon as possible (now) */
359  keepalive_send(NULL);
360  break;
361 
362  case KEEPALIVE_SCHEDULE_OR_STOP:
363  if(tsch_current_ka_timeout > 0) {
364  /* Pick a delay in the range [tsch_current_ka_timeout*0.9, tsch_current_ka_timeout[ */
365  unsigned long delay;
366  if(tsch_current_ka_timeout >= 10) {
367  delay = (tsch_current_ka_timeout - tsch_current_ka_timeout / 10)
368  + random_rand() % (tsch_current_ka_timeout / 10);
369  } else {
370  delay = tsch_current_ka_timeout - 1;
371  }
372  ctimer_set(&keepalive_timer, delay, keepalive_send, NULL);
373  } else {
374  /* zero timeout set, stop sending keepalives */
375  ctimer_stop(&keepalive_timer);
376  }
377  break;
378 
379  default:
380  break;
381  }
382  } else {
383  /* either coordinator or not associated */
384  ctimer_stop(&keepalive_timer);
385  }
386  }
387 }
388 /*---------------------------------------------------------------------------*/
389 static void
390 eb_input(struct input_packet *current_input)
391 {
392  /* LOG_INFO("EB received\n"); */
393  frame802154_t frame;
394  /* Verify incoming EB (does its ASN match our Rx time?),
395  * and update our join priority. */
396  struct ieee802154_ies eb_ies;
397 
398  if(tsch_packet_parse_eb(current_input->payload, current_input->len,
399  &frame, &eb_ies, NULL, 1)) {
400  /* PAN ID check and authentication done at rx time */
401 
402  /* Got an EB from a different neighbor than our time source, keep enough data
403  * to switch to it in case we lose the link to our time source */
405  linkaddr_t *ts_addr = tsch_queue_get_nbr_address(ts);
406  if(ts_addr == NULL || !linkaddr_cmp((linkaddr_t *)&frame.src_addr, ts_addr)) {
407  linkaddr_copy(&last_eb_nbr_addr, (linkaddr_t *)&frame.src_addr);
408  last_eb_nbr_jp = eb_ies.ie_join_priority;
409  }
410 
411 #if TSCH_AUTOSELECT_TIME_SOURCE
412  if(!tsch_is_coordinator) {
413  /* Maintain EB received counter for every neighbor */
414  struct eb_stat *stat = (struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, (linkaddr_t *)&frame.src_addr);
415  if(stat == NULL) {
416  stat = (struct eb_stat *)nbr_table_add_lladdr(eb_stats, (linkaddr_t *)&frame.src_addr, NBR_TABLE_REASON_MAC, NULL);
417  }
418  if(stat != NULL) {
419  stat->rx_count++;
420  stat->jp = eb_ies.ie_join_priority;
421  best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count);
422  }
423  /* Select best time source */
424  struct eb_stat *best_stat = NULL;
425  stat = nbr_table_head(eb_stats);
426  while(stat != NULL) {
427  /* Is neighbor eligible as a time source? */
428  if(stat->rx_count > best_neighbor_eb_count / 2) {
429  if(best_stat == NULL ||
430  stat->jp < best_stat->jp) {
431  best_stat = stat;
432  }
433  }
434  stat = nbr_table_next(eb_stats, stat);
435  }
436  /* Update time source */
437  if(best_stat != NULL) {
438  tsch_queue_update_time_source(nbr_table_get_lladdr(eb_stats, best_stat));
439  tsch_join_priority = best_stat->jp + 1;
440  }
441  }
442 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
443 
444  /* If this EB is coming from the root, add it to the root list */
445  if(eb_ies.ie_join_priority == 0) {
446  tsch_roots_add_address((linkaddr_t *)&frame.src_addr);
447  }
448 
449  /* Did the EB come from our time source? */
450  if(ts_addr != NULL && linkaddr_cmp((linkaddr_t *)&frame.src_addr, ts_addr)) {
451  /* Check for ASN drift */
452  int32_t asn_diff = TSCH_ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn);
453  if(asn_diff != 0) {
454  /* We disagree with our time source's ASN -- leave the network */
455  LOG_WARN("! ASN drifted by %"PRId32", leaving the network\n", asn_diff);
457  }
458 
459  if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) {
460  /* Join priority unacceptable. Leave network. */
461  LOG_WARN("! EB JP too high %u, leaving the network\n",
462  eb_ies.ie_join_priority);
464  } else {
465 #if TSCH_AUTOSELECT_TIME_SOURCE
466  /* Update join priority */
467  if(tsch_join_priority != eb_ies.ie_join_priority + 1) {
468  LOG_INFO("update JP from EB %u -> %u\n",
469  tsch_join_priority, eb_ies.ie_join_priority + 1);
470  tsch_join_priority = eb_ies.ie_join_priority + 1;
471  }
472 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
473  }
474 
475  /* TSCH hopping sequence */
476  if(eb_ies.ie_channel_hopping_sequence_id != 0) {
477  if(eb_ies.ie_hopping_sequence_len != tsch_hopping_sequence_length.val
478  || memcmp((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, tsch_hopping_sequence_length.val)) {
479  if(eb_ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
480  memcpy((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list,
481  eb_ies.ie_hopping_sequence_len);
482  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, eb_ies.ie_hopping_sequence_len);
483 
484  LOG_WARN("Updating TSCH hopping sequence from EB\n");
485  } else {
486  LOG_WARN("TSCH:! parse_eb: hopping sequence too long (%u)\n", eb_ies.ie_hopping_sequence_len);
487  }
488  }
489  }
490  }
491  }
492 }
493 /*---------------------------------------------------------------------------*/
494 /* Process pending input packet(s) */
495 static void
496 tsch_rx_process_pending()
497 {
498  int16_t input_index;
499  /* Loop on accessing (without removing) a pending output packet */
500  while((input_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
501  struct input_packet *current_input = &input_array[input_index];
502  frame802154_t frame;
503  uint8_t ret = frame802154_parse(current_input->payload, current_input->len, &frame);
504  int is_data = ret && frame.fcf.frame_type == FRAME802154_DATAFRAME;
505  int is_eb = ret
506  && frame.fcf.frame_version == FRAME802154_IEEE802154_2015
507  && frame.fcf.frame_type == FRAME802154_BEACONFRAME;
508 
509  if(is_data) {
510  /* Skip EBs and other control messages */
511  /* Copy to packetbuf for processing */
512  packetbuf_copyfrom(current_input->payload, current_input->len);
513  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, current_input->rssi);
514  packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, current_input->channel);
515  }
516 
517  if(is_data) {
518  /* Pass to upper layers */
519  packet_input();
520  } else if(is_eb) {
521  eb_input(current_input);
522  }
523 
524  /* Remove input from ringbuf */
525  ringbufindex_get(&input_ringbuf);
526  }
527 }
528 /*---------------------------------------------------------------------------*/
529 /* Pass sent packets to upper layer */
530 static void
531 tsch_tx_process_pending(void)
532 {
533  uint16_t num_packets_freed = 0;
534  int16_t dequeued_index;
535  /* Loop on accessing (without removing) a pending input packet */
536  while((dequeued_index = ringbufindex_peek_get(&dequeued_ringbuf)) != -1) {
537  struct tsch_packet *p = dequeued_array[dequeued_index];
538  /* Put packet into packetbuf for packet_sent callback */
539  queuebuf_to_packetbuf(p->qb);
540  LOG_INFO("packet sent to ");
541  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
542  LOG_INFO_(", seqno %u, status %d, tx %d\n",
543  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), p->ret, p->transmissions);
544  /* Call packet_sent callback */
545  mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
546  /* Free packet queuebuf */
548  /* Remove dequeued packet from ringbuf */
549  ringbufindex_get(&dequeued_ringbuf);
550  num_packets_freed++;
551  }
552 
553  if(num_packets_freed > 0) {
554  /* Free all unused neighbors */
556  }
557 }
558 /*---------------------------------------------------------------------------*/
559 /* Setup TSCH as a coordinator */
560 static void
561 tsch_start_coordinator(void)
562 {
563  frame802154_set_pan_id(IEEE802154_PANID);
564  /* Initialize hopping sequence as default */
565  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
566  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
567 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
569 #endif
570 
571  tsch_is_associated = 1;
572  tsch_join_priority = 0;
573 
574  LOG_INFO("starting as coordinator, PAN ID %x, asn-%x.%"PRIx32"\n",
575  frame802154_get_pan_id(), tsch_current_asn.ms1b, tsch_current_asn.ls4b);
576 
577  /* Start slot operation */
578  tsch_slot_operation_sync(RTIMER_NOW(), &tsch_current_asn);
579 }
580 /*---------------------------------------------------------------------------*/
581 /* Leave the TSCH network */
582 void
584 {
585  if(tsch_is_associated == 1) {
586  tsch_is_associated = 0;
588  process_poll(&tsch_process);
589  }
590 }
591 /*---------------------------------------------------------------------------*/
592 /* Attempt to associate to a network form an incoming EB */
593 static int
594 tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
595 {
596  frame802154_t frame;
597  struct ieee802154_ies ies;
598  uint8_t hdrlen;
599  int i;
600 
601  if(input_eb == NULL || tsch_packet_parse_eb(input_eb->payload, input_eb->len,
602  &frame, &ies, &hdrlen, 0) == 0) {
603  LOG_DBG("! failed to parse packet as EB while scanning (len %u)\n",
604  input_eb->len);
605  return 0;
606  }
607 
608  tsch_current_asn = ies.ie_asn;
609  tsch_join_priority = ies.ie_join_priority + 1;
610 
611 #if TSCH_JOIN_SECURED_ONLY
612  if(frame.fcf.security_enabled == 0) {
613  LOG_ERR("! parse_eb: EB is not secured\n");
614  return 0;
615  }
616 #endif /* TSCH_JOIN_SECURED_ONLY */
617 #if LLSEC802154_ENABLED
618  if(!tsch_security_parse_frame(input_eb->payload, hdrlen,
619  input_eb->len - hdrlen - tsch_security_mic_len(&frame),
620  &frame, (linkaddr_t*)&frame.src_addr, &tsch_current_asn)) {
621  LOG_ERR("! parse_eb: failed to authenticate\n");
622  return 0;
623  }
624 #endif /* LLSEC802154_ENABLED */
625 
626 #if !LLSEC802154_ENABLED
627  if(frame.fcf.security_enabled == 1) {
628  LOG_ERR("! parse_eb: we do not support security, but EB is secured\n");
629  return 0;
630  }
631 #endif /* !LLSEC802154_ENABLED */
632 
633 #if TSCH_JOIN_MY_PANID_ONLY
634  /* Check if the EB comes from the PAN ID we expect */
635  if(frame.src_pid != IEEE802154_PANID) {
636  LOG_ERR("! parse_eb: PAN ID %x != %x\n", frame.src_pid, IEEE802154_PANID);
637  return 0;
638  }
639 #endif /* TSCH_JOIN_MY_PANID_ONLY */
640 
641  /* There was no join priority (or 0xff) in the EB, do not join */
642  if(ies.ie_join_priority == 0xff) {
643  LOG_ERR("! parse_eb: no join priority\n");
644  return 0;
645  }
646 
647  /* TSCH timeslot timing */
648  for(i = 0; i < tsch_ts_elements_count; i++) {
649  if(ies.ie_tsch_timeslot_id == 0) {
650  tsch_timing_us[i] = tsch_default_timing_us[i];
651  } else {
652  tsch_timing_us[i] = ies.ie_tsch_timeslot[i];
653  }
654  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
655  }
656 
657  /* TSCH hopping sequence */
658  if(ies.ie_channel_hopping_sequence_id == 0) {
659  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
660  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
661  } else {
662  if(ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
663  memcpy(tsch_hopping_sequence, ies.ie_hopping_sequence_list, ies.ie_hopping_sequence_len);
664  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, ies.ie_hopping_sequence_len);
665  } else {
666  LOG_ERR("! parse_eb: hopping sequence too long (%u)\n", ies.ie_hopping_sequence_len);
667  return 0;
668  }
669  }
670 
671 #if TSCH_CHECK_TIME_AT_ASSOCIATION > 0
672  /* Divide by 4k and multiply again to avoid integer overflow */
673  uint32_t expected_asn = 4096 * TSCH_CLOCK_TO_SLOTS(clock_time() / 4096, tsch_timing_timeslot_length); /* Expected ASN based on our current time*/
674  int32_t asn_threshold = TSCH_CHECK_TIME_AT_ASSOCIATION * 60ul * TSCH_CLOCK_TO_SLOTS(CLOCK_SECOND, tsch_timing_timeslot_length);
675  int32_t asn_diff = (int32_t)tsch_current_asn.ls4b - expected_asn;
676  if(asn_diff > asn_threshold) {
677  LOG_ERR("! EB ASN rejected %lx %lx %ld\n",
678  tsch_current_asn.ls4b, expected_asn, asn_diff);
679  return 0;
680  }
681 #endif
682 
683 #if TSCH_INIT_SCHEDULE_FROM_EB
684  /* Create schedule */
685  if(ies.ie_tsch_slotframe_and_link.num_slotframes == 0) {
686 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
687  LOG_INFO("parse_eb: no schedule, setting up minimal schedule\n");
689 #else
690  LOG_INFO("parse_eb: no schedule\n");
691 #endif
692  } else {
693  /* First, empty current schedule */
695  /* We support only 0 or 1 slotframe in this IE */
696  int num_links = ies.ie_tsch_slotframe_and_link.num_links;
697  if(num_links <= FRAME802154E_IE_MAX_LINKS) {
698  int i;
700  ies.ie_tsch_slotframe_and_link.slotframe_handle,
701  ies.ie_tsch_slotframe_and_link.slotframe_size);
702  for(i = 0; i < num_links; i++) {
704  ies.ie_tsch_slotframe_and_link.links[i].link_options,
705  LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
706  ies.ie_tsch_slotframe_and_link.links[i].timeslot,
707  ies.ie_tsch_slotframe_and_link.links[i].channel_offset, 1);
708  }
709  } else {
710  LOG_ERR("! parse_eb: too many links in schedule (%u)\n", num_links);
711  return 0;
712  }
713  }
714 #endif /* TSCH_INIT_SCHEDULE_FROM_EB */
715 
716  if(tsch_join_priority < TSCH_MAX_JOIN_PRIORITY) {
717  struct tsch_neighbor *n;
718 
719  /* Add coordinator to list of neighbors, lock the entry */
720  n = tsch_queue_add_nbr((linkaddr_t *)&frame.src_addr);
721 
722  if(n != NULL) {
723  tsch_queue_update_time_source((linkaddr_t *)&frame.src_addr);
724 
725  /* Set PANID */
726  frame802154_set_pan_id(frame.src_pid);
727 
728  /* Synchronize on EB */
729  tsch_slot_operation_sync(timestamp - tsch_timing[tsch_ts_tx_offset], &tsch_current_asn);
730 
731  /* Update global flags */
732  tsch_is_associated = 1;
733  tsch_is_pan_secured = frame.fcf.security_enabled;
734  tx_count = 0;
735  rx_count = 0;
736  sync_count = 0;
737  min_drift_seen = 0;
738  max_drift_seen = 0;
739 
740  /* Start sending keep-alives now that tsch_is_associated is set */
742 
743  /* If this EB is coming from the root, add it to the root list */
744  if(ies.ie_join_priority == 0) {
745  tsch_roots_add_address((linkaddr_t *)&frame.src_addr);
746  }
747 
748 #ifdef TSCH_CALLBACK_JOINING_NETWORK
749  TSCH_CALLBACK_JOINING_NETWORK();
750 #endif
751 
752  tsch_association_count++;
753  LOG_INFO("association done (%u), sec %u, PAN ID %x, asn-%x.%"PRIx32", jp %u, timeslot id %u, hopping id %u, slotframe len %u with %u links, from ",
754  tsch_association_count,
755  tsch_is_pan_secured,
756  frame.src_pid,
757  tsch_current_asn.ms1b, tsch_current_asn.ls4b, tsch_join_priority,
758  ies.ie_tsch_timeslot_id,
759  ies.ie_channel_hopping_sequence_id,
760  ies.ie_tsch_slotframe_and_link.slotframe_size,
761  ies.ie_tsch_slotframe_and_link.num_links);
762  LOG_INFO_LLADDR((const linkaddr_t *)&frame.src_addr);
763  LOG_INFO_("\n");
764 
765  return 1;
766  }
767  }
768  LOG_ERR("! did not associate.\n");
769  return 0;
770 }
771 /* Processes and protothreads used by TSCH */
772 
773 /*---------------------------------------------------------------------------*/
774 /* Scanning protothread, called by tsch_process:
775  * Listen to different channels, and when receiving an EB,
776  * attempt to associate.
777  */
778 PT_THREAD(tsch_scan(struct pt *pt))
779 {
780  PT_BEGIN(pt);
781 
782  static struct input_packet input_eb;
783  static struct etimer scan_timer;
784  /* Time when we started scanning on current_channel */
785  static clock_time_t current_channel_since;
786 
787  TSCH_ASN_INIT(tsch_current_asn, 0, 0);
788 
789  etimer_set(&scan_timer, MAX(1, CLOCK_SECOND / TSCH_ASSOCIATION_POLL_FREQUENCY));
790  current_channel_since = clock_time();
791 
792  while(!tsch_is_associated && !tsch_is_coordinator) {
793  /* Hop to any channel offset */
794  static uint8_t current_channel = 0;
795 
796  /* We are not coordinator, try to associate */
797  rtimer_clock_t t0;
798  int is_packet_pending = 0;
799  clock_time_t now_time = clock_time();
800 
801  /* Switch to a (new) channel for scanning */
802  if(current_channel == 0 || now_time - current_channel_since > TSCH_CHANNEL_SCAN_DURATION) {
803  /* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
804  uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
805  random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
806 
807  NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
808  current_channel = scan_channel;
809  LOG_INFO("scanning on channel %u\n", scan_channel);
810 
811  current_channel_since = now_time;
812  }
813 
814  /* Turn radio on and wait for EB */
815  NETSTACK_RADIO.on();
816 
817  is_packet_pending = NETSTACK_RADIO.pending_packet();
818  if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
819  /* If we are currently receiving a packet, wait until end of reception */
820  t0 = RTIMER_NOW();
821  RTIMER_BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
822  }
823 
824  if(is_packet_pending) {
825  rtimer_clock_t t1;
826  /* Read packet */
827  input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
828 
829  if(input_eb.len > 0) {
830  /* Save packet timestamp */
831  NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
832  t1 = RTIMER_NOW();
833 
834  /* Parse EB and attempt to associate */
835  LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
836 
837  /* Sanity-check the timestamp */
838  if(ABS(RTIMER_CLOCK_DIFF(t0, t1)) < 2ul * RTIMER_SECOND) {
839  tsch_associate(&input_eb, t0);
840  } else {
841  LOG_WARN("scan: dropping packet, timestamp too far from current time %u %u\n",
842  (unsigned)t0,
843  (unsigned)t1
844  );
845  }
846  }
847  }
848 
849  if(tsch_is_associated) {
850  /* End of association, turn the radio off */
851  NETSTACK_RADIO.off();
852  } else if(!tsch_is_coordinator) {
853  /* Go back to scanning */
854  etimer_restart(&scan_timer);
855  PT_WAIT_UNTIL(pt, etimer_expired(&scan_timer));
856  }
857  }
858 
859  PT_END(pt);
860 }
861 
862 /*---------------------------------------------------------------------------*/
863 /* The main TSCH process */
864 PROCESS_THREAD(tsch_process, ev, data)
865 {
866  static struct pt scan_pt;
867 
868  PROCESS_BEGIN();
869 
870  while(1) {
871 
872  while(!tsch_is_associated) {
873  if(tsch_is_coordinator) {
874  /* We are coordinator, start operating now */
875  tsch_start_coordinator();
876  } else {
877  /* Start scanning, will attempt to join when receiving an EB */
878  PROCESS_PT_SPAWN(&scan_pt, tsch_scan(&scan_pt));
879  }
880  }
881 
882  /* We are part of a TSCH network, start slot operation */
884 
885  /* Yield our main process. Slot operation will re-schedule itself
886  * as long as we are associated */
887  PROCESS_YIELD_UNTIL(!tsch_is_associated);
888 
889  LOG_WARN("leaving the network, stats: tx %lu, rx %lu, sync %lu\n",
890  tx_count, rx_count, sync_count);
891 
892  /* Will need to re-synchronize */
893  tsch_reset();
894  }
895 
896  PROCESS_END();
897 }
898 
899 /*---------------------------------------------------------------------------*/
900 /* A periodic process to send TSCH Enhanced Beacons (EB) */
901 PROCESS_THREAD(tsch_send_eb_process, ev, data)
902 {
903  static struct etimer eb_timer;
904 
905  PROCESS_BEGIN();
906 
907  /* Wait until association */
908  etimer_set(&eb_timer, CLOCK_SECOND / 10);
909  while(!tsch_is_associated) {
911  etimer_reset(&eb_timer);
912  }
913 
914  /* Set an initial delay except for coordinator, which should send an EB asap */
915  if(!tsch_is_coordinator) {
916  etimer_set(&eb_timer, TSCH_EB_PERIOD ? random_rand() % TSCH_EB_PERIOD : 0);
918  }
919 
920  while(1) {
921  unsigned long delay;
922 
923  if(!tsch_is_associated) {
924  LOG_DBG("skip sending EB: not joined a TSCH network\n");
925  } else if(tsch_current_eb_period <= 0) {
926  LOG_DBG("skip sending EB: EB period disabled\n");
927 #ifdef TSCH_RPL_CHECK_DODAG_JOINED
928  } else if(!TSCH_RPL_CHECK_DODAG_JOINED()) {
929  /* Implementation section 6.3 of RFC 8180 */
930  LOG_DBG("skip sending EB: not joined a routing DAG\n");
931 #endif /* TSCH_RPL_CHECK_DODAG_JOINED */
932  } else if(NETSTACK_ROUTING.is_in_leaf_mode()) {
933  /* don't send when in leaf mode */
934  LOG_DBG("skip sending EB: in the leaf mode\n");
935  } else if(tsch_queue_nbr_packet_count(n_eb) != 0) {
936  /* Enqueue EB only if there isn't already one in queue */
937  LOG_DBG("skip sending EB: already queued\n");
938  } else {
939  uint8_t hdr_len = 0;
940  uint8_t tsch_sync_ie_offset;
941  /* Prepare the EB packet and schedule it to be sent */
942  if(tsch_packet_create_eb(&hdr_len, &tsch_sync_ie_offset) > 0) {
943  struct tsch_packet *p;
944  /* Enqueue EB packet, for a single transmission only */
945  if(!(p = tsch_queue_add_packet(&tsch_eb_address, 1, NULL, NULL))) {
946  LOG_ERR("! could not enqueue EB packet\n");
947  } else {
948  LOG_INFO("TSCH: enqueue EB packet %u %u\n",
950  p->tsch_sync_ie_offset = tsch_sync_ie_offset;
951  p->header_len = hdr_len;
952  }
953  }
954  }
955  if(tsch_current_eb_period > 0) {
956  /* Next EB transmission with a random delay
957  * within [tsch_current_eb_period*0.75, tsch_current_eb_period[ */
958  delay = (tsch_current_eb_period - tsch_current_eb_period / 4)
959  + random_rand() % (tsch_current_eb_period / 4);
960  } else {
961  delay = TSCH_EB_PERIOD;
962  }
963  etimer_set(&eb_timer, delay);
965  }
966  PROCESS_END();
967 }
968 
969 /*---------------------------------------------------------------------------*/
970 /* A process that is polled from interrupt and calls tx/rx input
971  * callbacks, outputs pending logs. */
972 PROCESS_THREAD(tsch_pending_events_process, ev, data)
973 {
974  PROCESS_BEGIN();
975  while(1) {
976  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
977  tsch_rx_process_pending();
978  tsch_tx_process_pending();
980  tsch_keepalive_process_pending();
981 #ifdef TSCH_CALLBACK_SELECT_CHANNELS
982  TSCH_CALLBACK_SELECT_CHANNELS();
983 #endif
984  }
985  PROCESS_END();
986 }
987 
988 /* Functions from the Contiki MAC layer driver interface */
989 
990 /*---------------------------------------------------------------------------*/
991 static void
992 tsch_init(void)
993 {
994  radio_value_t radio_rx_mode;
995  radio_value_t radio_tx_mode;
996  radio_value_t radio_max_payload_len;
997 
998  rtimer_clock_t t;
999 
1000  /* Check that the platform provides a TSCH timeslot timing template */
1001  if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) {
1002  LOG_ERR("! platform does not provide a timeslot timing template.\n");
1003  return;
1004  }
1005 
1006  /* Check that the radio can correctly report its max supported payload */
1007  if(NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN, &radio_max_payload_len) != RADIO_RESULT_OK) {
1008  LOG_ERR("! radio does not support getting RADIO_CONST_MAX_PAYLOAD_LEN. Abort init.\n");
1009  return;
1010  }
1011 
1012  /* Radio Rx mode */
1013  if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) {
1014  LOG_ERR("! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
1015  return;
1016  }
1017  /* Disable radio in frame filtering */
1018  radio_rx_mode &= ~RADIO_RX_MODE_ADDRESS_FILTER;
1019  /* Unset autoack */
1020  radio_rx_mode &= ~RADIO_RX_MODE_AUTOACK;
1021  /* Set radio in poll mode */
1022  radio_rx_mode |= RADIO_RX_MODE_POLL_MODE;
1023  if(NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode) != RADIO_RESULT_OK) {
1024  LOG_ERR("! radio does not support setting required RADIO_PARAM_RX_MODE. Abort init.\n");
1025  return;
1026  }
1027 
1028  /* Radio Tx mode */
1029  if(NETSTACK_RADIO.get_value(RADIO_PARAM_TX_MODE, &radio_tx_mode) != RADIO_RESULT_OK) {
1030  LOG_ERR("! radio does not support getting RADIO_PARAM_TX_MODE. Abort init.\n");
1031  return;
1032  }
1033  /* Unset CCA */
1034  radio_tx_mode &= ~RADIO_TX_MODE_SEND_ON_CCA;
1035  if(NETSTACK_RADIO.set_value(RADIO_PARAM_TX_MODE, radio_tx_mode) != RADIO_RESULT_OK) {
1036  LOG_ERR("! radio does not support setting required RADIO_PARAM_TX_MODE. Abort init.\n");
1037  return;
1038  }
1039  /* Test setting channel */
1040  if(NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, TSCH_DEFAULT_HOPPING_SEQUENCE[0]) != RADIO_RESULT_OK) {
1041  LOG_ERR("! radio does not support setting channel. Abort init.\n");
1042  return;
1043  }
1044  /* Test getting timestamp */
1045  if(NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t, sizeof(rtimer_clock_t)) != RADIO_RESULT_OK) {
1046  LOG_ERR("! radio does not support getting last packet timestamp. Abort init.\n");
1047  return;
1048  }
1049  /* Check max hopping sequence length vs default sequence length */
1050  if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
1051  LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
1052  return;
1053  }
1054 
1055  /* Init TSCH sub-modules */
1056 #if TSCH_AUTOSELECT_TIME_SOURCE
1057  nbr_table_register(eb_stats, NULL);
1058 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
1059  tsch_reset();
1060  tsch_queue_init();
1062  tsch_log_init();
1063  ringbufindex_init(&input_ringbuf, TSCH_MAX_INCOMING_PACKETS);
1064  ringbufindex_init(&dequeued_ringbuf, TSCH_DEQUEUED_ARRAY_SIZE);
1065 
1066  tsch_packet_seqno = random_rand();
1067  tsch_is_initialized = 1;
1068 
1069 #if TSCH_AUTOSTART
1070  /* Start TSCH operation.
1071  * If TSCH_AUTOSTART is not set, one needs to call NETSTACK_MAC.on() to start TSCH. */
1072  NETSTACK_MAC.on();
1073 #endif /* TSCH_AUTOSTART */
1074 
1075 #if TSCH_WITH_SIXTOP
1076  sixtop_init();
1077 #endif
1078 
1079  tsch_stats_init();
1080  tsch_roots_init();
1081 }
1082 /*---------------------------------------------------------------------------*/
1083 /* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */
1084 static void
1085 send_packet(mac_callback_t sent, void *ptr)
1086 {
1087  int ret = MAC_TX_DEFERRED;
1088  int hdr_len = 0;
1089  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
1090  uint8_t max_transmissions = 0;
1091 
1092  if(!tsch_is_associated) {
1093  if(!tsch_is_initialized) {
1094  LOG_WARN("! not initialized (see earlier logs), drop outgoing packet\n");
1095  } else {
1096  LOG_WARN("! not associated, drop outgoing packet\n");
1097  }
1098  ret = MAC_TX_ERR;
1099  mac_call_sent_callback(sent, ptr, ret, 1);
1100  return;
1101  }
1102 
1103  /* Ask for ACK if we are sending anything other than broadcast */
1104  if(!linkaddr_cmp(addr, &linkaddr_null)) {
1105  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
1106  in framer-802154.c. */
1107  if(++tsch_packet_seqno == 0) {
1108  tsch_packet_seqno++;
1109  }
1110  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno);
1111  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
1112  } else {
1113  /* Broadcast packets shall be added to broadcast queue
1114  * The broadcast address in Contiki is linkaddr_null which is equal
1115  * to tsch_eb_address */
1116  addr = &tsch_broadcast_address;
1117  }
1118 
1119  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
1120 
1121 #if LLSEC802154_ENABLED
1122  tsch_security_set_packetbuf_attr(FRAME802154_DATAFRAME);
1123 #endif /* LLSEC802154_ENABLED */
1124 
1125 #if !NETSTACK_CONF_BRIDGE_MODE
1126  /*
1127  * In the Contiki stack, the source address of a frame is set at the RDC
1128  * layer. Since TSCH doesn't use any RDC protocol and bypasses the layer to
1129  * transmit a frame, it should set the source address by itself.
1130  */
1131  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
1132 #endif
1133 
1134  max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
1135  if(max_transmissions == 0) {
1136  /* If not set by the application, use the default TSCH value */
1137  max_transmissions = TSCH_MAC_MAX_FRAME_RETRIES + 1;
1138  }
1139 
1140  if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
1141  LOG_ERR("! can't send packet due to framer error\n");
1142  ret = MAC_TX_ERR;
1143  } else {
1144  struct tsch_packet *p;
1145  struct tsch_neighbor *n;
1146  /* Enqueue packet */
1147  p = tsch_queue_add_packet(addr, max_transmissions, sent, ptr);
1148  n = tsch_queue_get_nbr(addr);
1149  if(p == NULL) {
1150  LOG_ERR("! can't send packet to ");
1151  LOG_ERR_LLADDR(addr);
1152  LOG_ERR_(" with seqno %u, queue %u/%u %u/%u\n",
1153  tsch_packet_seqno, tsch_queue_nbr_packet_count(n),
1154  TSCH_QUEUE_NUM_PER_NEIGHBOR, tsch_queue_global_packet_count(),
1155  QUEUEBUF_NUM);
1156  ret = MAC_TX_QUEUE_FULL;
1157  } else {
1158  p->header_len = hdr_len;
1159  LOG_INFO("send packet to ");
1160  LOG_INFO_LLADDR(addr);
1161  LOG_INFO_(" with seqno %u, queue %u/%u %u/%u, len %u %u\n",
1162  tsch_packet_seqno, tsch_queue_nbr_packet_count(n),
1163  TSCH_QUEUE_NUM_PER_NEIGHBOR, tsch_queue_global_packet_count(),
1164  QUEUEBUF_NUM, p->header_len, queuebuf_datalen(p->qb));
1165  }
1166  }
1167  if(ret != MAC_TX_DEFERRED) {
1168  mac_call_sent_callback(sent, ptr, ret, 1);
1169  }
1170 }
1171 /*---------------------------------------------------------------------------*/
1172 static void
1173 packet_input(void)
1174 {
1175  int frame_parsed = 1;
1176 
1177  frame_parsed = NETSTACK_FRAMER.parse();
1178 
1179  if(frame_parsed < 0) {
1180  LOG_ERR("! failed to parse %u\n", packetbuf_datalen());
1181  } else {
1182  int duplicate = 0;
1183 
1184  /* Seqno of 0xffff means no seqno */
1185  if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) != 0xffff) {
1186  /* Check for duplicates */
1187  duplicate = mac_sequence_is_duplicate();
1188  if(duplicate) {
1189  /* Drop the packet. */
1190  LOG_WARN("! drop dup ll from ");
1191  LOG_WARN_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1192  LOG_WARN_(" seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1193  } else {
1195  }
1196  }
1197 
1198  if(!duplicate) {
1199  LOG_INFO("received from ");
1200  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1201  LOG_INFO_(" with seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1202 #if TSCH_WITH_SIXTOP
1203  sixtop_input();
1204 #endif /* TSCH_WITH_SIXTOP */
1205  NETSTACK_NETWORK.input();
1206  }
1207  }
1208 }
1209 /*---------------------------------------------------------------------------*/
1210 static int
1211 turn_on(void)
1212 {
1213  if(tsch_is_initialized == 1 && tsch_is_started == 0) {
1214  tsch_is_started = 1;
1215  /* Process tx/rx callback and log messages whenever polled */
1216  process_start(&tsch_pending_events_process, NULL);
1217  if(TSCH_EB_PERIOD > 0) {
1218  /* periodically send TSCH EBs */
1219  process_start(&tsch_send_eb_process, NULL);
1220  }
1221  /* try to associate to a network or start one if setup as coordinator */
1222  process_start(&tsch_process, NULL);
1223  LOG_INFO("starting as %s\n", tsch_is_coordinator ? "coordinator": "node");
1224  return 1;
1225  }
1226  return 0;
1227 }
1228 /*---------------------------------------------------------------------------*/
1229 static int
1230 turn_off(void)
1231 {
1232  NETSTACK_RADIO.off();
1233  return 1;
1234 }
1235 /*---------------------------------------------------------------------------*/
1236 static int
1237 max_payload(void)
1238 {
1239  int framer_hdrlen;
1240  radio_value_t max_radio_payload_len;
1241  radio_result_t res;
1242 
1243  if(!tsch_is_associated) {
1244  LOG_WARN("Cannot compute max payload size: not associated\n");
1245  return 0;
1246  }
1247 
1248  res = NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN,
1249  &max_radio_payload_len);
1250 
1251  if(res == RADIO_RESULT_NOT_SUPPORTED) {
1252  LOG_ERR("Failed to retrieve max radio driver payload length\n");
1253  return 0;
1254  }
1255 
1256  /* Set packetbuf security attributes */
1257  tsch_security_set_packetbuf_attr(FRAME802154_DATAFRAME);
1258 
1259  framer_hdrlen = NETSTACK_FRAMER.length();
1260  if(framer_hdrlen < 0) {
1261  return 0;
1262  }
1263 
1264  /* Setup security... before. */
1265  return MIN(max_radio_payload_len, TSCH_PACKET_MAX_LEN)
1266  - framer_hdrlen
1267  - LLSEC802154_PACKETBUF_MIC_LEN();
1268 }
1269 /*---------------------------------------------------------------------------*/
1270 const struct mac_driver tschmac_driver = {
1271  "TSCH",
1272  tsch_init,
1273  send_packet,
1274  packet_input,
1275  turn_on,
1276  turn_off,
1277  max_payload,
1278 };
1279 /*---------------------------------------------------------------------------*/
1280 /** @} */
uint16_t src_pid
Source PAN ID.
Definition: frame802154.h:207
TSCH packet information.
Definition: tsch-types.h:97
#define TSCH_ASN_DIVISOR_INIT(div, val_)
Initialize a struct asn_divisor_t.
Definition: tsch-asn.h:86
int tsch_queue_global_packet_count(void)
Returns the number of packets currently in all TSCH queues.
Definition: tsch-queue.c:279
struct tsch_neighbor * tsch_queue_get_nbr(const linkaddr_t *addr)
Get a TSCH neighbor.
Definition: tsch-queue.c:110
void process_post_synch(struct process *p, process_event_t ev, process_data_t data)
Post a synchronous event to a process.
Definition: process.c:362
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
void ringbufindex_init(struct ringbufindex *r, uint8_t size)
Initialize a ring buffer.
Definition: ringbufindex.c:50
void tsch_log_process_pending(void)
Process pending log messages.
The parameter is not supported.
Definition: radio.h:473
int tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
Create an EB packet directly in packetbuf.
Definition: tsch-packet.c:220
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:75
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:204
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
void etimer_restart(struct etimer *et)
Restart an event timer from the current point in time.
Definition: etimer.c:199
int ringbufindex_peek_get(const struct ringbufindex *r)
Return the index of the first element which will be removed if calling ringbufindex_get.
Definition: ringbufindex.c:115
int tsch_schedule_init(void)
Module initialization, call only once at init.
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:62
void tsch_set_join_priority(uint8_t jp)
Set the TSCH join priority (JP)
Definition: tsch.c:186
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
Header file for the radio API
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
uint8_t security_enabled
1 bit.
Definition: frame802154.h:154
void tsch_log_init(void)
Initialize log module.
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:101
static void send_packet(linkaddr_t *dest)
This function is called by the 6lowpan code to send out a packet.
Definition: sicslowpan.c:1545
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:500
int mac_sequence_is_duplicate(void)
Tell whether the packetbuf is a duplicate packet.
Definition: mac-sequence.c:72
TSCH neighbor information.
Definition: tsch-types.h:109
802.15.4e slotframe (contains links)
Definition: tsch-types.h:84
void tsch_queue_init(void)
Initialize TSCH queue module.
Definition: tsch-queue.c:536
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:280
unsigned int tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, int datalen, const frame802154_t *frame, const linkaddr_t *sender, struct tsch_asn_t *asn)
Parse and check a frame protected with encryption and/or MIC.
Channel used for radio communication.
Definition: radio.h:134
struct tsch_neighbor * tsch_queue_get_time_source(void)
Get the TSCH time source (we currently assume there is only one)
Definition: tsch-queue.c:120
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition: pt.h:313
void tsch_set_ka_timeout(uint32_t timeout)
Set the desynchronization timeout after which a node sends a unicasst keep-alive (KA) to its time sou...
Definition: tsch.c:192
The MAC layer deferred the transmission for a later time.
Definition: mac.h:94
The parameter was set/read successfully.
Definition: radio.h:472
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:97
uint8_t packetbuf_hdrlen(void)
Get the length of the header in the packetbuf.
Definition: packetbuf.c:161
struct tsch_slotframe * tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
Creates and adds a new slotframe.
Definition: tsch-schedule.c:73
uint8_t(* is_in_leaf_mode)(void)
Tells whether the protocol is in leaf mode.
Definition: routing.h:190
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
Definition: radio.h:88
uint8_t src_addr[8]
Source address.
Definition: frame802154.h:203
A MAC framer for IEEE 802.15.4
const linkaddr_t linkaddr_null
The null link-layer address.
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
Definition: radio.h:180
#define RTIMER_SECOND
Number of rtimer ticks for 1 second.
Definition: rtimer.h:112
Header file for MAC sequence numbers management
void tsch_queue_free_unused_neighbors(void)
Deallocate all neighbors with empty queue.
Definition: tsch-queue.c:398
void tsch_roots_add_address(const linkaddr_t *root_address)
Add address as a potential RPL root that is a single-hop neighbor in the TSCH network.
Definition: tsch-roots.c:168
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
void sixtop_init(void)
Initialize 6top module This initialization function removes all the SFs which has been installed into...
Definition: sixtop.c:261
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:185
void sixtop_input(void)
Input a packet stored in packetbuf.
Definition: sixtop.c:204
int tsch_queue_nbr_packet_count(const struct tsch_neighbor *n)
Returns the number of packets currently a given neighbor queue (by pointer)
Definition: tsch-queue.c:286
unsigned int tsch_security_mic_len(const frame802154_t *frame)
Return MIC length.
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
struct tsch_link * tsch_schedule_add_link(struct tsch_slotframe *slotframe, uint8_t link_options, enum link_type link_type, const linkaddr_t *address, uint16_t timeslot, uint16_t channel_offset, uint8_t do_remove)
Adds a link to a slotframe.
For quick modulo operation on ASN.
Definition: tsch-asn.h:54
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:292
linkaddr_t * tsch_queue_get_nbr_address(const struct tsch_neighbor *n)
Get the address of a neighbor.
Definition: tsch-queue.c:135
struct tsch_neighbor * tsch_queue_add_nbr(const linkaddr_t *addr)
Add a TSCH neighbor queue.
Definition: tsch-queue.c:81
Header file for the Packet queue buffer management
void tsch_set_eb_period(uint32_t period)
Set the period at wich TSCH enhanced beacons (EBs) are sent.
Definition: tsch.c:199
uint8_t frame_version
2 bit.
Definition: frame802154.h:162
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
void tsch_schedule_keepalive(int immediate)
Schedule a keep-alive transmission within [timeout*0.9, timeout[ Can be called from an interrupt...
Definition: tsch.c:335
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
Definition: radio.h:173
int tsch_queue_update_time_source(const linkaddr_t *new_addr)
Update TSCH time source.
Definition: tsch-queue.c:142
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
Routing driver header file
Main API declarations for TSCH.
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:84
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
#define RTIMER_BUSYWAIT_UNTIL_ABS(cond, t0, max_time)
Busy-wait until a condition.
Definition: rtimer.h:202
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
#define TSCH_ASN_INIT(asn, ms1b_, ls4b_)
Initialize ASN.
Definition: tsch-asn.h:62
void tsch_roots_init(void)
Initialize the list of RPL network roots.
Definition: tsch-roots.c:181
void tsch_security_set_packetbuf_attr(uint8_t frame_type)
Set packetbuf (or eackbuf) attributes depending on a given frame type.
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
Definition: radio.h:443
uint8_t frame_type
3 bit.
Definition: frame802154.h:153
void tsch_slot_operation_sync(rtimer_clock_t next_slot_start, struct tsch_asn_t *next_slot_asn)
Set global time before starting slot operation, with a rtimer time and an ASN.
Parameters used by the frame802154_create() function.
Definition: frame802154.h:198
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition: pt.h:265
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
A timer.
Definition: etimer.h:76
6TiSCH Operation Sublayer (6top) APIs
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition: radio.h:466
#define TSCH_ASN_DIFF(asn1, asn2)
Returns the 32-bit diff between asn1 and asn2.
Definition: tsch-asn.h:82
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void tsch_queue_reset(void)
Reset neighbor queues module.
Definition: tsch-queue.c:380
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
Definition: radio.h:448
void(* send)(mac_callback_t sent_callback, void *ptr)
Send a packet from the packetbuf.
Definition: mac.h:69
int tsch_schedule_remove_all_slotframes(void)
Removes all slotframes, resulting in an empty schedule.
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Definition: radio.h:453
int ringbufindex_get(struct ringbufindex *r)
Remove the first element and return its index.
Definition: ringbufindex.c:90
void tsch_disassociate(void)
Leave the TSCH network we are currently in.
Definition: tsch.c:583
void tsch_set_pan_secured(int enable)
Enable/disable security.
Definition: tsch.c:180
void tsch_roots_set_self_to_root(uint8_t is_root)
Set the root status of the local node.
Definition: tsch-roots.c:172
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
void mac_sequence_register_seqno(void)
Register the sequence number of the packetbuf.
Definition: mac-sequence.c:101
#define PROCESS_PT_SPAWN(pt, thread)
Spawn a protothread from the process.
Definition: process.h:211
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition: mac.h:81
void tsch_queue_free_packet(struct tsch_packet *p)
Free a packet.
Definition: tsch-queue.c:314
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
Last packet timestamp, of type rtimer_clock_t.
Definition: radio.h:278
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
struct tsch_packet * tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, mac_callback_t sent, void *ptr)
Add packet to neighbor queue.
Definition: tsch-queue.c:229
void tsch_adaptive_timesync_reset(void)
Reset the status of the module.
Stores data about an incoming packet.
Definition: tsch-types.h:149
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:192
Header file for the logging system
void tsch_slot_operation_start(void)
Start actual slot operation.
int tsch_packet_parse_eb(const uint8_t *buf, int buf_size, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len, int frame_without_mic)
Parse EB.
Definition: tsch-packet.c:387
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
The ASN is an absolute slot number over 5 bytes.
Definition: tsch-asn.h:48
void tsch_schedule_create_minimal(void)
Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH.
#define PROCESS_WAIT_UNTIL(c)
Wait for a condition to occur.
Definition: process.h:192
void tsch_set_coordinator(int enable)
Set the node as PAN coordinator.
Definition: tsch.c:169
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99