From cc1c763db91bbb56e9fbacd4f2098b3cf37af083 Mon Sep 17 00:00:00 2001 From: Shalu-here Date: Fri, 21 Oct 2016 16:23:08 +0530 Subject: [PATCH] sixtop: 6top protocol implementation by CDAC https://github.com/contiki-os/contiki/pull/1898 --- examples/ipv6/rpl-tsch-sixtop/Makefile | 23 + examples/ipv6/rpl-tsch-sixtop/README.md | 39 + examples/ipv6/rpl-tsch-sixtop/node-sixtop.c | 136 +++ examples/ipv6/rpl-tsch-sixtop/project-conf.h | 183 ++++ .../rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc | 160 ++++ os/net/mac/tsch/sixtop/README.md | 64 ++ os/net/mac/tsch/sixtop/sixtop.c | 839 ++++++++++++++++++ os/net/mac/tsch/sixtop/sixtop.h | 105 +++ os/net/mac/tsch/tsch.c | 33 +- os/net/mac/tsch/tsch.h | 7 + 10 files changed, 1582 insertions(+), 7 deletions(-) create mode 100644 examples/ipv6/rpl-tsch-sixtop/Makefile create mode 100644 examples/ipv6/rpl-tsch-sixtop/README.md create mode 100755 examples/ipv6/rpl-tsch-sixtop/node-sixtop.c create mode 100755 examples/ipv6/rpl-tsch-sixtop/project-conf.h create mode 100644 examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc create mode 100644 os/net/mac/tsch/sixtop/README.md create mode 100644 os/net/mac/tsch/sixtop/sixtop.c create mode 100644 os/net/mac/tsch/sixtop/sixtop.h diff --git a/examples/ipv6/rpl-tsch-sixtop/Makefile b/examples/ipv6/rpl-tsch-sixtop/Makefile new file mode 100644 index 000000000..491d8b075 --- /dev/null +++ b/examples/ipv6/rpl-tsch-sixtop/Makefile @@ -0,0 +1,23 @@ +CONTIKI_PROJECT = node-sixtop +all: $(CONTIKI_PROJECT) + +CONTIKI=../../.. +CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" + +CONTIKI_WITH_IPV6 = 1 +MAKE_WITH_ORCHESTRA ?= 0 # force Orchestra from command line +MAKE_WITH_SECURITY ?= 0 # force Security from command line + +APPS += orchestra +MODULES += core/net/mac/tsch +MODULES += core/net/mac/tsch/sixtop + +ifeq ($(MAKE_WITH_ORCHESTRA),1) +CFLAGS += -DWITH_ORCHESTRA=1 +endif + +ifeq ($(MAKE_WITH_SECURITY),1) +CFLAGS += -DWITH_SECURITY=1 +endif + +include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6/rpl-tsch-sixtop/README.md b/examples/ipv6/rpl-tsch-sixtop/README.md new file mode 100644 index 000000000..9aacff864 --- /dev/null +++ b/examples/ipv6/rpl-tsch-sixtop/README.md @@ -0,0 +1,39 @@ +6top Example Description +------------------------ + +A RPL+TSCH node will act as basic node by default, but can be configured at startup +using the user button and following instructions from the log output. Every press +of a button toggles the mode as 6ln, 6dr or 6dr-sec (detailled next). After 10s with +no button press, the node starts in the last setting. + +The modes are: + +* 6ln (default): 6lowpan node, will join a RPL+TSCH network and act as router. +* 6dr: 6lowpan DAG Root, will start its own RPL+TSCH network. Note this is not a + border router, i.e. it does not have a serial interface with connection to + the Internet. For a border router, see ../border-router. +* 6dr-sec: 6lowpan DAG Root, starting a RPL+TSCH network with link-layer security + enabled. 6ln nodes are able to join both non-secured or secured networks. + + +6top Operation +--------------- + +If the mode is 6ln (node) + +* The application triggers a 6P Add Request to 6dr (neighbor) +* Following this the application triggers another 6P Add Request to 6dr +* After an interval, the application triggers a 6P Delete Request to 6dr + +For the Cooja simulation, you may use the rpl-tsch-sixtop-z1.csc file in this folder. +Once you run the simulation, "Mote output" window of Cooja simulator displays the +following messages. + +For a 6P Add transaction, + ID:1 TSCH-sixtop: Sixtop IE received + ID:1 TSCH-sixtop: Send Link Response to node 2 + ID:2 TSCH-sixtop: Sixtop IE received + ID:2 TSCH-sixtop: Schedule link x as RX with node 2 + ID:2 TSCH-sixtop: Schedule link x as TX with node 1 + +Similarly for a 6P Delete transaction. diff --git a/examples/ipv6/rpl-tsch-sixtop/node-sixtop.c b/examples/ipv6/rpl-tsch-sixtop/node-sixtop.c new file mode 100755 index 000000000..d50862beb --- /dev/null +++ b/examples/ipv6/rpl-tsch-sixtop/node-sixtop.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/** + * \file + * To test 6P transaction on a RPL+TSCH network + * + * \author + * Simon Duquennoy + * Shalu R + * Lijo Thomas + */ + +#include "contiki.h" +#include "node-id.h" +#include "net/rpl/rpl.h" +#include "net/ipv6/uip-ds6-route.h" +#include "net/mac/tsch/tsch.h" +#include "net/rpl/rpl-private.h" +#include "net/ip/uip-debug.h" +#include "net/mac/tsch/sixtop/sixtop.h" + +/*---------------------------------------------------------------------------*/ +PROCESS(node_process, "RPL Node"); +AUTOSTART_PROCESSES(&node_process); + +/*---------------------------------------------------------------------------*/ +static void +net_init(uip_ipaddr_t *br_prefix) +{ + uip_ipaddr_t global_ipaddr; + + if(br_prefix) { /* We are RPL root. Will be set automatically + as TSCH pan coordinator via the tsch-rpl module */ + memcpy(&global_ipaddr, br_prefix, 16); + uip_ds6_set_addr_iid(&global_ipaddr, &uip_lladdr); + uip_ds6_addr_add(&global_ipaddr, 0, ADDR_AUTOCONF); + rpl_set_root(RPL_DEFAULT_INSTANCE, &global_ipaddr); + rpl_set_prefix(rpl_get_any_dag(), br_prefix, 64); + rpl_repair_root(RPL_DEFAULT_INSTANCE); + } + + NETSTACK_MAC.on(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(node_process, ev, data) +{ + static struct etimer et; + PROCESS_BEGIN(); + + /* 3 possible roles: + * - role_6ln: simple node, will join any network, secured or not + * - role_6dr: DAG root, will advertise (unsecured) beacons + * - role_6dr_sec: DAG root, will advertise secured beacons + * */ + static int is_coordinator = 0, added_num_of_links = 0; + static enum { role_6ln, role_6dr, role_6dr_sec } node_role; + node_role = role_6ln; + + /* Set node with MAC address c1:0c:00:00:00:00:01 as coordinator, + * convenient in cooja for regression tests using z1 nodes + * */ + +#ifdef CONTIKI_TARGET_Z1 + extern unsigned char node_mac[8]; + unsigned char coordinator_mac[8] = { 0xc1, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + + if(memcmp(node_mac, coordinator_mac, 8) == 0) { + if(LLSEC802154_ENABLED) { + node_role = role_6dr_sec; + } else { + node_role = role_6dr; + } + } else { + node_role = role_6ln; + } +#endif + + tsch_set_pan_secured(LLSEC802154_ENABLED && (node_role == role_6dr_sec)); + is_coordinator = node_role > role_6ln; + + if(is_coordinator) { + uip_ipaddr_t prefix; + uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + net_init(&prefix); + } else { + net_init(NULL); + } + + etimer_set(&et, CLOCK_SECOND * 30); + while(1) { + PROCESS_YIELD_UNTIL(etimer_expired(&et)); + etimer_reset(&et); + + if(node_id != 1) { + clock_delay(1000); + if((added_num_of_links == 1) || (added_num_of_links == 3)) { + printf("App : Add a link\n"); + sixtop_add_links((linkaddr_t *)0xffff, 1); + } else if(added_num_of_links == 5) { + printf("App : Delete a link\n"); + sixtop_remove_link((linkaddr_t *)0xffff); + } + added_num_of_links++; + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/ipv6/rpl-tsch-sixtop/project-conf.h b/examples/ipv6/rpl-tsch-sixtop/project-conf.h new file mode 100755 index 000000000..89180bcd7 --- /dev/null +++ b/examples/ipv6/rpl-tsch-sixtop/project-conf.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015, SICS Swedish ICT. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +/* Set to run orchestra */ +#ifndef WITH_ORCHESTRA +#define WITH_ORCHESTRA 0 +#endif /* WITH_ORCHESTRA */ + +/* Set to enable TSCH security */ +#ifndef WITH_SECURITY +#define WITH_SECURITY 0 +#endif /* WITH_SECURITY */ + +/*******************************************************/ +/********* Enable RPL non-storing mode *****************/ +/*******************************************************/ + +#undef UIP_CONF_MAX_ROUTES +#define UIP_CONF_MAX_ROUTES 0 /* No need for routes */ +#undef RPL_CONF_MOP +#define RPL_CONF_MOP RPL_MOP_NON_STORING /* Mode of operation*/ +#undef ORCHESTRA_CONF_RULES +#define ORCHESTRA_CONF_RULES { &eb_per_time_source, &unicast_per_neighbor_rpl_ns, &default_common } /* Orchestra in non-storing */ + +/*******************************************************/ +/********************* Enable TSCH *********************/ +/*******************************************************/ + +/* Netstack layers */ +#undef NETSTACK_CONF_MAC +#define NETSTACK_CONF_MAC tschmac_driver +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nordc_driver +#undef NETSTACK_CONF_FRAMER +#define NETSTACK_CONF_FRAMER framer_802154 + +/* IEEE802.15.4 frame version */ +#undef FRAME802154_CONF_VERSION +#define FRAME802154_CONF_VERSION FRAME802154_IEEE802154E_2012 + +/* TSCH and RPL callbacks */ +#define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch +#define RPL_CALLBACK_NEW_DIO_INTERVAL tsch_rpl_callback_new_dio_interval +#define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network +#define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network + +/* Needed for CC2538 platforms only */ +/* For TSCH we have to use the more accurate crystal oscillator + * by default the RC oscillator is activated */ +#undef SYS_CTRL_CONF_OSC32K_USE_XTAL +#define SYS_CTRL_CONF_OSC32K_USE_XTAL 1 + +/* Needed for cc2420 platforms only */ +/* Disable DCO calibration (uses timerB) */ +#undef DCOSYNCH_CONF_ENABLED +#define DCOSYNCH_CONF_ENABLED 0 +/* Enable SFD timestamps (uses timerB) */ +#undef CC2420_CONF_SFD_TIMESTAMPS +#define CC2420_CONF_SFD_TIMESTAMPS 1 + +/* Enable Sixtop Implementation */ +#undef TSCH_CONF_WITH_SIXTOP +#define TSCH_CONF_WITH_SIXTOP 1 + +/*******************************************************/ +/******************* Configure TSCH ********************/ +/*******************************************************/ + +/* TSCH logging. 0: disabled. 1: basic log. 2: with delayed + * log messages from interrupt */ +#undef TSCH_LOG_CONF_LEVEL +#define TSCH_LOG_CONF_LEVEL 2 + +/* IEEE802.15.4 PANID */ +#undef IEEE802154_CONF_PANID +#define IEEE802154_CONF_PANID 0xabcd + +/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */ +#undef TSCH_CONF_AUTOSTART +#define TSCH_CONF_AUTOSTART 0 + +/* 6TiSCH schedule length */ +#undef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH +#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 11 + +#if WITH_SECURITY + +/* Enable security */ +#undef LLSEC802154_CONF_ENABLED +#define LLSEC802154_CONF_ENABLED 1 +/* TSCH uses explicit keys to identify k1 and k2 */ +#undef LLSEC802154_CONF_USES_EXPLICIT_KEYS +#define LLSEC802154_CONF_USES_EXPLICIT_KEYS 1 +/* TSCH uses the ASN rather than frame counter to construct the Nonce */ +#undef LLSEC802154_CONF_USES_FRAME_COUNTER +#define LLSEC802154_CONF_USES_FRAME_COUNTER 0 + +#endif /* WITH_SECURITY */ + +#if WITH_ORCHESTRA + +/* See apps/orchestra/README.md for more Orchestra configuration options */ +#define TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL 0 /* No 6TiSCH minimal schedule */ +#define TSCH_CONF_WITH_LINK_SELECTOR 1 /* Orchestra requires per-packet link selection */ +/* Orchestra callbacks */ +#define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source +#define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready +#define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added +#define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed + +#endif /* WITH_ORCHESTRA */ + +/*******************************************************/ +/************* Other system configuration **************/ +/*******************************************************/ + +#if CONTIKI_TARGET_Z1 +/* Save some space to fit the limited RAM of the z1 */ +#undef UIP_CONF_TCP +#define UIP_CONF_TCP 0 +#undef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 2 +#undef RPL_NS_CONF_LINK_NUM +#define RPL_NS_CONF_LINK_NUM 2 +#undef NBR_TABLE_CONF_MAX_NEIGHBORS +#define NBR_TABLE_CONF_MAX_NEIGHBORS 2 +#undef UIP_CONF_ND6_SEND_NA +#define UIP_CONF_ND6_SEND_NA 0 +#undef SICSLOWPAN_CONF_FRAG +#define SICSLOWPAN_CONF_FRAG 0 + +#if WITH_SECURITY +/* Note: on sky or z1 in cooja, crypto operations are done in S/W and + * cannot be accommodated in normal slots. Use 65ms slots instead, and + * a very short 6TiSCH minimal schedule length */ +#undef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH +#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 65000 +#undef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH +#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 2 +/* Reduce log level to make space for security on z1 */ +#undef TSCH_LOG_CONF_LEVEL +#define TSCH_LOG_CONF_LEVEL 0 +#endif /* WITH_SECURITY */ + +#endif /* CONTIKI_TARGET_Z1 */ + +#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL || \ + CONTIKI_TARGET_OPENMOTE_CC2538 +#define TSCH_CONF_HW_FRAME_FILTERING 0 +#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \ + || CONTIKI_TARGET_OPENMOTE_CC2538 */ + +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc b/examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc new file mode 100644 index 000000000..24a7f86c5 --- /dev/null +++ b/examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc @@ -0,0 +1,160 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + My simulation + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.Z1MoteType + z11 + Z1 Mote Type #z11 + [CONTIKI_DIR]/examples/ipv6/rpl-tsch-sixtop/node-sixtop.c + make node-sixtop.z1 TARGET=z1 + [CONTIKI_DIR]/examples/ipv6/rpl-tsch-sixtop/node-sixtop.z1 + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspButton + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspDefaultSerial + org.contikios.cooja.mspmote.interfaces.MspLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + + + + + org.contikios.cooja.interfaces.Position + 3.827476552301217 + 2.167129170680247 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspClock + 1.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + z11 + + + + + org.contikios.cooja.interfaces.Position + 30.278379737463556 + 17.799585117738026 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspClock + 1.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 2 + + z11 + + + + org.contikios.cooja.plugins.SimControl + 280 + 0 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + 4.027583163598053 0.0 0.0 4.027583163598053 133.5292942712438 14.03198741893021 + + 400 + 3 + 160 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + TSCH-sch + + + + 854 + 1 + 342 + 0 + 161 + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + + + + 500.0 + + 1366 + 5 + 166 + 0 + 503 + + + org.contikios.cooja.plugins.Notes + + Enter notes here + true + + 686 + 4 + 160 + 680 + 0 + + + org.contikios.cooja.plugins.RadioLogger + + 150 + + false + false + + 508 + 2 + 343 + 854 + 160 + + + diff --git a/os/net/mac/tsch/sixtop/README.md b/os/net/mac/tsch/sixtop/README.md new file mode 100644 index 000000000..dc26a2924 --- /dev/null +++ b/os/net/mac/tsch/sixtop/README.md @@ -0,0 +1,64 @@ + + + +# 6TiSCH Operation Sublayer (6top) + +## **Overview** + +6TiSCH Operation Sublayer (6top), a logical link layer in the 6TiSCH architecture, provides the abstraction of an IP link over a TSCH MAC layer (IEEE 802.15.4e). The functionality of 6top is to facilitate the dynamic cell negotiation with one-hop neighbors. + +This is a Contiki implementation of 6top, which defines how to handle a 2-step 6top transaction on a basic RPL+TSCH network. + +Developed by: + +- Shalu R, CDAC, shalur@cdac.in, github user: [shalurajendran](https://github.com/shalurajendran) +- Lijo Thomas, CDAC, lijo@cdac.in + +## **Features** + +This implementation includes: + +- 6top protocol(6P) + - 6P Add + - 6P Delete +- 2-step 6top Transaction + +The code has been tested on Zolertia Z1 (z1, tested in cooja only) platform. + +## **Code structure** + +The 6top frame format is included in: + +- core/net/mac/frame802154-ie.[ch]: Modified to include Sixtop Information Elements + +6top is implemented in: + +- core/net/mac/tsch/sixtop/sixtop.[ch]: 6top interface and 6top protocol(6P addition and deletion), handling of 6P Requests and Response + +TSCH file modified: + +- core/net/mac/tsch/tsch.[ch]: Modified to include Sixtop module + + +## **Using 6top** + +A simple 6top+TSCH+RPL example is included under examples/ipv6/rpl-tsch-sixtop. Currently this application triggers the 6P transactions, later the 6top Scheduling Function (SF) may be implemented for the purpose. + +To use 6top, make sure your platform supports TSCH and have sufficient memory. + +To add 6top to your application, first include the Sixtop module in your Makefile with: + + MODULES += core/net/mac/tsch/sixtop + +Also enable the sixtop functionalities in your project-conf.h file with + + #undef TSCH_CONF_WITH_SIXTOP + + #define TSCH_CONF_WITH_SIXTOP 1 + +## **Additional documentation** + +1. [IETF 6TiSCH Working Group](https://datatracker.ietf.org/wg/6tisch) +2. [6TiSCH 6top Protocol (6P)](https://tools.ietf.org/pdf/draft-ietf-6tisch-6top-protocol-02.pdf) + + diff --git a/os/net/mac/tsch/sixtop/sixtop.c b/os/net/mac/tsch/sixtop/sixtop.c new file mode 100644 index 000000000..ddaa15f55 --- /dev/null +++ b/os/net/mac/tsch/sixtop/sixtop.c @@ -0,0 +1,839 @@ +/* + * Copyright (c) 2016, Centre for Development of Advanced Computing (C-DAC). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * IEEE 802.15.4 TSCH MAC Sixtop. + * \author + * Shalu R + * Lijo Thomas + */ + +#include +#include "contiki.h" +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "net/mac/tsch/tsch.h" +#include "net/mac/tsch/tsch-packet.h" +#include "net/mac/tsch/tsch-private.h" +#include "net/mac/tsch/tsch-schedule.h" +#include "lib/random.h" +#include "sixtop.h" +#include "net/mac/frame802154e-ie.h" + +#define DEBUG DEBUG_PRINT +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#endif + +#define WRITE16(buf, val) \ + do { ((uint8_t *)(buf))[0] = (val) & 0xff; \ + ((uint8_t *)(buf))[1] = ((val) >> 8) & 0xff; \ + } while(0); + +#define READ16(buf, var) \ + (var) = ((uint8_t *)(buf))[0] | ((uint8_t *)(buf))[1] << 8 + +/* Required number of links specified in Link Request IE */ +uint8_t sixtop_request_num_links = 0; +/* Sequence Number of Link Request IE */ +static int sixtop_request_seqno = 0; +/* Sequence Number of Link Response IE */ +static int sixtop_response_seqno = 0; +/* Destination address of the last packet sent */ +static linkaddr_t last_pkt_address; +/* IE information of the last packet sent */ +struct ieee802154_ies last_pkt_ies; +/* SlotFrame ID specified in Link Request IE */ +struct tsch_slotframe *req_sf; + +/*---------------------------------------------------------------------------*/ +/* Update the packet to be send with Sixtop Information Elements. Returns length of IE */ +int +sixtop_update_ie(uint8_t *buf, struct ieee802154_ies *ies) +{ + if(ies != NULL) { + uint8_t i = 0, code = 0, ie_len = 0, max = 0; + + buf[2] = ies->ie_sixtop.subIE_id; + buf[3] = ies->ie_sixtop.version_code; + buf[4] = ies->ie_sixtop.schedule_fn_id; + + /* 6P Code */ + code = ies->ie_sixtop.version_code >> 4; + + switch(code) { + case CMD_ADD: + case CMD_DELETE: + buf[5] = ies->ie_sixtop.num_links; + buf[6] = ies->ie_sixtop.frame_id; + + if(code == CMD_ADD) { + max = SIXTOP_IE_MAX_LINKS; + } else { /* CMD_DELETE */ + max = sixtop_request_num_links; + } + for(i = 0; i < max; i++) { + WRITE16(buf + 7 + i * 4, ies->ie_sixtop.linkList[i].timeslot); + WRITE16(buf + 7 + i * 4 + 2, ies->ie_sixtop.linkList[i].channel_offset); + } + + ie_len = 5 + 4 * max; + break; + + case RC_SUCCESS: /* Response Code Success */ + for(i = 0; i < sixtop_request_num_links; i++) { + WRITE16(buf + 5 + i * 4, ies->ie_sixtop.linkList[i].timeslot); + WRITE16(buf + 5 + i * 4 + 2, ies->ie_sixtop.linkList[i].channel_offset); + } + + ie_len = 3 + 4 * sixtop_request_num_links; + break; + + default: + return -1; + } + return ie_len + 2; /* IE_len + IE_descriptor_len */ + } else { + return -1; + } +} +/*---------------------------------------------------------------------------*/ +/* Create a Sixtop IE for specified 6P code. Returns length of IEEE802.15.4e packet */ +int +sixtop_create_ie(uint8_t *buf, linkaddr_t dest_addr, uint8_t code, + uint8_t sf_id, struct sixtop_link *sl) +{ + uint8_t i = 0, len = 0, curr_len = 0, max = 0, sixtop_ie_offset = 0; + /* Schedule Function ID */ + uint8_t schedule_fn_id = 0; /* SF0 */ + struct ieee802154_ies ies; + + /* IEEE 802.15.4 MAC Frame Header */ + frame802154_t p; + memset(&p, 0, sizeof(p)); + + /* MAC Header : Frame Control Field */ + p.fcf.frame_type = FRAME802154_DATAFRAME; + p.fcf.security_enabled = 0; + p.fcf.frame_pending = 0; + p.fcf.ack_required = 1; + p.fcf.panid_compression = 0; + p.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO; + p.fcf.ie_list_present = 1; + p.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE; + p.fcf.frame_version = FRAME802154_IEEE802154E_2012; + p.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; + + /* MAC Header : Sequence Number Field */ + switch(code) { + case CMD_ADD: + case CMD_DELETE: + p.seq = sixtop_request_seqno; + sixtop_request_seqno++; + break; + + case RC_SUCCESS: /* Response Code Success */ + p.seq = sixtop_response_seqno; + break; + + default: + break; + } + + /* MAC Header : PAN ID and Address Fields */ + p.dest_pid = frame802154_get_pan_id(); + linkaddr_copy((linkaddr_t *)&p.dest_addr, &dest_addr); + p.src_pid = frame802154_get_pan_id(); + linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr); + + /* MAC Header : Auxillary Security Header */ +#if TSCH_SECURITY_ENABLED + if(tsch_is_pan_secured) { + p.fcf.security_enabled = 1; + p.aux_hdr.security_control.security_level = TSCH_SECURITY_KEY_SEC_LEVEL_ACK; + p.aux_hdr.security_control.key_id_mode = FRAME802154_1_BYTE_KEY_ID_MODE; + p.aux_hdr.security_control.frame_counter_suppression = 1; + p.aux_hdr.security_control.frame_counter_size = 1; + p.aux_hdr.key_index = TSCH_SECURITY_KEY_INDEX_ACK; + } +#endif /* TSCH_SECURITY_ENABLED */ + + /* Copy MAC Header to Buffer */ + if((curr_len = frame802154_create(&p, buf)) == 0) { + return 0; + } + + memset(&ies, 0, sizeof(ies)); + + /* Header IE Termination 1 */ + /* First add header-IE termination IE to stipulate that next come payload IEs */ + if((len = frame80215e_create_ie_header_list_termination_1(buf + curr_len, PACKETBUF_SIZE - curr_len, &ies)) == -1) { + return -1; + } + curr_len += len; + + /* Save offset of the Sixtop IE descriptor, we need to know the total length + * before writing it */ + sixtop_ie_offset = curr_len; + + /* Update Sixtop Information Elements */ + ies.ie_sixtop.subIE_id = SIXTOP_SUBIE_ID; + ies.ie_sixtop.version_code = (code << 4) | SIXTOP_VERSION; + ies.ie_sixtop.schedule_fn_id = schedule_fn_id; + + switch(code) { + case CMD_ADD: + case CMD_DELETE: + if(code == CMD_ADD) { + max = SIXTOP_IE_MAX_LINKS; + } else { + max = 1; + } + + ies.ie_sixtop.frame_id = sf_id; + ies.ie_sixtop.num_links = sixtop_request_num_links; + + for(i = 0; i < max; i++) { + if(sl[i].link_option != LINK_OPTION_OFF) { + ies.ie_sixtop.linkList[i].timeslot = sl[i].timeslot; + ies.ie_sixtop.linkList[i].channel_offset = sl[i].channel_offset; + } + } + break; + + case RC_SUCCESS: /* Response Code Success */ + for(i = 0; i < sixtop_request_num_links; i++) { + ies.ie_sixtop.linkList[i].timeslot = sl[i].timeslot; + ies.ie_sixtop.linkList[i].channel_offset = sl[i].channel_offset; + } + break; + + default: + break; + } + + /* Save a copy of Sixtop IE */ + last_pkt_ies = ies; + + /* Copy Sixtop IE content to buffer */ + if((len = sixtop_update_ie(buf + curr_len, &ies)) == -1) { + return -1; + } + curr_len += len; + + /* Outer IE descriptor - Sixtop */ + ies.ie_mlme_len = curr_len - sixtop_ie_offset - 2; + if((len = frame80215e_create_ie_sixtop(buf + sixtop_ie_offset, PACKETBUF_SIZE - sixtop_ie_offset, &ies)) == -1) { + return -1; + } + + return curr_len; +} +/*---------------------------------------------------------------------------*/ +/* Fetch the CandidateLinkList for Addition. Returns 0 if success */ +int +sixtop_get_link_list_for_addition(uint8_t sf_id, struct sixtop_link *sl) +{ + uint8_t i = 0, index = 0; + /* Flag to prevent repeated slots */ + uint8_t slot_check = 1; + uint16_t random_slot = 0; + struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(sf_id); + + do { + /* Randomly select a slot offset within TSCH_SCHEDULE_DEFAULT_LENGTH */ + random_slot = ((random_rand() & 0xFF)) % TSCH_SCHEDULE_DEFAULT_LENGTH; + + if(!tsch_schedule_get_link_by_timeslot(sf, random_slot)) { /* NULL value indicates a free link */ + + /* To prevent repeated slots */ + for(i = 0; i < index; i++) { + if(!(sl[i].timeslot == random_slot)) { + /* Random selection resulted in a free slot */ + if(i == index - 1) { /* Checked till last index of link list */ + slot_check = 1; + break; + } + } else { + /* Slot already present in CandidateLinkList */ + slot_check++; + break; + } + } + + /* Random selection resulted in a free slot, add it to linklist */ + if(slot_check == 1) { + sl[index].timeslot = random_slot; + sl[index].channel_offset = 0; + sl[index].link_option = LINK_OPTION_TX; + index++; + slot_check++; + } else if(slot_check > TSCH_SCHEDULE_DEFAULT_LENGTH) { + PRINTF("TSCH-sixtop:! Number of trials for free slot exceeded...\n"); + return -1; + break; /* exit while loop */ + } + } + } while(index < SIXTOP_IE_MAX_LINKS); + + if(index == 0) { + return -1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------------*/ +/* Fetches the CandidateLinkList (atmost one link) for Deletion. Returns 0 if success */ +int +sixtop_get_link_list_for_deletion(uint8_t sf_id, struct sixtop_link *sl, linkaddr_t *dest_addr) +{ + uint8_t i = 0, index = 0; + struct tsch_link *l; + struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(sf_id); + + for(i = 0; i < TSCH_SCHEDULE_DEFAULT_LENGTH; i++) { + l = tsch_schedule_get_link_by_timeslot(sf, i); + + if(l) { + /* Non-zero value indicates a scheduled link */ + if((linkaddr_cmp(&l->addr, dest_addr)) && (l->link_options == LINK_OPTION_TX)) { + /* This link is scheduled as a TX link to the specified neighbor */ + sl[index].timeslot = i; + sl[index].channel_offset = l->channel_offset; + sl[index].link_option = LINK_OPTION_TX; + index++; + break; /* delete atmost one */ + } + } + } + + if(index == 0) { + return -1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------------*/ +/* Adds links to the schedule as Tx/Rx depending on the sixtop_state value */ +void +sixtop_add_links_to_schedule(uint8_t sf_id, struct sixtop_link *sl, + linkaddr_t *previous_hop, uint8_t state) +{ + uint8_t i = 0, num_added_links = 0; + + for(i = 0; i < SIXTOP_IE_MAX_LINKS; i++) { + if(sl[i].timeslot != 0xFFFF) { + switch(state) { + case SIXTOP_ADD_RESPONSE_WAIT_SENDDONE: + PRINTF("TSCH-sixtop: Schedule link %d as RX with node %u\n", sl[i].timeslot, previous_hop->u8[7]); + /* Add a TX link to neighbor */ + tsch_schedule_add_link(tsch_schedule_get_slotframe_by_handle(sf_id), + LINK_OPTION_RX, LINK_TYPE_NORMAL, previous_hop, + sl[i].timeslot, sl[i].channel_offset); + break; + + case SIXTOP_ADD_RESPONSE_RECEIVED: + PRINTF("TSCH-sixtop: Schedule link %d as TX with node %u\n", sl[i].timeslot, previous_hop->u8[7]); + /* Add a RX link to neighbor */ + tsch_schedule_add_link(tsch_schedule_get_slotframe_by_handle(sf_id), + LINK_OPTION_TX, LINK_TYPE_NORMAL, previous_hop, + sl[i].timeslot, sl[i].channel_offset); + break; + + default: + PRINTF("TSCH-sixtop:! Sixtop_state error\n"); + break; + } + + num_added_links++; + + if(num_added_links == sixtop_request_num_links) { + break; + } + } + } +} +/*---------------------------------------------------------------------------*/ +/* Remove links from schedule */ +void +sixtop_remove_links_from_schedule(uint8_t sf_id, struct sixtop_link *sl, + linkaddr_t *previous_hop) +{ + uint8_t i = 0; + struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(sf_id); + + for(i = 0; i < sixtop_request_num_links; i++) { + PRINTF("TSCH-sixtop: Remove link %d from the schedule\n", sl[i].timeslot); + tsch_schedule_remove_link_by_timeslot(sf, sl[i].timeslot); + } +} +/*---------------------------------------------------------------------------*/ +/* Process the callback of a Sixtop IE by sixtop_state */ +void +sixtop_ie_process_callback(struct ieee802154_ies *ies, linkaddr_t *dest_addr) +{ + uint8_t i = 0, frame_id = 0; + struct sixtop_link sl[SIXTOP_IE_MAX_LINKS]; + + switch(sixtop_state) { + case SIXTOP_ADD_REQUEST_WAIT_SENDDONE: + sixtop_state = SIXTOP_ADD_RESPONSE_WAIT; + break; + + case SIXTOP_DELETE_REQUEST_WAIT_SENDDONE: + sixtop_state = SIXTOP_DELETE_RESPONSE_WAIT; + break; + + case SIXTOP_ADD_RESPONSE_WAIT_SENDDONE: + case SIXTOP_DELETE_RESPONSE_WAIT_SENDDONE: + frame_id = ies->ie_sixtop.frame_id; + + if(sixtop_request_num_links > 0) { + for(i = 0; i < sixtop_request_num_links; i++) { + sl[i].timeslot = ies->ie_sixtop.linkList[i].timeslot; + sl[i].channel_offset = ies->ie_sixtop.linkList[i].channel_offset; + } + if(sixtop_state == SIXTOP_ADD_RESPONSE_WAIT_SENDDONE) { + /* Add links to TSCH schedule */ + sixtop_add_links_to_schedule(frame_id, sl, dest_addr, sixtop_state); + } else { /* SIXTOP_DELETE_RESPONSE_WAIT_SENDDONE */ + /* Remove links from TSCH schedule */ + sixtop_remove_links_from_schedule(frame_id, sl, dest_addr); + } + } + + break; + + default: + /* log error */ + break; + } +} +/*---------------------------------------------------------------------------*/ +/* Tx callback for Sixtop IE */ +static void +sixtop_packet_sent(void *ptr, int status, int transmissions) +{ + /*PRINTF("TSCH-sixtop: Sixtop IE sent to %u, st %d-%d\n", + last_pkt_address.u8[7], status, transmissions);*/ + + /* Process the callback by sixtop_state */ + sixtop_ie_process_callback(&last_pkt_ies, &last_pkt_address); +} +/*---------------------------------------------------------------------------*/ +/* Initiates transmission of a Link Request */ +int +sixtop_create_link_request(uint8_t code, linkaddr_t *dest_addr, uint16_t num_Links) +{ + uint8_t len = 0; + struct sixtop_link sl[SIXTOP_IE_MAX_LINKS]; + + /* Get time-source neighbor */ + struct tsch_neighbor *n = tsch_queue_get_time_source(); + + req_sf = tsch_schedule_get_slotframe_by_handle(0); /* Slotframe 0 */ + memset(sl, 0, sizeof(sl)); + + if(dest_addr == NULL) { + return -1; + } + + sixtop_request_num_links = num_Links; + + if(code == CMD_ADD) { + /* Fetch CandidateLinkList for addition */ + if(sixtop_get_link_list_for_addition(req_sf->handle, sl) == -1) { + return -1; + } + } else if(code == CMD_DELETE) { + /* Fetch CandidateLinkList for deletion */ + if(sixtop_get_link_list_for_deletion(req_sf->handle, sl, &n->addr) == -1) { + return -1; + } + } + + if(tsch_queue_packet_count(&n->addr) == 0) { + /* Get a free buffer */ + packetbuf_clear(); + packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, SIXTOP_CONF_MAX_MAC_TRANSMISSIONS); + + /* Save destination address of last packet sent */ + last_pkt_address = n->addr; + + /* Create IE by 6P code */ + len += sixtop_create_ie(packetbuf_dataptr(), n->addr, code, req_sf->handle, sl); + + if(len != 0) { + struct tsch_packet *p; + packetbuf_set_datalen(len); + + /* Add packet to Tx queue. TSCH layer schedules transmission */ + if(!(p = tsch_queue_add_packet(&n->addr, sixtop_packet_sent, NULL))) { + PRINTF("TSCH-sixtop:! could not enqueue 6top packet\n"); + } + } else { + return -1; + } + } + + if(code == CMD_ADD) { + sixtop_state = SIXTOP_ADD_REQUEST_WAIT_SENDDONE; + } else if(code == CMD_DELETE) { + sixtop_state = SIXTOP_DELETE_REQUEST_WAIT_SENDDONE; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +/* Initiates transmission of a Link Response (On receiving a Link Request) */ +void +sixtop_create_link_response(uint8_t code, linkaddr_t *dest_addr, struct ieee802154_ies *ies) +{ + uint8_t i = 0, len = 0, frame_id = 0; + struct sixtop_link sl[SIXTOP_IE_MAX_LINKS]; + + /* Save destination address of last packet sent */ + linkaddr_copy((linkaddr_t *)&last_pkt_address, dest_addr); + + frame_id = ies->ie_sixtop.frame_id; + + for(i = 0; i < SIXTOP_IE_MAX_LINKS; i++) { + sl[i].timeslot = ies->ie_sixtop.linkList[i].timeslot; + sl[i].channel_offset = ies->ie_sixtop.linkList[i].channel_offset; + } + + if(tsch_queue_packet_count(&last_pkt_address) == 0) { + /* Get a free buffer */ + packetbuf_clear(); + packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, SIXTOP_CONF_MAX_MAC_TRANSMISSIONS); + + /* Create a Sixtop Link Response packet */ + len += sixtop_create_ie(packetbuf_dataptr(), last_pkt_address, RC_SUCCESS, frame_id, sl); + + if(len != 0) { + struct tsch_packet *p; + + packetbuf_set_datalen(len); + last_pkt_ies = *ies; + + /* Add packet to Tx queue. TSCH layer schedules transmission */ + if(!(p = tsch_queue_add_packet(&last_pkt_address, sixtop_packet_sent, NULL))) { + PRINTF("TSCH-sixtop:! could not enqueue 6top packet\n"); + } + } + + if(code == CMD_ADD) { + sixtop_state = SIXTOP_ADD_RESPONSE_WAIT_SENDDONE; + } else if(code == CMD_DELETE) { + sixtop_state = SIXTOP_DELETE_RESPONSE_WAIT_SENDDONE; + } + } +} +/*---------------------------------------------------------------------------*/ +/* Initiates a Sixtop Link addition + * Neighbor can be specified from application or upper layers + * Currently Time source neighbor is taken as default + * Returns 0 if Success + */ +int +sixtop_add_links(linkaddr_t *dest_addr, uint8_t num_Links) +{ + /* Create a Sixtop Add Request. Return 0 if Success */ + if(sixtop_create_link_request(CMD_ADD, dest_addr, num_Links) == -1) { + PRINTF("TSCH-sixtop:! Add link failed"); + return -1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* Initiates a Sixtop Link deletion + * Neighbor can be specified from application or upper layers + * Currently Time source neighbor is taken as default + * Returns 0 if Success + */ +int +sixtop_remove_link(linkaddr_t *dest_addr) +{ + /* Create a Sixtop Delete Request. Return 0 if Success */ + if(sixtop_create_link_request(CMD_DELETE, dest_addr, 1) == -1) { /* delete atmost one */ + PRINTF("TSCH-sixtop:! Delete link failed"); + return -1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* Check links for addition/deletion. Returns 0 if feasible */ +int +sixtop_are_links_feasible(uint8_t code, uint8_t frame_id, struct sixtop_link *sl) +{ + uint8_t i = 0; + + /* Counter for infeasible number of links + * A non-zero value indicates infeasibility */ + uint8_t infeasible_num_links = sixtop_request_num_links; + + if(sixtop_request_num_links > SIXTOP_IE_MAX_LINKS) { + return -1; + } else { + if(code == CMD_ADD) { + do { + /* Checking availability of requested number of slots */ + if(tsch_schedule_get_link_by_timeslot(tsch_schedule_get_slotframe_by_handle(0), sl[i].timeslot) == NULL) { + /* A free link present */ + infeasible_num_links--; + } else { + sl[i].timeslot = 0xFFFF; /* Error */ + } + i++; + } while(i < sixtop_request_num_links && infeasible_num_links > 0); + } else if(code == CMD_DELETE) { + do { + /* Ensure before delete */ + if(tsch_schedule_get_link_by_timeslot(tsch_schedule_get_slotframe_by_handle(0), sl[i].timeslot)) { + /* A scheduled link present */ + infeasible_num_links--; + } else { + sl[i].timeslot = 0xFFFF; /* Error */ + } + i++; + } while(i < sixtop_request_num_links && infeasible_num_links > 0); + } + + if(infeasible_num_links == 0) { /* Links are feasible */ + + while(i < sixtop_request_num_links) { + sl[i].timeslot = 0xFFFF; /* Error */ + i++; + } + + return 0; /* Return success(0) */ + } + } + + return -1; +} +/*---------------------------------------------------------------------------*/ +/* Process Sixtop IE by code */ +void +sixtop_process_by_code(uint8_t code, struct ieee802154_ies *ies, linkaddr_t *dest_addr) +{ + uint8_t frame_id = 0, i = 0; + struct sixtop_link sl[SIXTOP_IE_MAX_LINKS]; + + switch(code) { + case CMD_ADD: + case CMD_DELETE: + frame_id = ies->ie_sixtop.frame_id; + + /* Are the links feasible for addition/deletion. Returns 0 if feasible */ + if(!(sixtop_are_links_feasible(code, frame_id, ies->ie_sixtop.linkList))) { + + PRINTF("TSCH-sixtop: Send Link Response to node %d\n", dest_addr->u8[7]); + /* Links are feasible. Create Link Response packet */ + sixtop_create_link_response(code, dest_addr, ies); + } + break; + + case RC_SUCCESS: /* Response Code Success */ + frame_id = req_sf->handle; + + for(i = 0; i < sixtop_request_num_links; i++) { + sl[i].timeslot = ies->ie_sixtop.linkList[i].timeslot; + sl[i].channel_offset = ies->ie_sixtop.linkList[i].channel_offset; + } + + /* Add/delete links to/from Schedule */ + if(sixtop_state == SIXTOP_ADD_RESPONSE_RECEIVED) { + sixtop_add_links_to_schedule(frame_id, sl, dest_addr, sixtop_state); + } else if(sixtop_state == SIXTOP_DELETE_RESPONSE_RECEIVED) { + sixtop_remove_links_from_schedule(frame_id, sl, dest_addr); + } + break; + + default: + break; + } +} +/*---------------------------------------------------------------------------*/ +/* Parse a Sixtop IE. Returns length of IE */ +int +sixtop_parse_ie(const uint8_t *buf, linkaddr_t *dest_addr) +{ + struct ieee802154_ies ies; + uint8_t i = 0, max = 0, ie_len = 0; + + /* Parse the 6top message elements */ + int subIE_id = buf[4]; + int version_code = buf[5]; + + /* Parse the 6P Code */ + int code = (version_code & 0xF0) >> 4; + + /* Check for 6P SubIE and 6P Version */ + if(subIE_id == SIXTOP_SUBIE_ID && (version_code & SIXTOP_VERSION)) { + + ies.ie_sixtop.subIE_id = buf[4]; + ies.ie_sixtop.version_code = buf[5]; + ies.ie_sixtop.schedule_fn_id = buf[6]; + + switch(code) { + case CMD_ADD: + case CMD_DELETE: + ies.ie_sixtop.num_links = buf[7]; + ies.ie_sixtop.frame_id = buf[8]; + + /* Save the number of links specified in Link Request IE */ + sixtop_request_num_links = ies.ie_sixtop.num_links; + + if(sixtop_request_num_links == 0) { + PRINTF("TSCH-sixtop:! Requested number of links is zero\n"); + return -1; + } + + if(code == CMD_ADD) { + max = SIXTOP_IE_MAX_LINKS; + PRINTF("TSCH-sixtop: Received a 6P Add Request for %d links from node %d with LinkList : ", + sixtop_request_num_links, dest_addr->u8[7]); + } else { /* CMD_DELETE */ + max = ies.ie_sixtop.num_links; /* delete atmost one */ + PRINTF("TSCH-sixtop: Received a 6P Delete Request for %d links from node %d with LinkList : ", + sixtop_request_num_links, dest_addr->u8[7]); + } + + /* Parse the Candidate Link List */ + for(i = 0; i < max; i++) { + READ16(buf + 9 + i * 4, ies.ie_sixtop.linkList[i].timeslot); + READ16(buf + 9 + i * 4 + 2, ies.ie_sixtop.linkList[i].channel_offset); + PRINTF("%d ", ies.ie_sixtop.linkList[i].timeslot); + } + PRINTF("\n"); + + /* Update the IE length */ + ie_len = 9 + (max * 4); + + /* Process Sixtop IE by code */ + sixtop_process_by_code(code, &ies, dest_addr); + + break; + + case RC_SUCCESS: /* Response Code Success */ + if(sixtop_state == SIXTOP_ADD_RESPONSE_WAIT) { + PRINTF("TSCH-sixtop: Received a 6P Add Response from node %d with LinkList : ", dest_addr->u8[7]); + sixtop_state = SIXTOP_ADD_RESPONSE_RECEIVED; + } else if(sixtop_state == SIXTOP_DELETE_RESPONSE_WAIT) { + PRINTF("TSCH-sixtop: Received a 6P Delete Response from node %d with LinkList : ", dest_addr->u8[7]); + sixtop_state = SIXTOP_DELETE_RESPONSE_RECEIVED; + } + + /* Parse the Candidate Link List */ + for(i = 0; i < sixtop_request_num_links; i++) { + READ16(buf + 7 + i * 4, ies.ie_sixtop.linkList[i].timeslot); + READ16(buf + 7 + i * 4 + 2, ies.ie_sixtop.linkList[i].channel_offset); + PRINTF("%d ", ies.ie_sixtop.linkList[i].timeslot); + } + PRINTF("\n"); + + /* Update the IE length */ + ie_len = 7 + (sixtop_request_num_links * 4); + + /* Process Sixtop IE by code */ + sixtop_process_by_code(code, &ies, dest_addr); + + break; + + default: + break; + } + } + + return ie_len; +} +/*---------------------------------------------------------------------------*/ +/* Is it a Sixtop IE? Returns 0 if success */ +int +sixtop_is_sixtop_ie(const uint8_t *buf, int buf_size, + frame802154_t *frame, struct ieee802154_ies *ies) +{ + uint8_t curr_len = 0; + int ret; + + if(frame == NULL || buf_size < 0) { + return -1; + } + + /* Parse 802.15.4-2006 frame, i.e. all fields before Information Elements */ + if((ret = frame802154_parse((uint8_t *)buf, buf_size, frame)) == 0) { + PRINTF("TSCH-sixtop:! parse_sixtop_ie: failed to parse frame\n"); + return -1; + } + + if(frame->fcf.frame_version < FRAME802154_IEEE802154E_2012 + || frame->fcf.frame_type != FRAME802154_DATAFRAME) { + PRINTF("TSCH-sixtop:! parse_sixtop_ie: frame is not a valid Sixtop IE. Frame version %u, type %u, FCF %02x %02x\n", + frame->fcf.frame_version, frame->fcf.frame_type, buf[0], buf[1]); + PRINTF("TSCH-sixtop:! parse_sixtop_ie: frame was from 0x%x/", frame->src_pid); + PRINTLLADDR((const uip_lladdr_t *)&frame->src_addr); + PRINTF(" to 0x%x/", frame->dest_pid); + PRINTLLADDR((const uip_lladdr_t *)&frame->dest_addr); + PRINTF("\n"); + return -1; + } + curr_len += ret; + + if(ies != NULL) { + memset(ies, 0, sizeof(struct ieee802154_ies)); + } + if(frame->fcf.ie_list_present) { + int mic_len = 0; + + /* Parse information elements. We need to substract the MIC length, as the exact payload len is needed while parsing */ + if((ret = frame802154e_parse_information_elements(buf + curr_len, buf_size - curr_len - mic_len, ies)) == -1) { + PRINTF("TSCH-sixtop:! parse_sixtop_ie: failed to parse IEs\n"); + return -1; + } else if(!ret) { + PRINTF("TSCH-sixtop: Sixtop IE received\n"); + return 0; /* Sixtop IE found. Return success(0) */ + } + curr_len += ret; + } + + return curr_len; +} +/*---------------------------------------------------------------------------*/ +/* Set the Sequence Number of Link Response as in Link Request */ +/* Function is called from TSCH layer on receiving a Sixtop IE */ +void +sixtop_set_seqno(uint8_t seq_num) +{ + sixtop_response_seqno = seq_num; +} diff --git a/os/net/mac/tsch/sixtop/sixtop.h b/os/net/mac/tsch/sixtop/sixtop.h new file mode 100644 index 000000000..1b0861dd0 --- /dev/null +++ b/os/net/mac/tsch/sixtop/sixtop.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * A sixtop protocol that performs link addition/deletion + * \author + * Shalu R + * Lijo Thomas + */ + +#ifndef __SIXTOP_H__ +#define __SIXTOP_H__ + +#include "contiki.h" +#include "stdbool.h" +#include "net/ip/uip-debug.h" +#include "net/linkaddr.h" +#include "net/netstack.h" +#include "net/mac/tsch/tsch-schedule.h" +#include "net/mac/tsch/tsch-asn.h" + +#define SIXTOP_SUBIE_ID 0x00 +#define SIXTOP_VERSION 0x01 + +/* Link Option OFF */ +#define LINK_OPTION_OFF 0 + +/* Maximum number of retransmissions permissible at MAC layer */ +#define SIXTOP_CONF_MAX_MAC_TRANSMISSIONS 3 + +/* 6P Command ID */ +enum sixtop_command_id { + CMD_ADD = 0x01, + CMD_DELETE = 0x02, + CMD_COUNT = 0x03, + CMD_LIST = 0x04, + CMD_CLEAR = 0x05, +}; + +/* 6P Return Code */ +enum sixtop_return_code { + RC_SUCCESS = 0x06, /* Operation succeeded */ + RC_VER_ERR = 0x07, /* Unsupported 6P version */ + RC_SFID_ERR = 0x08, /* Unsupported SFID */ + RC_BUSY = 0x09, /* Handling previous request */ + RC_RESET = 0x0a, /* Abort 6P transaction */ + RC_ERR = 0x0b, /* Operation failed */ +}; + +/* Sixtop State Machine */ +enum { + SIXTOP_IDLE = 0x00, + SIXTOP_ADD_REQUEST_WAIT_SENDDONE = 0x01, /* Waiting for SendDone confirmation of Add Request */ + SIXTOP_ADD_RESPONSE_WAIT = 0x02, /* Waiting for Add Response */ + SIXTOP_ADD_RESPONSE_WAIT_SENDDONE = 0x03, /* Waiting for SendDone confirmation of Add Response */ + SIXTOP_ADD_RESPONSE_RECEIVED = 0x04, /* Received Add Response */ + SIXTOP_DELETE_REQUEST_WAIT_SENDDONE = 0x05, /* Waiting for SendDone confirmation of Delete Request */ + SIXTOP_DELETE_RESPONSE_WAIT = 0x06, /* waiting for Delete Response */ + SIXTOP_DELETE_RESPONSE_WAIT_SENDDONE = 0x07, /* Waiting for SendDone confirmation of Add Response */ + SIXTOP_DELETE_RESPONSE_RECEIVED = 0x08, /* Received Delete Response */ +} sixtop_state; + +/********** Functions *********/ +/* Initiates a Sixtop Link addition */ +int sixtop_add_links(linkaddr_t *dest_addr, uint8_t num_Links); +/* Initiates a Sixtop Link deletion */ +int sixtop_remove_link(linkaddr_t *dest_addr); +/* Is it a Sixtop IE? Returns 0 if success */ +int sixtop_is_sixtop_ie(const uint8_t *buf, int buf_size, frame802154_t *frame, struct ieee802154_ies *ies); +/* Set the Sequence Number of Link Response as in Link Request */ +void sixtop_set_seqno(uint8_t seq_num); +/* Parse a Sixtop IE. Returns length of IE */ +int sixtop_parse_ie(const uint8_t *buf, linkaddr_t *dest_addr); + +#endif /* __SIXTOP_H__ */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index a4b30e137..b1915ab54 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -55,6 +55,7 @@ #include "net/mac/tsch/tsch-log.h" #include "net/mac/tsch/tsch-packet.h" #include "net/mac/tsch/tsch-security.h" +#include "net/mac/tsch/sixtop/sixtop.h" #include "net/mac/mac-sequence.h" #include "lib/random.h" @@ -245,7 +246,6 @@ tsch_reset(void) #endif /* TSCH_AUTOSELECT_TIME_SOURCE */ tsch_set_eb_period(TSCH_EB_PERIOD); } - /* TSCH keep-alive functions */ /*---------------------------------------------------------------------------*/ @@ -407,7 +407,6 @@ eb_input(struct input_packet *current_input) } } } - /*---------------------------------------------------------------------------*/ /* Process pending input packet(s) */ static void @@ -424,6 +423,28 @@ tsch_rx_process_pending() && frame.fcf.frame_version == FRAME802154_IEEE802154_2015 && frame.fcf.frame_type == FRAME802154_BEACONFRAME; +#if TSCH_WITH_SIXTOP + int is_ie = ret + && frame.fcf.frame_version == FRAME802154_IEEE802154E_2012 + && frame.fcf.frame_type == FRAME802154_DATAFRAME + && frame.fcf.ie_list_present == 1; + + if(is_ie) { + /* IE received (Data may/ maynot be present) */ + + /* Save sequence number of Link Request */ + sixtop_set_seqno(frame.seq); + + /* Check and parse, if it is a Sixtop IE. Returns length of data */ + uint8_t data_len = ie_input(current_input); + + if(data_len <= 0) { + /* Only Sixtop IE present , no data */ + is_data = 0; + } + } +#endif /* TSCH_WITH_SIXTOP */ + if(is_data) { /* Skip EBs and other control messages */ /* Copy to packetbuf for processing */ @@ -443,7 +464,6 @@ tsch_rx_process_pending() ringbufindex_get(&input_ringbuf); } } - /*---------------------------------------------------------------------------*/ /* Pass sent packets to upper layer */ static void @@ -613,9 +633,9 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) ies.ie_tsch_slotframe_and_link.slotframe_size); for(i = 0; i < num_links; i++) { tsch_schedule_add_link(sf, - ies.ie_tsch_slotframe_and_link.links[i].link_options, - LINK_TYPE_ADVERTISING, &tsch_broadcast_address, - ies.ie_tsch_slotframe_and_link.links[i].timeslot, ies.ie_tsch_slotframe_and_link.links[i].channel_offset); + ies.ie_tsch_slotframe_and_link.links[i].link_options, + LINK_TYPE_ADVERTISING, &tsch_broadcast_address, + ies.ie_tsch_slotframe_and_link.links[i].timeslot, ies.ie_tsch_slotframe_and_link.links[i].channel_offset); } } else { LOG_ERR("! parse_eb: too many links in schedule (%u)\n", num_links); @@ -672,7 +692,6 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) LOG_ERR("! did not associate.\n"); return 0; } - /* Processes and protothreads used by TSCH */ /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index d436b69af..9516e09c8 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -145,6 +145,13 @@ #define TSCH_AUTOSELECT_TIME_SOURCE 0 #endif /* TSCH_CONF_EB_AUTOSELECT */ +/* To include Sixtop Implementation */ +#ifdef TSCH_CONF_WITH_SIXTOP +#define TSCH_WITH_SIXTOP TSCH_CONF_WITH_SIXTOP +#else +#define TSCH_WITH_SIXTOP 0 +#endif /* TSCH_CONF_EB_AUTOSELECT */ + /*********** Callbacks *********/ /* Called by TSCH when joining a network */