287 lines
8.7 KiB
C
287 lines
8.7 KiB
C
/*
|
|
* Copyright (c) 2016, Yasuyuki Tanaka
|
|
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
|
* COPYRIGHT HOLDER 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.
|
|
*/
|
|
/**
|
|
* \addtogroup sixtop
|
|
* @{
|
|
*/
|
|
/**
|
|
* \file
|
|
* 6TiSCH Operation Sublayer (6top)
|
|
*
|
|
* \author
|
|
* Yasuyuki Tanaka <yasuyuki.tanaka@inf.ethz.ch>
|
|
*/
|
|
|
|
#include "lib/assert.h"
|
|
|
|
#include "net/netstack.h"
|
|
#include "net/packetbuf.h"
|
|
#include "net/mac/framer/frame802154.h"
|
|
#include "net/mac/framer/frame802154e-ie.h"
|
|
|
|
#include "sixtop.h"
|
|
#include "sixtop-conf.h"
|
|
#include "sixp.h"
|
|
|
|
/* Log configuration */
|
|
#include "sys/log.h"
|
|
#define LOG_MODULE "6top"
|
|
#define LOG_LEVEL LOG_LEVEL_6TOP
|
|
|
|
const sixtop_sf_t *scheduling_functions[SIXTOP_MAX_SCHEDULING_FUNCTIONS];
|
|
|
|
const sixtop_sf_t *sixtop_find_sf(uint8_t sfid);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
strip_payload_termination_ie(void)
|
|
{
|
|
uint8_t *ptr = packetbuf_dataptr();
|
|
if(ptr[0] == 0x00 && ptr[1] == 0xf8) {
|
|
/* Payload Termination IE is 2 octets long */
|
|
packetbuf_hdrreduce(2);
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int
|
|
sixtop_add_sf(const sixtop_sf_t *sf)
|
|
{
|
|
int i;
|
|
|
|
assert(sf != NULL);
|
|
|
|
LOG_INFO("6top: sixtop_add_sf() is adding a SF [SFID:%u]\n", sf->sfid);
|
|
|
|
if(sixtop_find_sf(sf->sfid) != NULL) {
|
|
LOG_ERR("6top: sixtop_add_sf() fails because of duplicate SF\n");
|
|
return -1;
|
|
}
|
|
|
|
for(i = 0; i < SIXTOP_MAX_SCHEDULING_FUNCTIONS; i++) {
|
|
if(scheduling_functions[i] == NULL) {
|
|
scheduling_functions[i] = sf;
|
|
if(sf->init != NULL) {
|
|
sf->init();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(i == SIXTOP_MAX_SCHEDULING_FUNCTIONS) {
|
|
LOG_ERR("6top: sixtop_add_sf() fails because of no memory\n");
|
|
return -1;
|
|
}
|
|
|
|
if(sf->init != NULL) {
|
|
sf->init();
|
|
}
|
|
LOG_INFO("6top: SF [SFID:%u] has been added and initialized\n", sf->sfid);
|
|
return 0;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
const sixtop_sf_t *
|
|
sixtop_find_sf(uint8_t sfid)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < SIXTOP_MAX_SCHEDULING_FUNCTIONS; i++) {
|
|
if(scheduling_functions[i] != NULL &&
|
|
scheduling_functions[i]->sfid == sfid) {
|
|
return (const sixtop_sf_t *)scheduling_functions[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
sixtop_output(const linkaddr_t *dest_addr, mac_callback_t callback, void *arg)
|
|
{
|
|
uint8_t *p;
|
|
struct ieee802154_ies ies;
|
|
int len;
|
|
|
|
assert(dest_addr != NULL);
|
|
if(dest_addr == NULL) {
|
|
LOG_ERR("6top: sixtop_output() fails because dest_addr is NULL\n");
|
|
if(callback != NULL) {
|
|
callback(arg, MAC_TX_ERR_FATAL, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* prepend 6top Sub-IE ID */
|
|
if(packetbuf_hdralloc(1) != 1) {
|
|
LOG_ERR("6top: sixtop_output() fails because of no room for Sub-IE ID\n");
|
|
return;
|
|
}
|
|
p = packetbuf_hdrptr();
|
|
p[0] = SIXTOP_SUBIE_ID;
|
|
|
|
/*
|
|
* prepend Payload IE header; 2 octets
|
|
* only sixtop_ie_content_len matters in frame80215e_create_ie_ietf().
|
|
*/
|
|
memset(&ies, 0, sizeof(ies));
|
|
ies.sixtop_ie_content_len = packetbuf_totlen();
|
|
if(packetbuf_hdralloc(2) != 1 ||
|
|
(len = frame80215e_create_ie_ietf(packetbuf_hdrptr(),
|
|
2,
|
|
&ies)) < 0) {
|
|
LOG_ERR("6top: sixtop_output() fails because of Payload IE Header\n");
|
|
if(callback != NULL) {
|
|
callback(arg, MAC_TX_ERR_FATAL, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if SIXP_WITH_PAYLOAD_TERMINATION_IE
|
|
/* append Payload Termination IE to the data field; 2 octets */
|
|
memset(&ies, 0, sizeof(ies));
|
|
if((len = frame80215e_create_ie_payload_list_termination(
|
|
(uint8_t *)packetbuf_dataptr() + packetbuf_datalen(),
|
|
PACKETBUF_SIZE - packetbuf_totlen(),
|
|
&ies)) < 0) {
|
|
LOG_ERR("6top: sixtop_output() fails because of Payload Termination IE\n");
|
|
callback(arg, MAC_TX_ERR_FATAL, 0);
|
|
return;
|
|
}
|
|
packetbuf_set_datalen(packetbuf_datalen() + len);
|
|
#endif /* SIXP_WITH_PAYLOAD_TERMINATION_IE */
|
|
|
|
/* prepend Termination 1 IE to the header field; 2 octets */
|
|
memset(&ies, 0, sizeof(ies));
|
|
if(packetbuf_hdralloc(2) &&
|
|
frame80215e_create_ie_header_list_termination_1(packetbuf_hdrptr(),
|
|
2,
|
|
&ies) < 0) {
|
|
LOG_ERR("6top: sixtop_output() fails because of Header Termination 1 IE\n");
|
|
callback(arg, MAC_TX_ERR_FATAL, 0);
|
|
return;
|
|
}
|
|
|
|
/* specify with PACKETBUF_ATTR_METADATA that packetbuf has IEs */
|
|
packetbuf_set_attr(PACKETBUF_ATTR_MAC_METADATA, 1);
|
|
|
|
/* 6P packet is data frame */
|
|
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
|
|
|
|
packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, dest_addr);
|
|
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
|
|
|
|
NETSTACK_MAC.send(callback, arg);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
sixtop_input(void)
|
|
{
|
|
uint8_t *hdr_ptr, *payload_ptr;
|
|
uint16_t hdr_len, payload_len;
|
|
|
|
frame802154_t frame;
|
|
struct ieee802154_ies ies;
|
|
linkaddr_t src_addr;
|
|
|
|
/*
|
|
* A received *DATA* frame is supposed to be stored in packetbuf by
|
|
* framer_802154.parse(). packetbuf_dataptr() points at the starting address
|
|
* of the IE field or Frame Payload field if it's available. FCS should not be
|
|
* in packetbuf, which is expected to be stripped at a radio.
|
|
*/
|
|
|
|
payload_ptr = packetbuf_dataptr();
|
|
payload_len = packetbuf_datalen();
|
|
hdr_len = packetbuf_hdrlen();
|
|
hdr_ptr = payload_ptr - hdr_len;
|
|
|
|
memcpy(&src_addr, packetbuf_addr(PACKETBUF_ADDR_SENDER), sizeof(src_addr));
|
|
|
|
if(frame802154_parse(hdr_ptr, hdr_len, &frame) == 0) {
|
|
/* parse error; should not occur, anyway */
|
|
LOG_ERR("6top: frame802154_parse error\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* We don't need to check the frame version nor frame type. The frame version
|
|
* is turned out to be 0b10 automatically if the frame has a IE list. The
|
|
* frame type is supposed to be DATA as mentioned above.
|
|
*/
|
|
assert(frame.fcf.frame_version == FRAME802154_IEEE802154_2015);
|
|
assert(frame.fcf.frame_type == FRAME802154_DATAFRAME);
|
|
memset(&ies, 0, sizeof(ies));
|
|
if(frame.fcf.ie_list_present &&
|
|
frame802154e_parse_information_elements(payload_ptr,
|
|
payload_len, &ies) >= 0 &&
|
|
ies.sixtop_ie_content_ptr != NULL &&
|
|
ies.sixtop_ie_content_len > 0) {
|
|
|
|
sixp_input(ies.sixtop_ie_content_ptr, ies.sixtop_ie_content_len,
|
|
&src_addr);
|
|
|
|
/*
|
|
* move payloadbuf_dataptr() to the beginning of the next layer for further
|
|
* processing
|
|
*/
|
|
packetbuf_hdrreduce(ies.sixtop_ie_content_ptr - payload_ptr +
|
|
ies.sixtop_ie_content_len);
|
|
strip_payload_termination_ie();
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
sixtop_init(void)
|
|
{
|
|
int i;
|
|
|
|
sixp_init();
|
|
|
|
for(i = 0; i < SIXTOP_MAX_SCHEDULING_FUNCTIONS; i++) {
|
|
scheduling_functions[i] = NULL;
|
|
}
|
|
|
|
sixtop_init_sf();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
sixtop_init_sf(void)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < SIXTOP_MAX_SCHEDULING_FUNCTIONS; i++) {
|
|
if(scheduling_functions[i] != NULL &&
|
|
scheduling_functions[i]->init != NULL) {
|
|
scheduling_functions[i]->init();
|
|
}
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
/** @} */
|