/* * 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 */ #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(); } } } /*---------------------------------------------------------------------------*/ /** @} */