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