sixtop: 6top protocol implementation by CDAC
https://github.com/contiki-os/contiki/pull/1898
This commit is contained in:
parent
69affad825
commit
cc1c763db9
23
examples/ipv6/rpl-tsch-sixtop/Makefile
Normal file
23
examples/ipv6/rpl-tsch-sixtop/Makefile
Normal file
@ -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
|
39
examples/ipv6/rpl-tsch-sixtop/README.md
Normal file
39
examples/ipv6/rpl-tsch-sixtop/README.md
Normal file
@ -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.
|
136
examples/ipv6/rpl-tsch-sixtop/node-sixtop.c
Executable file
136
examples/ipv6/rpl-tsch-sixtop/node-sixtop.c
Executable file
@ -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 <simonduq@sics.se>
|
||||||
|
* Shalu R <shalur@cdac.in>
|
||||||
|
* Lijo Thomas <lijo@cdac.in>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
183
examples/ipv6/rpl-tsch-sixtop/project-conf.h
Executable file
183
examples/ipv6/rpl-tsch-sixtop/project-conf.h
Executable file
@ -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__ */
|
160
examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc
Normal file
160
examples/ipv6/rpl-tsch-sixtop/rpl-tsch-sixtop-z1.csc
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<simconf>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||||
|
<simulation>
|
||||||
|
<title>My simulation</title>
|
||||||
|
<randomseed>123456</randomseed>
|
||||||
|
<motedelay_us>1000000</motedelay_us>
|
||||||
|
<radiomedium>
|
||||||
|
org.contikios.cooja.radiomediums.UDGM
|
||||||
|
<transmitting_range>50.0</transmitting_range>
|
||||||
|
<interference_range>100.0</interference_range>
|
||||||
|
<success_ratio_tx>1.0</success_ratio_tx>
|
||||||
|
<success_ratio_rx>1.0</success_ratio_rx>
|
||||||
|
</radiomedium>
|
||||||
|
<events>
|
||||||
|
<logoutput>40000</logoutput>
|
||||||
|
</events>
|
||||||
|
<motetype>
|
||||||
|
org.contikios.cooja.mspmote.Z1MoteType
|
||||||
|
<identifier>z11</identifier>
|
||||||
|
<description>Z1 Mote Type #z11</description>
|
||||||
|
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-tsch-sixtop/node-sixtop.c</source>
|
||||||
|
<commands EXPORT="discard">make node-sixtop.z1 TARGET=z1</commands>
|
||||||
|
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-tsch-sixtop/node-sixtop.z1</firmware>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||||
|
</motetype>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>3.827476552301217</x>
|
||||||
|
<y>2.167129170680247</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>1</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>30.278379737463556</x>
|
||||||
|
<y>17.799585117738026</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>2</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
</simulation>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.SimControl
|
||||||
|
<width>280</width>
|
||||||
|
<z>0</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>400</location_x>
|
||||||
|
<location_y>0</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Visualizer
|
||||||
|
<plugin_config>
|
||||||
|
<moterelations>true</moterelations>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||||
|
<viewport>4.027583163598053 0.0 0.0 4.027583163598053 133.5292942712438 14.03198741893021</viewport>
|
||||||
|
</plugin_config>
|
||||||
|
<width>400</width>
|
||||||
|
<z>3</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>1</location_x>
|
||||||
|
<location_y>1</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.LogListener
|
||||||
|
<plugin_config>
|
||||||
|
<filter>TSCH-sch</filter>
|
||||||
|
<formatted_time />
|
||||||
|
<coloring />
|
||||||
|
</plugin_config>
|
||||||
|
<width>854</width>
|
||||||
|
<z>1</z>
|
||||||
|
<height>342</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>161</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.TimeLine
|
||||||
|
<plugin_config>
|
||||||
|
<mote>0</mote>
|
||||||
|
<mote>1</mote>
|
||||||
|
<showRadioRXTX />
|
||||||
|
<showRadioHW />
|
||||||
|
<showLEDs />
|
||||||
|
<zoomfactor>500.0</zoomfactor>
|
||||||
|
</plugin_config>
|
||||||
|
<width>1366</width>
|
||||||
|
<z>5</z>
|
||||||
|
<height>166</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>503</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Notes
|
||||||
|
<plugin_config>
|
||||||
|
<notes>Enter notes here</notes>
|
||||||
|
<decorations>true</decorations>
|
||||||
|
</plugin_config>
|
||||||
|
<width>686</width>
|
||||||
|
<z>4</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>680</location_x>
|
||||||
|
<location_y>0</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.RadioLogger
|
||||||
|
<plugin_config>
|
||||||
|
<split>150</split>
|
||||||
|
<formatted_time />
|
||||||
|
<showdups>false</showdups>
|
||||||
|
<hidenodests>false</hidenodests>
|
||||||
|
</plugin_config>
|
||||||
|
<width>508</width>
|
||||||
|
<z>2</z>
|
||||||
|
<height>343</height>
|
||||||
|
<location_x>854</location_x>
|
||||||
|
<location_y>160</location_y>
|
||||||
|
</plugin>
|
||||||
|
</simconf>
|
||||||
|
|
64
os/net/mac/tsch/sixtop/README.md
Normal file
64
os/net/mac/tsch/sixtop/README.md
Normal file
@ -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)
|
||||||
|
|
||||||
|
|
839
os/net/mac/tsch/sixtop/sixtop.c
Normal file
839
os/net/mac/tsch/sixtop/sixtop.c
Normal file
@ -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 <shalur@cdac.in>
|
||||||
|
* Lijo Thomas <lijo@cdac.in>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
105
os/net/mac/tsch/sixtop/sixtop.h
Normal file
105
os/net/mac/tsch/sixtop/sixtop.h
Normal file
@ -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 <shalur@cdac.in>
|
||||||
|
* Lijo Thomas <lijo@cdac.in>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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__ */
|
@ -55,6 +55,7 @@
|
|||||||
#include "net/mac/tsch/tsch-log.h"
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
#include "net/mac/tsch/tsch-packet.h"
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
#include "net/mac/tsch/tsch-security.h"
|
#include "net/mac/tsch/tsch-security.h"
|
||||||
|
#include "net/mac/tsch/sixtop/sixtop.h"
|
||||||
#include "net/mac/mac-sequence.h"
|
#include "net/mac/mac-sequence.h"
|
||||||
#include "lib/random.h"
|
#include "lib/random.h"
|
||||||
|
|
||||||
@ -245,7 +246,6 @@ tsch_reset(void)
|
|||||||
#endif /* TSCH_AUTOSELECT_TIME_SOURCE */
|
#endif /* TSCH_AUTOSELECT_TIME_SOURCE */
|
||||||
tsch_set_eb_period(TSCH_EB_PERIOD);
|
tsch_set_eb_period(TSCH_EB_PERIOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TSCH keep-alive functions */
|
/* TSCH keep-alive functions */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -407,7 +407,6 @@ eb_input(struct input_packet *current_input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Process pending input packet(s) */
|
/* Process pending input packet(s) */
|
||||||
static void
|
static void
|
||||||
@ -424,6 +423,28 @@ tsch_rx_process_pending()
|
|||||||
&& frame.fcf.frame_version == FRAME802154_IEEE802154_2015
|
&& frame.fcf.frame_version == FRAME802154_IEEE802154_2015
|
||||||
&& frame.fcf.frame_type == FRAME802154_BEACONFRAME;
|
&& 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) {
|
if(is_data) {
|
||||||
/* Skip EBs and other control messages */
|
/* Skip EBs and other control messages */
|
||||||
/* Copy to packetbuf for processing */
|
/* Copy to packetbuf for processing */
|
||||||
@ -443,7 +464,6 @@ tsch_rx_process_pending()
|
|||||||
ringbufindex_get(&input_ringbuf);
|
ringbufindex_get(&input_ringbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Pass sent packets to upper layer */
|
/* Pass sent packets to upper layer */
|
||||||
static void
|
static void
|
||||||
@ -672,7 +692,6 @@ tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
|
|||||||
LOG_ERR("! did not associate.\n");
|
LOG_ERR("! did not associate.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Processes and protothreads used by TSCH */
|
/* Processes and protothreads used by TSCH */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -145,6 +145,13 @@
|
|||||||
#define TSCH_AUTOSELECT_TIME_SOURCE 0
|
#define TSCH_AUTOSELECT_TIME_SOURCE 0
|
||||||
#endif /* TSCH_CONF_EB_AUTOSELECT */
|
#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 *********/
|
/*********** Callbacks *********/
|
||||||
|
|
||||||
/* Called by TSCH when joining a network */
|
/* Called by TSCH when joining a network */
|
||||||
|
Loading…
Reference in New Issue
Block a user