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 
61 #if TSCH_WITH_SIXTOP
63 #endif
64 
65 #if FRAME802154_VERSION < FRAME802154_IEEE802154_2015
66 #error TSCH: FRAME802154_VERSION must be at least FRAME802154_IEEE802154_2015
67 #endif
68 
69 /* Log configuration */
70 #include "sys/log.h"
71 #define LOG_MODULE "TSCH"
72 #define LOG_LEVEL LOG_LEVEL_MAC
73 
74 /* Use to collect link statistics even on Keep-Alive, even though they were
75  * not sent from an upper layer and don't have a valid packet_sent callback */
76 #ifndef TSCH_LINK_NEIGHBOR_CALLBACK
77 #if NETSTACK_CONF_WITH_IPV6
78 void uip_ds6_link_neighbor_callback(int status, int numtx);
79 #define TSCH_LINK_NEIGHBOR_CALLBACK(dest, status, num) uip_ds6_link_neighbor_callback(status, num)
80 #endif /* NETSTACK_CONF_WITH_IPV6 */
81 #endif /* TSCH_LINK_NEIGHBOR_CALLBACK */
82 
83 /* The address of the last node we received an EB from (other than our time source).
84  * Used for recovery */
85 static linkaddr_t last_eb_nbr_addr;
86 /* The join priority advertised by last_eb_nbr_addr */
87 static uint8_t last_eb_nbr_jp;
88 
89 /* Let TSCH select a time source with no help of an upper layer.
90  * We do so using statistics from incoming EBs */
91 #if TSCH_AUTOSELECT_TIME_SOURCE
92 int best_neighbor_eb_count;
93 struct eb_stat {
94  int rx_count;
95  int jp;
96 };
97 NBR_TABLE(struct eb_stat, eb_stats);
98 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
99 
100 /* TSCH channel hopping sequence */
101 uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
102 struct tsch_asn_divisor_t tsch_hopping_sequence_length;
103 
104 /* Default TSCH timeslot timing (in micro-second) */
105 static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = {
106  TSCH_DEFAULT_TS_CCA_OFFSET,
107  TSCH_DEFAULT_TS_CCA,
108  TSCH_DEFAULT_TS_TX_OFFSET,
109  TSCH_DEFAULT_TS_RX_OFFSET,
110  TSCH_DEFAULT_TS_RX_ACK_DELAY,
111  TSCH_DEFAULT_TS_TX_ACK_DELAY,
112  TSCH_DEFAULT_TS_RX_WAIT,
113  TSCH_DEFAULT_TS_ACK_WAIT,
114  TSCH_DEFAULT_TS_RX_TX,
115  TSCH_DEFAULT_TS_MAX_ACK,
116  TSCH_DEFAULT_TS_MAX_TX,
117  TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
118 };
119 /* TSCH timeslot timing (in rtimer ticks) */
120 rtimer_clock_t tsch_timing[tsch_ts_elements_count];
121 
122 #if LINKADDR_SIZE == 8
123 /* 802.15.4 broadcast MAC address */
124 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
125 /* Address used for the EB virtual neighbor queue */
126 const linkaddr_t tsch_eb_address = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
127 #else /* LINKADDR_SIZE == 8 */
128 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff } };
129 const linkaddr_t tsch_eb_address = { { 0, 0 } };
130 #endif /* LINKADDR_SIZE == 8 */
131 
132 /* Is TSCH started? */
133 int tsch_is_started = 0;
134 /* Has TSCH initialization failed? */
135 int tsch_is_initialized = 0;
136 /* Are we coordinator of the TSCH network? */
137 int tsch_is_coordinator = 0;
138 /* Are we associated to a TSCH network? */
139 int tsch_is_associated = 0;
140 /* Total number of associations since boot */
141 int tsch_association_count = 0;
142 /* Is the PAN running link-layer security? */
143 int tsch_is_pan_secured = LLSEC802154_ENABLED;
144 /* The current Absolute Slot Number (ASN) */
145 struct tsch_asn_t tsch_current_asn;
146 /* Device rank or join priority:
147  * For PAN coordinator: 0 -- lower is better */
148 uint8_t tsch_join_priority;
149 /* The current TSCH sequence number, used for unicast data frames only */
150 static uint8_t tsch_packet_seqno;
151 /* Current period for EB output */
152 static clock_time_t tsch_current_eb_period;
153 /* Current period for keepalive output */
154 static clock_time_t tsch_current_ka_timeout;
155 
156 /* timer for sending keepalive messages */
157 static struct ctimer keepalive_timer;
158 
159 /* Statistics on the current session */
160 unsigned long tx_count;
161 unsigned long rx_count;
162 unsigned long sync_count;
163 
164 /* TSCH processes and protothreads */
165 PT_THREAD(tsch_scan(struct pt *pt));
166 PROCESS(tsch_process, "main process");
167 PROCESS(tsch_send_eb_process, "send EB process");
168 PROCESS(tsch_pending_events_process, "pending events process");
169 
170 /* Other function prototypes */
171 static void packet_input(void);
172 
173 /* Getters and setters */
174 
175 /*---------------------------------------------------------------------------*/
176 void
178 {
179  if(tsch_is_coordinator != enable) {
180  tsch_is_associated = 0;
181  }
182  tsch_is_coordinator = enable;
183  tsch_set_eb_period(TSCH_EB_PERIOD);
184 }
185 /*---------------------------------------------------------------------------*/
186 void
188 {
189  tsch_is_pan_secured = LLSEC802154_ENABLED && enable;
190 }
191 /*---------------------------------------------------------------------------*/
192 void
194 {
195  tsch_join_priority = jp;
196 }
197 /*---------------------------------------------------------------------------*/
198 void
199 tsch_set_ka_timeout(uint32_t timeout)
200 {
201  tsch_current_ka_timeout = timeout;
202  if(timeout == 0) {
203  ctimer_stop(&keepalive_timer);
204  } else {
206  }
207 }
208 /*---------------------------------------------------------------------------*/
209 void
210 tsch_set_eb_period(uint32_t period)
211 {
212  tsch_current_eb_period = MIN(period, TSCH_MAX_EB_PERIOD);
213 }
214 /*---------------------------------------------------------------------------*/
215 static void
216 tsch_reset(void)
217 {
218  int i;
219  frame802154_set_pan_id(0xffff);
220  /* First make sure pending packet callbacks are sent etc */
221  process_post_synch(&tsch_pending_events_process, PROCESS_EVENT_POLL, NULL);
222  /* Reset neighbor queues */
224  /* Remove unused neighbors */
227  /* Initialize global variables */
228  tsch_join_priority = 0xff;
229  TSCH_ASN_INIT(tsch_current_asn, 0, 0);
230  current_link = NULL;
231  /* Reset timeslot timing to defaults */
232  for(i = 0; i < tsch_ts_elements_count; i++) {
233  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
234  }
235 #ifdef TSCH_CALLBACK_LEAVING_NETWORK
236  TSCH_CALLBACK_LEAVING_NETWORK();
237 #endif
238  linkaddr_copy(&last_eb_nbr_addr, &linkaddr_null);
239 #if TSCH_AUTOSELECT_TIME_SOURCE
240  struct nbr_sync_stat *stat;
241  best_neighbor_eb_count = 0;
242  /* Remove all nbr stats */
243  stat = nbr_table_head(sync_stats);
244  while(stat != NULL) {
245  nbr_table_remove(sync_stats, stat);
246  stat = nbr_table_next(sync_stats, stat);
247  }
248 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
249  tsch_set_eb_period(TSCH_EB_PERIOD);
250 }
251 /* TSCH keep-alive functions */
252 
253 /*---------------------------------------------------------------------------*/
254 /* Tx callback for keepalive messages */
255 static void
256 keepalive_packet_sent(void *ptr, int status, int transmissions)
257 {
258  /* Update neighbor link statistics */
259  link_stats_packet_sent(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
260  /* Call RPL callback if RPL is enabled */
261 #ifdef TSCH_CALLBACK_KA_SENT
262  TSCH_CALLBACK_KA_SENT(status, transmissions);
263 #endif /* TSCH_CALLBACK_KA_SENT */
264  LOG_INFO("KA sent to ");
265  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
266  LOG_INFO_(", st %d-%d\n", status, transmissions);
267 
268  /* We got no ack, try to recover by switching to the last neighbor we received an EB from */
269  if(status == MAC_TX_NOACK) {
270  if(linkaddr_cmp(&last_eb_nbr_addr, &linkaddr_null)) {
271  LOG_WARN("not able to re-synchronize, received no EB from other neighbors\n");
272  if(sync_count == 0) {
273  /* We got no synchronization at all in this session, leave the network */
275  }
276  } else {
277  LOG_WARN("re-synchronizing on ");
278  LOG_WARN_LLADDR(&last_eb_nbr_addr);
279  LOG_WARN_("\n");
280  /* We simply pick the last neighbor we receiver sync information from */
281  tsch_queue_update_time_source(&last_eb_nbr_addr);
282  tsch_join_priority = last_eb_nbr_jp + 1;
283  /* Try to get in sync ASAP */
285  return;
286  }
287  }
288 
290 }
291 /*---------------------------------------------------------------------------*/
292 /* Prepare and send a keepalive message */
293 static void
294 keepalive_send(void *ptr)
295 {
296  if(tsch_is_associated) {
298  if(n != NULL) {
299  /* Simply send an empty packet */
300  packetbuf_clear();
301  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &n->addr);
302  NETSTACK_MAC.send(keepalive_packet_sent, NULL);
303  LOG_INFO("sending KA to ");
304  LOG_INFO_LLADDR(&n->addr);
305  LOG_INFO_("\n");
306  } else {
307  LOG_ERR("no timesource - KA not sent\n");
308  }
309  }
310 }
311 /*---------------------------------------------------------------------------*/
312 /* Set ctimer to send a keepalive message after expiration of TSCH_KEEPALIVE_TIMEOUT */
313 void
315 {
316  /* Pick a delay in the range [tsch_current_ka_timeout*0.9, tsch_current_ka_timeout[ */
317  if(!tsch_is_coordinator && tsch_is_associated && tsch_current_ka_timeout > 0) {
318  unsigned long delay = (tsch_current_ka_timeout - tsch_current_ka_timeout / 10)
319  + random_rand() % (tsch_current_ka_timeout / 10);
320  ctimer_set(&keepalive_timer, delay, keepalive_send, NULL);
321  }
322 }
323 /*---------------------------------------------------------------------------*/
324 /* Set ctimer to send a keepalive message immediately */
325 void
327 {
328  /* Pick a delay in the range [tsch_current_ka_timeout*0.9, tsch_current_ka_timeout[ */
329  if(!tsch_is_coordinator && tsch_is_associated) {
330  ctimer_set(&keepalive_timer, 0, keepalive_send, NULL);
331  }
332 }
333 /*---------------------------------------------------------------------------*/
334 static void
335 eb_input(struct input_packet *current_input)
336 {
337  /* LOG_INFO("EB received\n"); */
338  frame802154_t frame;
339  /* Verify incoming EB (does its ASN match our Rx time?),
340  * and update our join priority. */
341  struct ieee802154_ies eb_ies;
342 
343  if(tsch_packet_parse_eb(current_input->payload, current_input->len,
344  &frame, &eb_ies, NULL, 1)) {
345  /* PAN ID check and authentication done at rx time */
346 
347  /* Got an EB from a different neighbor than our time source, keep enough data
348  * to switch to it in case we lose the link to our time source */
350  if(ts == NULL || !linkaddr_cmp(&last_eb_nbr_addr, &ts->addr)) {
351  linkaddr_copy(&last_eb_nbr_addr, (linkaddr_t *)&frame.src_addr);
352  last_eb_nbr_jp = eb_ies.ie_join_priority;
353  }
354 
355 #if TSCH_AUTOSELECT_TIME_SOURCE
356  if(!tsch_is_coordinator) {
357  /* Maintain EB received counter for every neighbor */
358  struct eb_stat *stat = (struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, (linkaddr_t *)&frame.src_addr);
359  if(stat == NULL) {
360  stat = (struct eb_stat *)nbr_table_add_lladdr(eb_stats, (linkaddr_t *)&frame.src_addr, NBR_TABLE_REASON_MAC, NULL);
361  }
362  if(stat != NULL) {
363  stat->rx_count++;
364  stat->jp = eb_ies.ie_join_priority;
365  best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count);
366  }
367  /* Select best time source */
368  struct eb_stat *best_stat = NULL;
369  stat = nbr_table_head(eb_stats);
370  while(stat != NULL) {
371  /* Is neighbor eligible as a time source? */
372  if(stat->rx_count > best_neighbor_eb_count / 2) {
373  if(best_stat == NULL ||
374  stat->jp < best_stat->jp) {
375  best_stat = stat;
376  }
377  }
378  stat = nbr_table_next(eb_stats, stat);
379  }
380  /* Update time source */
381  if(best_stat != NULL) {
382  tsch_queue_update_time_source(nbr_table_get_lladdr(eb_stats, best_stat));
383  tsch_join_priority = best_stat->jp + 1;
384  }
385  }
386 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
387 
388  /* Did the EB come from our time source? */
389  if(ts != NULL && linkaddr_cmp((linkaddr_t *)&frame.src_addr, &ts->addr)) {
390  /* Check for ASN drift */
391  int32_t asn_diff = TSCH_ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn);
392  if(asn_diff != 0) {
393  /* We disagree with our time source's ASN -- leave the network */
394  LOG_WARN("! ASN drifted by %ld, leaving the network\n", asn_diff);
396  }
397 
398  if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) {
399  /* Join priority unacceptable. Leave network. */
400  LOG_WARN("! EB JP too high %u, leaving the network\n",
401  eb_ies.ie_join_priority);
403  } else {
404 #if TSCH_AUTOSELECT_TIME_SOURCE
405  /* Update join priority */
406  if(tsch_join_priority != eb_ies.ie_join_priority + 1) {
407  LOG_INFO("update JP from EB %u -> %u\n",
408  tsch_join_priority, eb_ies.ie_join_priority + 1);
409  tsch_join_priority = eb_ies.ie_join_priority + 1;
410  }
411 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
412  }
413  }
414  }
415 }
416 /*---------------------------------------------------------------------------*/
417 /* Process pending input packet(s) */
418 static void
419 tsch_rx_process_pending()
420 {
421  int16_t input_index;
422  /* Loop on accessing (without removing) a pending input packet */
423  while((input_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
424  struct input_packet *current_input = &input_array[input_index];
425  frame802154_t frame;
426  uint8_t ret = frame802154_parse(current_input->payload, current_input->len, &frame);
427  int is_data = ret && frame.fcf.frame_type == FRAME802154_DATAFRAME;
428  int is_eb = ret
429  && frame.fcf.frame_version == FRAME802154_IEEE802154_2015
430  && frame.fcf.frame_type == FRAME802154_BEACONFRAME;
431 
432  if(is_data) {
433  /* Skip EBs and other control messages */
434  /* Copy to packetbuf for processing */
435  packetbuf_copyfrom(current_input->payload, current_input->len);
436  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, current_input->rssi);
437  packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, current_input->channel);
438  }
439 
440  if(is_data) {
441  /* Pass to upper layers */
442  packet_input();
443  } else if(is_eb) {
444  eb_input(current_input);
445  }
446 
447  /* Remove input from ringbuf */
448  ringbufindex_get(&input_ringbuf);
449  }
450 }
451 /*---------------------------------------------------------------------------*/
452 /* Pass sent packets to upper layer */
453 static void
454 tsch_tx_process_pending(void)
455 {
456  int16_t dequeued_index;
457  /* Loop on accessing (without removing) a pending input packet */
458  while((dequeued_index = ringbufindex_peek_get(&dequeued_ringbuf)) != -1) {
459  struct tsch_packet *p = dequeued_array[dequeued_index];
460  /* Put packet into packetbuf for packet_sent callback */
461  queuebuf_to_packetbuf(p->qb);
462  LOG_INFO("packet sent to ");
463  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
464  LOG_INFO_(", seqno %u, status %d, tx %d\n",
465  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), p->ret, p->transmissions);
466  /* Call packet_sent callback */
467  mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
468  /* Free packet queuebuf */
470  /* Free all unused neighbors */
472  /* Remove dequeued packet from ringbuf */
473  ringbufindex_get(&dequeued_ringbuf);
474  }
475 }
476 /*---------------------------------------------------------------------------*/
477 /* Setup TSCH as a coordinator */
478 static void
479 tsch_start_coordinator(void)
480 {
481  frame802154_set_pan_id(IEEE802154_PANID);
482  /* Initialize hopping sequence as default */
483  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
484  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
485 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
487 #endif
488 
489  tsch_is_associated = 1;
490  tsch_join_priority = 0;
491 
492  LOG_INFO("starting as coordinator, PAN ID %x, asn-%x.%lx\n",
493  frame802154_get_pan_id(), tsch_current_asn.ms1b, tsch_current_asn.ls4b);
494 
495  /* Start slot operation */
496  tsch_slot_operation_sync(RTIMER_NOW(), &tsch_current_asn);
497 }
498 /*---------------------------------------------------------------------------*/
499 /* Leave the TSCH network */
500 void
502 {
503  if(tsch_is_associated == 1) {
504  tsch_is_associated = 0;
505  process_post(&tsch_process, PROCESS_EVENT_POLL, NULL);
506  }
507 }
508 /*---------------------------------------------------------------------------*/
509 /* Attempt to associate to a network form an incoming EB */
510 static int
511 tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
512 {
513  frame802154_t frame;
514  struct ieee802154_ies ies;
515  uint8_t hdrlen;
516  int i;
517 
518  if(input_eb == NULL || tsch_packet_parse_eb(input_eb->payload, input_eb->len,
519  &frame, &ies, &hdrlen, 0) == 0) {
520  LOG_ERR("! failed to parse EB (len %u)\n", input_eb->len);
521  return 0;
522  }
523 
524  tsch_current_asn = ies.ie_asn;
525  tsch_join_priority = ies.ie_join_priority + 1;
526 
527 #if TSCH_JOIN_SECURED_ONLY
528  if(frame.fcf.security_enabled == 0) {
529  LOG_ERR("! parse_eb: EB is not secured\n");
530  return 0;
531  }
532 #endif /* TSCH_JOIN_SECURED_ONLY */
533 #if LLSEC802154_ENABLED
534  if(!tsch_security_parse_frame(input_eb->payload, hdrlen,
535  input_eb->len - hdrlen - tsch_security_mic_len(&frame),
536  &frame, (linkaddr_t*)&frame.src_addr, &tsch_current_asn)) {
537  LOG_ERR("! parse_eb: failed to authenticate\n");
538  return 0;
539  }
540 #endif /* LLSEC802154_ENABLED */
541 
542 #if !LLSEC802154_ENABLED
543  if(frame.fcf.security_enabled == 1) {
544  LOG_ERR("! parse_eb: we do not support security, but EB is secured\n");
545  return 0;
546  }
547 #endif /* !LLSEC802154_ENABLED */
548 
549 #if TSCH_JOIN_MY_PANID_ONLY
550  /* Check if the EB comes from the PAN ID we expect */
551  if(frame.src_pid != IEEE802154_PANID) {
552  LOG_ERR("! parse_eb: PAN ID %x != %x\n", frame.src_pid, IEEE802154_PANID);
553  return 0;
554  }
555 #endif /* TSCH_JOIN_MY_PANID_ONLY */
556 
557  /* There was no join priority (or 0xff) in the EB, do not join */
558  if(ies.ie_join_priority == 0xff) {
559  LOG_ERR("! parse_eb: no join priority\n");
560  return 0;
561  }
562 
563  /* TSCH timeslot timing */
564  for(i = 0; i < tsch_ts_elements_count; i++) {
565  if(ies.ie_tsch_timeslot_id == 0) {
566  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
567  } else {
568  tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]);
569  }
570  }
571 
572  /* TSCH hopping sequence */
573  if(ies.ie_channel_hopping_sequence_id == 0) {
574  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
575  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
576  } else {
577  if(ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
578  memcpy(tsch_hopping_sequence, ies.ie_hopping_sequence_list, ies.ie_hopping_sequence_len);
579  TSCH_ASN_DIVISOR_INIT(tsch_hopping_sequence_length, ies.ie_hopping_sequence_len);
580  } else {
581  LOG_ERR("! parse_eb: hopping sequence too long (%u)\n", ies.ie_hopping_sequence_len);
582  return 0;
583  }
584  }
585 
586 #if TSCH_CHECK_TIME_AT_ASSOCIATION > 0
587  /* Divide by 4k and multiply again to avoid integer overflow */
588  uint32_t expected_asn = 4096 * TSCH_CLOCK_TO_SLOTS(clock_time() / 4096, tsch_timing_timeslot_length); /* Expected ASN based on our current time*/
589  int32_t asn_threshold = TSCH_CHECK_TIME_AT_ASSOCIATION * 60ul * TSCH_CLOCK_TO_SLOTS(CLOCK_SECOND, tsch_timing_timeslot_length);
590  int32_t asn_diff = (int32_t)tsch_current_asn.ls4b - expected_asn;
591  if(asn_diff > asn_threshold) {
592  LOG_ERR("! EB ASN rejected %lx %lx %ld\n",
593  tsch_current_asn.ls4b, expected_asn, asn_diff);
594  return 0;
595  }
596 #endif
597 
598 #if TSCH_INIT_SCHEDULE_FROM_EB
599  /* Create schedule */
600  if(ies.ie_tsch_slotframe_and_link.num_slotframes == 0) {
601 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
602  LOG_INFO("parse_eb: no schedule, setting up minimal schedule\n");
604 #else
605  LOG_INFO("parse_eb: no schedule\n");
606 #endif
607  } else {
608  /* First, empty current schedule */
610  /* We support only 0 or 1 slotframe in this IE */
611  int num_links = ies.ie_tsch_slotframe_and_link.num_links;
612  if(num_links <= FRAME802154E_IE_MAX_LINKS) {
613  int i;
615  ies.ie_tsch_slotframe_and_link.slotframe_handle,
616  ies.ie_tsch_slotframe_and_link.slotframe_size);
617  for(i = 0; i < num_links; i++) {
619  ies.ie_tsch_slotframe_and_link.links[i].link_options,
620  LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
621  ies.ie_tsch_slotframe_and_link.links[i].timeslot, ies.ie_tsch_slotframe_and_link.links[i].channel_offset);
622  }
623  } else {
624  LOG_ERR("! parse_eb: too many links in schedule (%u)\n", num_links);
625  return 0;
626  }
627  }
628 #endif /* TSCH_INIT_SCHEDULE_FROM_EB */
629 
630  if(tsch_join_priority < TSCH_MAX_JOIN_PRIORITY) {
631  struct tsch_neighbor *n;
632 
633  /* Add coordinator to list of neighbors, lock the entry */
634  n = tsch_queue_add_nbr((linkaddr_t *)&frame.src_addr);
635 
636  if(n != NULL) {
637  tsch_queue_update_time_source((linkaddr_t *)&frame.src_addr);
638 
639  /* Set PANID */
640  frame802154_set_pan_id(frame.src_pid);
641 
642  /* Synchronize on EB */
643  tsch_slot_operation_sync(timestamp - tsch_timing[tsch_ts_tx_offset], &tsch_current_asn);
644 
645  /* Update global flags */
646  tsch_is_associated = 1;
647  tsch_is_pan_secured = frame.fcf.security_enabled;
648  tx_count = 0;
649  rx_count = 0;
650  sync_count = 0;
651 
652  /* Start sending keep-alives now that tsch_is_associated is set */
654 
655 #ifdef TSCH_CALLBACK_JOINING_NETWORK
656  TSCH_CALLBACK_JOINING_NETWORK();
657 #endif
658 
659  tsch_association_count++;
660  LOG_INFO("association done (%u), sec %u, PAN ID %x, asn-%x.%lx, jp %u, timeslot id %u, hopping id %u, slotframe len %u with %u links, from ",
661  tsch_association_count,
662  tsch_is_pan_secured,
663  frame.src_pid,
664  tsch_current_asn.ms1b, tsch_current_asn.ls4b, tsch_join_priority,
665  ies.ie_tsch_timeslot_id,
666  ies.ie_channel_hopping_sequence_id,
667  ies.ie_tsch_slotframe_and_link.slotframe_size,
668  ies.ie_tsch_slotframe_and_link.num_links);
669  LOG_INFO_LLADDR((const linkaddr_t *)&frame.src_addr);
670  LOG_INFO_("\n");
671 
672  return 1;
673  }
674  }
675  LOG_ERR("! did not associate.\n");
676  return 0;
677 }
678 /* Processes and protothreads used by TSCH */
679 
680 /*---------------------------------------------------------------------------*/
681 /* Scanning protothread, called by tsch_process:
682  * Listen to different channels, and when receiving an EB,
683  * attempt to associate.
684  */
685 PT_THREAD(tsch_scan(struct pt *pt))
686 {
687  PT_BEGIN(pt);
688 
689  static struct input_packet input_eb;
690  static struct etimer scan_timer;
691  /* Time when we started scanning on current_channel */
692  static clock_time_t current_channel_since;
693 
694  TSCH_ASN_INIT(tsch_current_asn, 0, 0);
695 
696  etimer_set(&scan_timer, CLOCK_SECOND / TSCH_ASSOCIATION_POLL_FREQUENCY);
697  current_channel_since = clock_time();
698 
699  while(!tsch_is_associated && !tsch_is_coordinator) {
700  /* Hop to any channel offset */
701  static uint8_t current_channel = 0;
702 
703  /* We are not coordinator, try to associate */
704  rtimer_clock_t t0;
705  int is_packet_pending = 0;
706  clock_time_t now_time = clock_time();
707 
708  /* Switch to a (new) channel for scanning */
709  if(current_channel == 0 || now_time - current_channel_since > TSCH_CHANNEL_SCAN_DURATION) {
710  /* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
711  uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
712  random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
713  if(current_channel != scan_channel) {
714  NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
715  current_channel = scan_channel;
716  LOG_INFO("scanning on channel %u\n", scan_channel);
717  }
718  current_channel_since = now_time;
719  }
720 
721  /* Turn radio on and wait for EB */
722  NETSTACK_RADIO.on();
723 
724  is_packet_pending = NETSTACK_RADIO.pending_packet();
725  if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
726  /* If we are currently receiving a packet, wait until end of reception */
727  t0 = RTIMER_NOW();
728  BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
729  }
730 
731  if(is_packet_pending) {
732  /* Read packet */
733  input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
734 
735  /* Save packet timestamp */
736  NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
737 
738  /* Parse EB and attempt to associate */
739  LOG_INFO("scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
740 
741  tsch_associate(&input_eb, t0);
742  }
743 
744  if(tsch_is_associated) {
745  /* End of association, turn the radio off */
746  NETSTACK_RADIO.off();
747  } else if(!tsch_is_coordinator) {
748  /* Go back to scanning */
749  etimer_reset(&scan_timer);
750  PT_WAIT_UNTIL(pt, etimer_expired(&scan_timer));
751  }
752  }
753 
754  PT_END(pt);
755 }
756 
757 /*---------------------------------------------------------------------------*/
758 /* The main TSCH process */
759 PROCESS_THREAD(tsch_process, ev, data)
760 {
761  static struct pt scan_pt;
762 
763  PROCESS_BEGIN();
764 
765  while(1) {
766 
767  while(!tsch_is_associated) {
768  if(tsch_is_coordinator) {
769  /* We are coordinator, start operating now */
770  tsch_start_coordinator();
771  } else {
772  /* Start scanning, will attempt to join when receiving an EB */
773  PROCESS_PT_SPAWN(&scan_pt, tsch_scan(&scan_pt));
774  }
775  }
776 
777  /* We are part of a TSCH network, start slot operation */
779 
780  /* Yield our main process. Slot operation will re-schedule itself
781  * as long as we are associated */
782  PROCESS_YIELD_UNTIL(!tsch_is_associated);
783 
784  LOG_WARN("leaving the network, stats: tx %lu, rx %lu, sync %lu\n",
785  tx_count, rx_count, sync_count);
786 
787  /* Will need to re-synchronize */
788  tsch_reset();
789  }
790 
791  PROCESS_END();
792 }
793 
794 /*---------------------------------------------------------------------------*/
795 /* A periodic process to send TSCH Enhanced Beacons (EB) */
796 PROCESS_THREAD(tsch_send_eb_process, ev, data)
797 {
798  static struct etimer eb_timer;
799 
800  PROCESS_BEGIN();
801 
802  /* Wait until association */
803  etimer_set(&eb_timer, CLOCK_SECOND / 10);
804  while(!tsch_is_associated) {
806  etimer_reset(&eb_timer);
807  }
808 
809  /* Set an initial delay except for coordinator, which should send an EB asap */
810  if(!tsch_is_coordinator) {
811  etimer_set(&eb_timer, random_rand() % TSCH_EB_PERIOD);
813  }
814 
815  while(1) {
816  unsigned long delay;
817 
818  if(tsch_is_associated && tsch_current_eb_period > 0) {
819  /* Enqueue EB only if there isn't already one in queue */
820  if(tsch_queue_packet_count(&tsch_eb_address) == 0) {
821  uint8_t hdr_len = 0;
822  uint8_t tsch_sync_ie_offset;
823  /* Prepare the EB packet and schedule it to be sent */
824  if(tsch_packet_create_eb(&hdr_len, &tsch_sync_ie_offset) > 0) {
825  struct tsch_packet *p;
826  /* Enqueue EB packet, for a single transmission only */
827  if(!(p = tsch_queue_add_packet(&tsch_eb_address, 1, NULL, NULL))) {
828  LOG_ERR("! could not enqueue EB packet\n");
829  } else {
830  LOG_INFO("TSCH: enqueue EB packet %u %u\n",
832  p->tsch_sync_ie_offset = tsch_sync_ie_offset;
833  p->header_len = hdr_len;
834  }
835  }
836  }
837  }
838  if(tsch_current_eb_period > 0) {
839  /* Next EB transmission with a random delay
840  * within [tsch_current_eb_period*0.75, tsch_current_eb_period[ */
841  delay = (tsch_current_eb_period - tsch_current_eb_period / 4)
842  + random_rand() % (tsch_current_eb_period / 4);
843  } else {
844  delay = TSCH_EB_PERIOD;
845  }
846  etimer_set(&eb_timer, delay);
848  }
849  PROCESS_END();
850 }
851 
852 /*---------------------------------------------------------------------------*/
853 /* A process that is polled from interrupt and calls tx/rx input
854  * callbacks, outputs pending logs. */
855 PROCESS_THREAD(tsch_pending_events_process, ev, data)
856 {
857  PROCESS_BEGIN();
858  while(1) {
859  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
860  tsch_rx_process_pending();
861  tsch_tx_process_pending();
863  }
864  PROCESS_END();
865 }
866 
867 /* Functions from the Contiki MAC layer driver interface */
868 
869 /*---------------------------------------------------------------------------*/
870 static void
871 tsch_init(void)
872 {
873  radio_value_t radio_rx_mode;
874  radio_value_t radio_tx_mode;
875  rtimer_clock_t t;
876 
877  /* Radio Rx mode */
878  if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) {
879  LOG_ERR("! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
880  return;
881  }
882  /* Disable radio in frame filtering */
883  radio_rx_mode &= ~RADIO_RX_MODE_ADDRESS_FILTER;
884  /* Unset autoack */
885  radio_rx_mode &= ~RADIO_RX_MODE_AUTOACK;
886  /* Set radio in poll mode */
887  radio_rx_mode |= RADIO_RX_MODE_POLL_MODE;
888  if(NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode) != RADIO_RESULT_OK) {
889  LOG_ERR("! radio does not support setting required RADIO_PARAM_RX_MODE. Abort init.\n");
890  return;
891  }
892 
893  /* Radio Tx mode */
894  if(NETSTACK_RADIO.get_value(RADIO_PARAM_TX_MODE, &radio_tx_mode) != RADIO_RESULT_OK) {
895  LOG_ERR("! radio does not support getting RADIO_PARAM_TX_MODE. Abort init.\n");
896  return;
897  }
898  /* Unset CCA */
899  radio_tx_mode &= ~RADIO_TX_MODE_SEND_ON_CCA;
900  if(NETSTACK_RADIO.set_value(RADIO_PARAM_TX_MODE, radio_tx_mode) != RADIO_RESULT_OK) {
901  LOG_ERR("! radio does not support setting required RADIO_PARAM_TX_MODE. Abort init.\n");
902  return;
903  }
904  /* Test setting channel */
905  if(NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, TSCH_DEFAULT_HOPPING_SEQUENCE[0]) != RADIO_RESULT_OK) {
906  LOG_ERR("! radio does not support setting channel. Abort init.\n");
907  return;
908  }
909  /* Test getting timestamp */
910  if(NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t, sizeof(rtimer_clock_t)) != RADIO_RESULT_OK) {
911  LOG_ERR("! radio does not support getting last packet timestamp. Abort init.\n");
912  return;
913  }
914  /* Check max hopping sequence length vs default sequence length */
915  if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
916  LOG_ERR("! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
917  }
918 
919  /* Init the queuebuf and TSCH sub-modules */
920  queuebuf_init();
921  tsch_reset();
922  tsch_queue_init();
924  tsch_log_init();
925  ringbufindex_init(&input_ringbuf, TSCH_MAX_INCOMING_PACKETS);
926  ringbufindex_init(&dequeued_ringbuf, TSCH_DEQUEUED_ARRAY_SIZE);
927 #if TSCH_AUTOSELECT_TIME_SOURCE
928  nbr_table_register(sync_stats, NULL);
929 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
930 
931  tsch_packet_seqno = random_rand();
932  tsch_is_initialized = 1;
933 
934 #if TSCH_AUTOSTART
935  /* Start TSCH operation.
936  * If TSCH_AUTOSTART is not set, one needs to call NETSTACK_MAC.on() to start TSCH. */
937  NETSTACK_MAC.on();
938 #endif /* TSCH_AUTOSTART */
939 
940 #if TSCH_WITH_SIXTOP
941  sixtop_init();
942 #endif
943 }
944 /*---------------------------------------------------------------------------*/
945 /* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */
946 static void
947 send_packet(mac_callback_t sent, void *ptr)
948 {
949  int ret = MAC_TX_DEFERRED;
950  int hdr_len = 0;
951  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
952  uint8_t max_transmissions = 0;
953 
954  if(!tsch_is_associated) {
955  if(!tsch_is_initialized) {
956  LOG_WARN("! not initialized (see earlier logs), drop outgoing packet\n");
957  } else {
958  LOG_WARN("! not associated, drop outgoing packet\n");
959  }
960  ret = MAC_TX_ERR;
961  mac_call_sent_callback(sent, ptr, ret, 1);
962  return;
963  }
964 
965  /* Ask for ACK if we are sending anything other than broadcast */
966  if(!linkaddr_cmp(addr, &linkaddr_null)) {
967  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
968  in framer-802154.c. */
969  if(++tsch_packet_seqno == 0) {
970  tsch_packet_seqno++;
971  }
972  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno);
973  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
974  } else {
975  /* Broadcast packets shall be added to broadcast queue
976  * The broadcast address in Contiki is linkaddr_null which is equal
977  * to tsch_eb_address */
978  addr = &tsch_broadcast_address;
979  }
980 
981  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
982 
983 #if LLSEC802154_ENABLED
984  if(tsch_is_pan_secured) {
985  /* Set security level, key id and index */
986  packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER);
987  packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */
988  packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER);
989  }
990 #endif /* LLSEC802154_ENABLED */
991 
992 #if !NETSTACK_CONF_BRIDGE_MODE
993  /*
994  * In the Contiki stack, the source address of a frame is set at the RDC
995  * layer. Since TSCH doesn't use any RDC protocol and bypasses the layer to
996  * transmit a frame, it should set the source address by itself.
997  */
998  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
999 #endif
1000 
1001  max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
1002  if(max_transmissions == 0) {
1003  /* If not set by the application, use the default TSCH value */
1004  max_transmissions = TSCH_MAC_MAX_FRAME_RETRIES + 1;
1005  }
1006 
1007  if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
1008  LOG_ERR("! can't send packet due to framer error\n");
1009  ret = MAC_TX_ERR;
1010  } else {
1011  struct tsch_packet *p;
1012  /* Enqueue packet */
1013  p = tsch_queue_add_packet(addr, max_transmissions, sent, ptr);
1014  if(p == NULL) {
1015  LOG_ERR("! can't send packet to ");
1016  LOG_ERR_LLADDR(addr);
1017  LOG_ERR_(" with seqno %u, queue %u %u\n",
1018  tsch_packet_seqno, tsch_queue_packet_count(addr), tsch_queue_global_packet_count());
1019  ret = MAC_TX_ERR;
1020  } else {
1021  p->header_len = hdr_len;
1022  LOG_INFO("send packet to ");
1023  LOG_INFO_LLADDR(addr);
1024  LOG_INFO_(" with seqno %u, queue %u %u, len %u %u\n",
1025  tsch_packet_seqno,
1027  p->header_len, queuebuf_datalen(p->qb));
1028  }
1029  }
1030  if(ret != MAC_TX_DEFERRED) {
1031  mac_call_sent_callback(sent, ptr, ret, 1);
1032  }
1033 }
1034 /*---------------------------------------------------------------------------*/
1035 static void
1036 packet_input(void)
1037 {
1038  int frame_parsed = 1;
1039 
1040  frame_parsed = NETSTACK_FRAMER.parse();
1041 
1042  if(frame_parsed < 0) {
1043  LOG_ERR("! failed to parse %u\n", packetbuf_datalen());
1044  } else {
1045  int duplicate = 0;
1046 
1047  /* Seqno of 0xffff means no seqno */
1048  if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) != 0xffff) {
1049  /* Check for duplicates */
1050  duplicate = mac_sequence_is_duplicate();
1051  if(duplicate) {
1052  /* Drop the packet. */
1053  LOG_WARN("! drop dup ll from ");
1054  LOG_WARN_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1055  LOG_WARN_(" seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1056  } else {
1058  }
1059  }
1060 
1061  if(!duplicate) {
1062  LOG_INFO("received from ");
1063  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1064  LOG_INFO_(" with seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1065 #if TSCH_WITH_SIXTOP
1066  sixtop_input();
1067 #endif /* TSCH_WITH_SIXTOP */
1068  NETSTACK_NETWORK.input();
1069  }
1070  }
1071 }
1072 /*---------------------------------------------------------------------------*/
1073 static int
1074 turn_on(void)
1075 {
1076  if(tsch_is_initialized == 1 && tsch_is_started == 0) {
1077  tsch_is_started = 1;
1078  /* Process tx/rx callback and log messages whenever polled */
1079  process_start(&tsch_pending_events_process, NULL);
1080  /* periodically send TSCH EBs */
1081  process_start(&tsch_send_eb_process, NULL);
1082  /* try to associate to a network or start one if setup as coordinator */
1083  process_start(&tsch_process, NULL);
1084  LOG_INFO("starting as %s\n", tsch_is_coordinator ? "coordinator": "node");
1085  return 1;
1086  }
1087  return 0;
1088 }
1089 /*---------------------------------------------------------------------------*/
1090 static int
1091 turn_off(void)
1092 {
1093  NETSTACK_RADIO.off();
1094  return 1;
1095 }
1096 /*---------------------------------------------------------------------------*/
1097 const struct mac_driver tschmac_driver = {
1098  "TSCH",
1099  tsch_init,
1100  send_packet,
1101  packet_input,
1102  turn_on,
1103  turn_off
1104 };
1105 /*---------------------------------------------------------------------------*/
1106 /** @} */
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:271
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.
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:227
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:115
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:193
#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
static void send_packet(linkaddr_t *dest)
This function is called by the 6lowpan code to send out a packet.
Definition: sicslowpan.c:1475
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:519
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
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.
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:124
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition: pt.h:147
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:199
void tsch_schedule_keepalive_immediately(void)
Schedule a keep-alive immediately.
Definition: tsch.c:326
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:72
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
void tsch_schedule_keepalive(void)
Schedule a keep-alive transmission within [timeout*0.9, timeout[.
Definition: tsch.c:314
A MAC framer for IEEE 802.15.4
const linkaddr_t linkaddr_null
The null link-layer address.
Header file for MAC sequence numbers management
void tsch_queue_free_unused_neighbors(void)
Deallocate all neighbors with empty queue.
Definition: tsch-queue.c:381
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:94
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:260
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:158
void sixtop_input(void)
Input a packet stored in packetbuf.
Definition: sixtop.c:203
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
For quick modulo operation on ASN.
Definition: tsch-asn.h:54
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
struct tsch_neighbor * tsch_queue_add_nbr(const linkaddr_t *addr)
Add a TSCH neighbor queue.
Definition: tsch-queue.c:80
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:210
uint8_t frame_version
2 bit.
Definition: frame802154.h:162
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
int tsch_queue_update_time_source(const linkaddr_t *new_addr)
Update TSCH time source.
Definition: tsch-queue.c:140
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
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
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)
Adds a link to a slotframe.
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:98
#define TSCH_ASN_INIT(asn, ms1b_, ls4b_)
Initialize ASN.
Definition: tsch-asn.h:62
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:204
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:99
A timer.
Definition: etimer.h:75
6TiSCH Operation Sublayer (6top) APIs
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
Definition: radio.h:216
#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:363
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.
int tsch_queue_packet_count(const linkaddr_t *addr)
Returns the number of packets currently a given neighbor queue.
Definition: tsch-queue.c:278
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
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:501
void tsch_set_pan_secured(int enable)
Enable/disable security.
Definition: tsch.c:187
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
void tsch_queue_free_packet(struct tsch_packet *p)
Free a packet.
Definition: tsch-queue.c:310
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1008
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:228
Stores data about an incoming packet.
Definition: tsch-types.h:146
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
The MAC layer deferred the transmission for a later time.
Definition: mac.h:91
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:401
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:177
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99