diff --git a/arch/cpu/nrf52832/ble/ble-mac.c b/arch/cpu/nrf52832/ble/ble-mac.c index 4fe1ef934..d604a911d 100644 --- a/arch/cpu/nrf52832/ble/ble-mac.c +++ b/arch/cpu/nrf52832/ble/ble-mac.c @@ -347,6 +347,12 @@ off(void) return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return PACKETBUF_SIZE; +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -371,7 +377,8 @@ const struct mac_driver ble_ipsp_mac_driver = { send_packet, NULL, on, - off + off, + max_payload }; /*---------------------------------------------------------------------------*/ /** diff --git a/examples/rpl-udp/udp-client.c b/examples/rpl-udp/udp-client.c index 1fb030034..7f24c8bac 100644 --- a/examples/rpl-udp/udp-client.c +++ b/examples/rpl-udp/udp-client.c @@ -32,16 +32,21 @@ udp_rx_callback(struct simple_udp_connection *c, const uint8_t *data, uint16_t datalen) { - unsigned count = *(unsigned *)data; - LOG_INFO("Received response %u from ", count); + + LOG_INFO("Received response '%.*s' from ", datalen, (char *) data); LOG_INFO_6ADDR(sender_addr); +#if LLSEC802154_CONF_ENABLED + LOG_INFO_(" LLSEC LV:%d", uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); +#endif LOG_INFO_("\n"); + } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic_timer; static unsigned count; + static char str[32]; uip_ipaddr_t dest_ipaddr; PROCESS_BEGIN(); @@ -59,7 +64,8 @@ PROCESS_THREAD(udp_client_process, ev, data) LOG_INFO("Sending request %u to ", count); LOG_INFO_6ADDR(&dest_ipaddr); LOG_INFO_("\n"); - simple_udp_sendto(&udp_conn, &count, sizeof(count), &dest_ipaddr); + snprintf(str, sizeof(str), "hello %d", count); + simple_udp_sendto(&udp_conn, str, strlen(str), &dest_ipaddr); count++; } else { LOG_INFO("Not reachable yet\n"); diff --git a/examples/rpl-udp/udp-server.c b/examples/rpl-udp/udp-server.c index 399cabfc4..072eb8ae8 100644 --- a/examples/rpl-udp/udp-server.c +++ b/examples/rpl-udp/udp-server.c @@ -54,15 +54,13 @@ udp_rx_callback(struct simple_udp_connection *c, const uint8_t *data, uint16_t datalen) { - unsigned count = *(unsigned *)data; - LOG_INFO("Received request %u from ", count); + LOG_INFO("Received request '%.*s' from ", datalen, (char *) data); LOG_INFO_6ADDR(sender_addr); LOG_INFO_("\n"); #if WITH_SERVER_REPLY - LOG_INFO("Sending response %u to ", count); - LOG_INFO_6ADDR(sender_addr); - LOG_INFO_("\n"); - simple_udp_sendto(&udp_conn, &count, sizeof(count), sender_addr); + /* send back the same string to the client as an echo reply */ + LOG_INFO("Sending response.\n"); + simple_udp_sendto(&udp_conn, data, datalen, sender_addr); #endif /* WITH_SERVER_REPLY */ } /*---------------------------------------------------------------------------*/ diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 35128c3d7..d61d44baf 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -126,24 +126,6 @@ /** @} */ - -/** \brief Maximum available size for frame headers, - link layer security-related overhead, as well as - 6LoWPAN payload. */ -#ifdef SICSLOWPAN_CONF_MAC_MAX_PAYLOAD -#define MAC_MAX_PAYLOAD SICSLOWPAN_CONF_MAC_MAX_PAYLOAD -#else /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ -#define MAC_MAX_PAYLOAD (127 - 2) -#endif /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ - -/** \brief Maximum size of a frame header. This value is - * used in case framer returns an error */ -#ifdef SICSLOWPAN_CONF_MAC_MAX_HEADER -#define MAC_MAX_HEADER SICSLOWPAN_CONF_MAC_MAX_HEADER -#else /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ -#define MAC_MAX_HEADER 21 -#endif /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ - /* set this to zero if not compressing EXT_HDR - for backwards compatibility */ #ifdef SICSLOWPAN_CONF_COMPRESS_EXT_HDR #define COMPRESS_EXT_HDR SICSLOWPAN_CONF_COMPRESS_EXT_HDR @@ -246,7 +228,7 @@ static uint16_t my_tag; #define SICSLOWPAN_FRAGMENT_SIZE SICSLOWPAN_CONF_FRAGMENT_SIZE #else /* The default fragment size (110 bytes for 127-2 bytes frames) */ -#define SICSLOWPAN_FRAGMENT_SIZE (MAC_MAX_PAYLOAD - 15) +#define SICSLOWPAN_FRAGMENT_SIZE (127 - 2 - 15) #endif /* Assuming that the worst growth for uncompression is 38 bytes */ @@ -1544,8 +1526,6 @@ fragment_copy_payload_and_send(uint16_t uip_offset, linkaddr_t *dest) { static uint8_t output(const linkaddr_t *localdest) { - int framer_hdrlen; - int max_payload; int frag_needed; /* The MAC address of the destination of the packet */ @@ -1584,13 +1564,23 @@ output(const linkaddr_t *localdest) /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC */ packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = MAC_MAX_HEADER; - } +#if LLSEC802154_USES_AUX_HEADER + /* copy LLSEC level */ + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); +#if LLSEC802154_USES_EXPLICIT_KEYS + packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_KEY_ID)); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_USES_AUX_HEADER */ - mac_max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; + mac_max_payload = NETSTACK_MAC.max_payload(); + + if(mac_max_payload <= 0) { + /* Framing failed, drop packet */ + LOG_WARN("output: failed to calculate payload size - dropping packet\n"); + return 0; + } /* Try to compress the headers */ #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 @@ -1611,22 +1601,17 @@ output(const linkaddr_t *localdest) } #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ - /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC. - * We calculate it here only to make a better decision of whether the outgoing packet - * needs to be fragmented or not. */ - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = MAC_MAX_HEADER; - } + /* Use the mac_max_payload to understand what is the max payload in a MAC + * packet. We calculate it here only to make a better decision of whether + * the outgoing packet needs to be fragmented or not. */ - max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; - frag_needed = (int)uip_len - (int)uncomp_hdr_len + (int)packetbuf_hdr_len > max_payload; + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); + + frag_needed = (int)uip_len - (int)uncomp_hdr_len + (int)packetbuf_hdr_len > mac_max_payload; LOG_INFO("output: header len %d -> %d, total len %d -> %d, MAC max payload %d, frag_needed %d\n", uncomp_hdr_len, packetbuf_hdr_len, uip_len, uip_len - uncomp_hdr_len + packetbuf_hdr_len, - max_payload, frag_needed); + mac_max_payload, frag_needed); if(frag_needed) { #if SICSLOWPAN_CONF_FRAG @@ -1646,11 +1631,11 @@ output(const linkaddr_t *localdest) /* Total IPv6 payload */ int total_payload = (uip_len - uncomp_hdr_len); /* IPv6 payload that goes to first fragment */ - int frag1_payload = (max_payload - packetbuf_hdr_len - SICSLOWPAN_FRAG1_HDR_LEN) & 0xfffffff8; + int frag1_payload = (mac_max_payload - packetbuf_hdr_len - SICSLOWPAN_FRAG1_HDR_LEN) & 0xfffffff8; /* max IPv6 payload in each FRAGN. Must be multiple of 8 bytes */ - int fragn_max_payload = (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) & 0xfffffff8; + int fragn_max_payload = (mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN) & 0xfffffff8; /* max IPv6 payload in the last fragment. Needs not be multiple of 8 bytes */ - int last_fragn_max_payload = max_payload - SICSLOWPAN_FRAGN_HDR_LEN; + int last_fragn_max_payload = mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN; /* sum of all IPv6 payload that goes to non-first and non-last fragments */ int middle_fragn_total_payload = MAX(total_payload - frag1_payload - last_fragn_max_payload, 0); /* Ceiling of: 2 + middle_fragn_total_payload / fragn_max_payload */ @@ -1802,6 +1787,9 @@ input(void) return; } + /* Clear uipbuf and set default attributes */ + uipbuf_clear(); + /* This is default uip_buf since we assume that this is not fragmented */ buffer = (uint8_t *)UIP_IP_BUF; @@ -1836,7 +1824,6 @@ input(void) } buffer = frag_info[frag_context].first_frag; - break; case SICSLOWPAN_DISPATCH_FRAGN: /* @@ -2000,6 +1987,19 @@ input(void) callback->input_callback(); } +#if LLSEC802154_USES_AUX_HEADER + /* + * Assuming that the last packet in packetbuf is containing + * the LLSEC state so that it can be copied to uipbuf. + */ + uipbuf_set_attr(UIPBUF_ATTR_LLSEC_LEVEL, + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)); +#if LLSEC802154_USES_EXPLICIT_KEYS + uipbuf_set_attr(UIPBUF_ATTR_LLSEC_KEY_ID, + packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX)); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_USES_AUX_HEADER */ + tcpip_input(); #if SICSLOWPAN_CONF_FRAG } diff --git a/os/net/ipv6/uip6.c b/os/net/ipv6/uip6.c index 25e052f34..8a1c27682 100644 --- a/os/net/ipv6/uip6.c +++ b/os/net/ipv6/uip6.c @@ -388,6 +388,7 @@ uip_init(void) { int c; + uipbuf_init(); uip_ds6_init(); uip_icmp6_init(); uip_nd6_init(); diff --git a/os/net/ipv6/uipbuf.c b/os/net/ipv6/uipbuf.c index eaf43e308..f7e8f4b06 100644 --- a/os/net/ipv6/uipbuf.c +++ b/os/net/ipv6/uipbuf.c @@ -37,6 +37,7 @@ /*---------------------------------------------------------------------------*/ static uint16_t uipbuf_attrs[UIPBUF_ATTR_MAX]; +static uint16_t uipbuf_default_attrs[UIPBUF_ATTR_MAX]; /*---------------------------------------------------------------------------*/ void @@ -197,15 +198,21 @@ uipbuf_set_attr(uint8_t type, uint16_t value) return 0; } /*---------------------------------------------------------------------------*/ +int +uipbuf_set_default_attr(uint8_t type, uint16_t value) +{ + if(type < UIPBUF_ATTR_MAX) { + uipbuf_default_attrs[type] = value; + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ void uipbuf_clear_attr(void) { - /* set everything to "zero" */ - memset(uipbuf_attrs, 0, sizeof(uipbuf_attrs)); - - /* And initialize anything that should be initialized */ - uipbuf_set_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, - UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED); + /* set everything to "defaults" */ + memcpy(uipbuf_attrs, uipbuf_default_attrs, sizeof(uipbuf_attrs)); } /*---------------------------------------------------------------------------*/ void @@ -227,3 +234,17 @@ uipbuf_is_attr_flag(uint16_t flag) return (uipbuf_attrs[UIPBUF_ATTR_FLAGS] & flag) == flag; } /*---------------------------------------------------------------------------*/ +void +uipbuf_init(void) +{ + memset(uipbuf_default_attrs, 0, sizeof(uipbuf_default_attrs)); + /* And initialize anything that should be initialized */ + uipbuf_set_default_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, + UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED); + /* set the not-set default value - this will cause the MAC layer to + configure its default */ + uipbuf_set_default_attr(UIPBUF_ATTR_LLSEC_LEVEL, + UIPBUF_ATTR_LLSEC_LEVEL_MAC_DEFAULT); +} + +/*---------------------------------------------------------------------------*/ diff --git a/os/net/ipv6/uipbuf.h b/os/net/ipv6/uipbuf.h index 96b180ee8..fdea60b28 100644 --- a/os/net/ipv6/uipbuf.h +++ b/os/net/ipv6/uipbuf.h @@ -125,6 +125,17 @@ uint16_t uipbuf_get_attr(uint8_t type); */ int uipbuf_set_attr(uint8_t type, uint16_t value); +/** + * \brief Set the default value of the attribute + * \param type The attribute to set the default value of + * \param value The value to set + * \retval 0 - indicates failure of setting the value + * \retval 1 - indicates success of setting the value + * + * This function sets the default value of a uipbuf attribute. + */ +int uipbuf_set_default_attr(uint8_t type, uint16_t value); + /** * \brief Set bits in the uipbuf attribute flags. * \param flag_bits The bits to set in the flag. @@ -159,6 +170,14 @@ uint16_t uipbuf_is_attr_flag(uint16_t flag_bits); */ void uipbuf_clear_attr(void); +/** + * \brief Initialize uipbuf attributes. + * + * This function initialize all attributes in the uipbuf + * attributes including all flags. + */ +void uipbuf_init(void); + /** * \brief The bits defined for uipbuf attributes flag. * @@ -168,6 +187,9 @@ void uipbuf_clear_attr(void); /* Avoid using prefix compression on the packet (6LoWPAN) */ #define UIPBUF_ATTR_FLAGS_6LOWPAN_NO_PREFIX_COMPRESSION 0x02 +/* MAC will set the default for this packet */ +#define UIPBUF_ATTR_LLSEC_LEVEL_MAC_DEFAULT 0xffff + /** * \brief The attributes defined for uipbuf attributes function. * diff --git a/os/net/mac/ble/ble-l2cap.c b/os/net/mac/ble/ble-l2cap.c index 076d919e8..fb755cc85 100644 --- a/os/net/mac/ble/ble-l2cap.c +++ b/os/net/mac/ble/ble-l2cap.c @@ -505,6 +505,12 @@ off(void) return 0; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return BLE_L2CAP_NODE_MTU; +} +/*---------------------------------------------------------------------------*/ const struct mac_driver ble_l2cap_driver = { "ble-l2cap", init, @@ -512,6 +518,7 @@ const struct mac_driver ble_l2cap_driver = { input, on, off, + max_payload, }; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(ble_l2cap_tx_process, ev, data) diff --git a/os/net/mac/csma/anti-replay.c b/os/net/mac/csma/anti-replay.c new file mode 100644 index 000000000..347674184 --- /dev/null +++ b/os/net/mac/csma/anti-replay.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, Hasso-Plattner-Institut. + * 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 + * Protects against replay attacks by comparing with the last + * unicast or broadcast frame counter of the sender. + * \author + * Konrad Krentz + */ + +/** + * \addtogroup csma + * @{ + */ + +#include "net/mac/csma/anti-replay.h" +#include "net/packetbuf.h" +#include "net/mac/llsec802154.h" + +#if LLSEC802154_USES_FRAME_COUNTER + +/* This node's current frame counter value */ +static uint32_t counter; + +/*---------------------------------------------------------------------------*/ +void +anti_replay_set_counter(void) +{ + frame802154_frame_counter_t reordered_counter; + + ++counter; + reordered_counter.u32 = LLSEC802154_HTONL(counter); + + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, reordered_counter.u16[0]); + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, reordered_counter.u16[1]); +} +/*---------------------------------------------------------------------------*/ +uint32_t +anti_replay_get_counter(void) +{ + frame802154_frame_counter_t disordered_counter; + + disordered_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1); + disordered_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3); + + return LLSEC802154_HTONL(disordered_counter.u32); +} +/*---------------------------------------------------------------------------*/ +void +anti_replay_init_info(struct anti_replay_info *info) +{ + info->last_broadcast_counter + = info->last_unicast_counter + = anti_replay_get_counter(); +} +/*---------------------------------------------------------------------------*/ +int +anti_replay_was_replayed(struct anti_replay_info *info) +{ + uint32_t received_counter; + + received_counter = anti_replay_get_counter(); + + if(packetbuf_holds_broadcast()) { + /* broadcast */ + if(received_counter <= info->last_broadcast_counter) { + return 1; + } else { + info->last_broadcast_counter = received_counter; + return 0; + } + } else { + /* unicast */ + if(received_counter <= info->last_unicast_counter) { + return 1; + } else { + info->last_unicast_counter = received_counter; + return 0; + } + } +} +/*---------------------------------------------------------------------------*/ +#endif /* LLSEC802154_USES_FRAME_COUNTER */ + +/** @} */ diff --git a/os/net/mac/csma/anti-replay.h b/os/net/mac/csma/anti-replay.h new file mode 100644 index 000000000..9211a6e7a --- /dev/null +++ b/os/net/mac/csma/anti-replay.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, Hasso-Plattner-Institut. + * 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 + * Interface to anti-replay mechanisms. + * \author + * Konrad Krentz + */ + +/** + * \addtogroup llsec802154 + * @{ + */ + +#ifndef ANTI_REPLAY_H +#define ANTI_REPLAY_H + +#include "contiki.h" + +struct anti_replay_info { + uint32_t last_broadcast_counter; + uint32_t last_unicast_counter; +}; + +/** + * \brief Sets the frame counter packetbuf attributes. + */ +void anti_replay_set_counter(void); + +/** + * \brief Gets the frame counter from packetbuf. + */ +uint32_t anti_replay_get_counter(void); + +/** + * \brief Initializes the anti-replay information about the sender + * \param info Anti-replay information about the sender + */ +void anti_replay_init_info(struct anti_replay_info *info); + +/** + * \brief Checks if received frame was replayed + * \param info Anti-replay information about the sender + * \retval 0 <-> received frame was not replayed + */ +int anti_replay_was_replayed(struct anti_replay_info *info); + +#endif /* ANTI_REPLAY_H */ + +/** @} */ diff --git a/os/net/mac/csma/ccm-star-packetbuf.c b/os/net/mac/csma/ccm-star-packetbuf.c new file mode 100644 index 000000000..17b9befdc --- /dev/null +++ b/os/net/mac/csma/ccm-star-packetbuf.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Hasso-Plattner-Institut. + * 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 + * CCM* convenience functions for LLSEC use + * \author + * Justin King-Lacroix + * Konrad Krentz + */ + +#include "net/linkaddr.h" +#include "net/packetbuf.h" +#include "net/mac/llsec802154.h" +#include + +#if LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER + +/*---------------------------------------------------------------------------*/ +static const uint8_t * +get_extended_address(const linkaddr_t *addr) +#if LINKADDR_SIZE == 2 +{ + /* workaround for short addresses: derive EUI64 as in RFC 6282 */ + static linkaddr_extended_t template = { { 0x00 , 0x00 , 0x00 , + 0xFF , 0xFE , 0x00 , 0x00 , 0x00 } }; + template.u16[3] = LLSEC802154_HTONS(addr->u16); + + return template.u8; +} +#else /* LINKADDR_SIZE == 2 */ +{ + return addr->u8; +} +#endif /* LINKADDR_SIZE == 2 */ +/*---------------------------------------------------------------------------*/ +void +ccm_star_packetbuf_set_nonce(uint8_t *nonce, int forward) +{ + const linkaddr_t *source_addr; + + source_addr = forward ? &linkaddr_node_addr : packetbuf_addr(PACKETBUF_ADDR_SENDER); + memcpy(nonce, get_extended_address(source_addr), 8); + nonce[8] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3) >> 8; + nonce[9] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3) & 0xff; + nonce[10] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1) >> 8; + nonce[11] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1) & 0xff; + nonce[12] = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL); +} +/*---------------------------------------------------------------------------*/ +#endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */ diff --git a/os/net/mac/csma/ccm-star-packetbuf.h b/os/net/mac/csma/ccm-star-packetbuf.h new file mode 100644 index 000000000..578bdef96 --- /dev/null +++ b/os/net/mac/csma/ccm-star-packetbuf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Hasso-Plattner-Institut. + * 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. + * + */ + +#ifndef CCM_STAR_PACKETBUF_H_ +#define CCM_STAR_PACKETBUF_H_ + +/*---------------------------------------------------------------------------*/ +void ccm_star_packetbuf_set_nonce(uint8_t *nonce, int forward); + +#endif /* CCM_STAR_PACKETBUF_H_ */ diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 0436bacea..ebea0fd8a 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -40,6 +40,7 @@ */ #include "net/mac/csma/csma.h" +#include "net/mac/csma/csma-security.h" #include "net/packetbuf.h" #include "net/queuebuf.h" #include "dev/watchdog.h" @@ -169,9 +170,16 @@ send_one_packet(void *ptr) packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); - if(NETSTACK_FRAMER.create() < 0) { +#if LLSEC802154_ENABLED +#if LLSEC802154_USES_EXPLICIT_KEYS + /* This should possibly be taken from upper layers in the future */ + packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, CSMA_LLSEC_KEY_ID_MODE); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_ENABLED */ + + if(csma_security_create_frame() < 0) { /* Failed to allocate space for headers */ - LOG_ERR("failed to create packet\n"); + LOG_ERR("failed to create packet, seqno: %d\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)); ret = MAC_TX_ERR_FATAL; } else { int is_broadcast; diff --git a/os/net/mac/csma/csma-security.c b/os/net/mac/csma/csma-security.c new file mode 100644 index 000000000..0b44fa348 --- /dev/null +++ b/os/net/mac/csma/csma-security.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2017, RISE SICS + * 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 + * CSMA security + * \author + * Joakim Eriksson + */ + +/** + * \addtogroup csma + * @{ +*/ + +#include "contiki.h" +#include "net/mac/csma/csma.h" +#include "net/mac/csma/anti-replay.h" +#include "net/mac/csma/csma-security.h" +#include "net/mac/framer/frame802154.h" +#include "net/mac/framer/framer-802154.h" +#include "net/mac/llsec802154.h" +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "lib/ccm-star.h" +#include "lib/aes-128.h" +#include +#include +#include "ccm-star-packetbuf.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "CSMA" +#define LOG_LEVEL LOG_LEVEL_MAC + +#if LOG_LEVEL == LOG_LEVEL_DBG +static const char * HEX = "0123456789ABCDEF"; +#endif + +#if LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER + +#define MIC_LEN(level) LLSEC802154_MIC_LEN(level) + +#if LLSEC802154_USES_EXPLICIT_KEYS +#define LLSEC_KEY_INDEX (FRAME802154_IMPLICIT_KEY == packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE) \ + ? 0 \ + : packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX)) +#define LLSEC_KEY_MODE (packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE)) +#else +#define LLSEC_KEY_INDEX (0) +#define LLSEC_KEY_MODE (FRAME802154_IMPLICIT_KEY) +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ + +/** + * The keys for LLSEC for CSMA + */ +typedef struct { + uint8_t u8[16]; +} aes_key_t; +static aes_key_t keys[CSMA_LLSEC_MAXKEYS]; + +/* assumed to be 16 bytes */ +int +csma_security_set_key(uint8_t index, const uint8_t *key) +{ + if(key != NULL && index < CSMA_LLSEC_MAXKEYS) { + memcpy(keys[index].u8, key, 16); + return 1; + } + return 0; +} + +#define N_KEYS (sizeof(keys) / sizeof(aes_key)) +/*---------------------------------------------------------------------------*/ +static int +aead(uint8_t hdrlen, int forward) +{ + uint8_t totlen; + uint8_t nonce[CCM_STAR_NONCE_LENGTH]; + uint8_t *m; + uint8_t m_len; + uint8_t *a; + uint8_t a_len; + uint8_t *result; + /* Allocate for MAX level */ + uint8_t generated_mic[MIC_LEN(7)]; + uint8_t *mic; + uint8_t key_index; + aes_key_t *key; + uint8_t with_encryption; + + key_index = LLSEC_KEY_INDEX; + if(key_index >= CSMA_LLSEC_MAXKEYS) { + LOG_ERR("Key not available: %u\n", key_index); + return 0; + } + + key = &keys[key_index]; + + ccm_star_packetbuf_set_nonce(nonce, forward); + totlen = packetbuf_totlen(); + a = packetbuf_hdrptr(); + + with_encryption = + (packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4) ? 1 : 0; + + if(with_encryption) { + a_len = hdrlen; + m = a + a_len; + m_len = totlen - hdrlen; + } else { + a_len = totlen; + m = NULL; + m_len = 0; + } + + mic = a + totlen; + result = forward ? mic : generated_mic; + + CCM_STAR.set_key(key->u8); + CCM_STAR.aead(nonce, + m, m_len, + a, a_len, + result, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07), + forward); + + if(forward) { + packetbuf_set_datalen(packetbuf_datalen() + MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)); + return 1; + } else { + return (memcmp(generated_mic, mic, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) == 0); + } +} + +/*---------------------------------------------------------------------------*/ +int +csma_security_create_frame(void) +{ + int hdr_len; + + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 && + LLSEC_KEY_INDEX != 0xffff) { + anti_replay_set_counter(); + } + + hdr_len = NETSTACK_FRAMER.create(); + if(hdr_len < 0) { + return hdr_len; + } + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0) { +#if LOG_LEVEL == LOG_LEVEL_DBG + int i = 0; + uint8_t *p; + LOG_DBG(" Payload before (%d):", packetbuf_totlen()); + p = packetbuf_hdrptr(); + for(i = 0; i < packetbuf_totlen(); i++) { + LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]); + } + LOG_DBG("\n"); +#endif + + if(!aead(hdr_len, 1)) { + LOG_ERR("failed to encrypt packet to "); + LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_ERR_("\n"); + return FRAMER_FAILED; + } + LOG_INFO("LLSEC-OUT:"); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_(" "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_INFO_(" %u (%u) LV:%d, KEY:0x%02x\n", packetbuf_datalen(), packetbuf_totlen(), + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL), LLSEC_KEY_INDEX); + +#if LOG_LEVEL == LOG_LEVEL_DBG + LOG_DBG(" Payload after: (%d)", packetbuf_totlen()); + p = packetbuf_hdrptr(); + for(i = 0; i < packetbuf_totlen(); i++) { + LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]); + } + LOG_DBG_("\n"); +#endif + + } + return hdr_len; +} + +/*---------------------------------------------------------------------------*/ +int +csma_security_frame_len(void) +{ + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 && + LLSEC_KEY_INDEX != 0xffff) { + return NETSTACK_FRAMER.length() + + MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07); + } + return NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ +int +csma_security_parse_frame(void) +{ + int hdr_len; + + hdr_len = NETSTACK_FRAMER.parse(); + if(hdr_len < 0) { + return hdr_len; + } + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == 0) { + /* No security - no more processing required */ + return hdr_len; + } + + LOG_INFO("LLSEC-IN: "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_(" "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_INFO_(" %d %u (%u) LV:%d KM:%d KEY:0x%02x\n", hdr_len, packetbuf_datalen(), + packetbuf_totlen(), packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL), + LLSEC_KEY_MODE, + LLSEC_KEY_INDEX); + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != CSMA_LLSEC_SECURITY_LEVEL) { + LOG_INFO("received frame with wrong security level (%u) from ", + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_("\n"); + return FRAMER_FAILED; + } + + if(LLSEC_KEY_MODE != CSMA_LLSEC_KEY_ID_MODE) { + LOG_INFO("received frame with wrong key id mode (%u) from ", LLSEC_KEY_MODE); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO("\n"); + return FRAMER_FAILED; + } + + if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), &linkaddr_node_addr)) { + LOG_INFO("frame from ourselves\n"); + return FRAMER_FAILED; + } + + if(packetbuf_datalen() <= MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) { + LOG_ERR("MIC error - too little data in frame!\n"); + return FRAMER_FAILED; + } + + packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)); + if(!aead(hdr_len, 0)) { + LOG_INFO("received unauthentic frame %u from ", + (unsigned int) anti_replay_get_counter()); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_("\n"); + return FRAMER_FAILED; + } + + /* TODO anti-reply protection */ + return hdr_len; +} +/*---------------------------------------------------------------------------*/ +#else +/* The "unsecure" version of the create frame / parse frame */ +int +csma_security_create_frame(void) +{ + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); + return NETSTACK_FRAMER.create(); +} +int +csma_security_parse_frame(void) +{ + return NETSTACK_FRAMER.parse(); +} + +#endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */ + +/** @} */ diff --git a/os/net/mac/csma/csma-security.h b/os/net/mac/csma/csma-security.h new file mode 100644 index 000000000..97092b84d --- /dev/null +++ b/os/net/mac/csma/csma-security.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, Tiny Mesh AS + * 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 + * LLSEC802154 Security related configuration + * \author + * Olav Frengstad + */ + +#ifndef CSMA_SECURITY_H_ +#define CSMA_SECURITY_H_ + + +#ifdef CSMA_CONF_LLSEC_DEFAULT_KEY0 +#define CSMA_LLSEC_DEFAULT_KEY0 CSMA_CONF_LLSEC_DEFAULT_KEY0 +#else +#define CSMA_LLSEC_DEFAULT_KEY0 {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f} +#endif + +#ifdef CSMA_CONF_LLSEC_SECURITY_LEVEL +#define CSMA_LLSEC_SECURITY_LEVEL CSMA_CONF_LLSEC_SECURITY_LEVEL +#else +#define CSMA_LLSEC_SECURITY_LEVEL 5 +#endif /* CSMA_CONF_LLSEC_SECURITY_LEVEL */ + +#ifdef CSMA_CONF_LLSEC_KEY_ID_MODE +#define CSMA_LLSEC_KEY_ID_MODE CSMA_CONF_LLSEC_KEY_ID_MODE +#else +#define CSMA_LLSEC_KEY_ID_MODE FRAME802154_IMPLICIT_KEY +#endif /* CSMA_CONF_LLSEC_KEY_ID_MODE */ + +#ifdef CSMA_CONF_LLSEC_KEY_INDEX +#define CSMA_LLSEC_KEY_INDEX CSMA_CONF_LLSEC_KEY_INDEX +#else +#define CSMA_LLSEC_KEY_INDEX 0 +#endif /* CSMA_CONF_LLSEC_KEY_INDEX */ + +#ifdef CSMA_CONF_LLSEC_MAXKEYS +#define CSMA_LLSEC_MAXKEYS CSMA_CONF_LLSEC_MAXKEYS +#else +#define CSMA_LLSEC_MAXKEYS 1 +#endif + +#endif /* CSMA_SECURITY_H_ */ diff --git a/os/net/mac/csma/csma.c b/os/net/mac/csma/csma.c index 7259e35c8..63808192f 100644 --- a/os/net/mac/csma/csma.c +++ b/os/net/mac/csma/csma.c @@ -49,10 +49,25 @@ #define LOG_MODULE "CSMA" #define LOG_LEVEL LOG_LEVEL_MAC + +static void +init_sec(void) +{ +#if LLSEC802154_USES_AUX_HEADER + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == + PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT) { + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + CSMA_LLSEC_SECURITY_LEVEL); + } +#endif +} /*---------------------------------------------------------------------------*/ static void send_packet(mac_callback_t sent, void *ptr) { + + init_sec(); + csma_output_packet(sent, ptr); } /*---------------------------------------------------------------------------*/ @@ -70,7 +85,7 @@ input_packet(void) if(packetbuf_datalen() == CSMA_ACK_LEN) { /* Ignore ack packets */ LOG_DBG("ignored ack\n"); - } else if(NETSTACK_FRAMER.parse() < 0) { + } else if(csma_security_parse_frame() < 0) { LOG_ERR("failed to parse %u\n", packetbuf_datalen()); } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) && @@ -131,16 +146,41 @@ off(void) static void init(void) { + +#if LLSEC802154_USES_AUX_HEADER +#ifdef CSMA_LLSEC_DEFAULT_KEY0 + uint8_t key[16] = CSMA_LLSEC_DEFAULT_KEY0; + csma_security_set_key(0, key); +#endif +#endif /* LLSEC802154_USES_AUX_HEADER */ csma_output_init(); on(); } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + int framer_hdrlen; + + init_sec(); + + framer_hdrlen = NETSTACK_FRAMER.length(); + + if(framer_hdrlen < 0) { + /* Framing failed, we assume the maximum header length */ + framer_hdrlen = CSMA_MAC_MAX_HEADER; + } + + return CSMA_MAC_LEN - framer_hdrlen; +} +/*---------------------------------------------------------------------------*/ const struct mac_driver csma_driver = { "CSMA", init, send_packet, input_packet, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/csma/csma.h b/os/net/mac/csma/csma.h index 9e0773f28..88396db0b 100644 --- a/os/net/mac/csma/csma.h +++ b/os/net/mac/csma/csma.h @@ -65,6 +65,25 @@ #define CSMA_ACK_LEN 3 +/* Default MAC len for 802.15.4 classic */ +#ifdef CSMA_MAC_CONF_LEN +#define CSMA_MAC_LEN CSMA_MAC_CONF_LEN +#else +#define CSMA_MAC_LEN 127 - 2 +#endif + +/* just a default - with LLSEC, etc */ +#define CSMA_MAC_MAX_HEADER 21 + + extern const struct mac_driver csma_driver; +/* CSMA security framer functions */ +int csma_security_create_frame(void); +int csma_security_parse_frame(void); + +/* key management for CSMA */ +int csma_security_set_key(uint8_t index, const uint8_t *key); + + #endif /* CSMA_H_ */ diff --git a/os/net/mac/llsec802154.h b/os/net/mac/llsec802154.h index fe1a9d231..e808fef7a 100644 --- a/os/net/mac/llsec802154.h +++ b/os/net/mac/llsec802154.h @@ -74,6 +74,12 @@ #define LLSEC802154_USES_AUX_HEADER LLSEC802154_ENABLED #endif /* LLSEC802154_CONF_USES_AUX_HEADER */ +#ifdef LLSEC802154_CONF_USES_FRAME_COUNTER +#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_CONF_USES_FRAME_COUNTER +#else +#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_ENABLED +#endif /* LLSEC802154_CONF_USES_FRAME_COUNTER */ + #if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN #define LLSEC802154_HTONS(n) (n) #define LLSEC802154_HTONL(n) (n) diff --git a/os/net/mac/mac.h b/os/net/mac/mac.h index 4f2a75b15..f64838b4c 100644 --- a/os/net/mac/mac.h +++ b/os/net/mac/mac.h @@ -76,6 +76,9 @@ struct mac_driver { /** Turn the MAC layer off. */ int (* off)(void); + + /** Read out estimated max payload size based on payload in packetbuf */ + int (* max_payload)(void); }; /* Generic MAC return values. */ diff --git a/os/net/mac/nullmac/nullmac.c b/os/net/mac/nullmac/nullmac.c index a6199a3f9..de92ee5d8 100644 --- a/os/net/mac/nullmac/nullmac.c +++ b/os/net/mac/nullmac/nullmac.c @@ -67,6 +67,12 @@ off(void) return 0; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -78,6 +84,7 @@ const struct mac_driver nullmac_driver = { send_packet, packet_input, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index d158c802c..c4712ce2d 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -66,8 +66,8 @@ /* 1 channel, sequence length 1 */ #define TSCH_HOPPING_SEQUENCE_1_1 (uint8_t[]){ 20 } -/* Max TSCH packet lenght */ -#define TSCH_PACKET_MAX_LEN MIN(127, PACKETBUF_SIZE) +/* Max TSCH packet lenght - last bytes are CRC in default 802.15.4 packets */ +#define TSCH_PACKET_MAX_LEN MIN(127 - 2, PACKETBUF_SIZE) /* The jitter to remove in ticks. * This should be the sum of measurement errors on Tx and Rx nodes. diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 8a5218355..a33feeef1 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -1151,13 +1151,21 @@ turn_off(void) return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + /* Setup security... before. */ + return TSCH_PACKET_MAX_LEN - NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ const struct mac_driver tschmac_driver = { "TSCH", tsch_init, send_packet, packet_input, turn_on, - turn_off + turn_off, + max_payload, }; /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/packetbuf.h b/os/net/packetbuf.h index 20e071474..c077ae940 100644 --- a/os/net/packetbuf.h +++ b/os/net/packetbuf.h @@ -55,6 +55,7 @@ #include "contiki.h" #include "net/linkaddr.h" #include "net/mac/llsec802154.h" +#include "net/mac/csma/csma-security.h" #include "net/mac/tsch/tsch-conf.h" /** @@ -238,6 +239,11 @@ enum { PACKETBUF_ATTR_KEY_INDEX, #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#if LLSEC802154_USES_FRAME_COUNTER + PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, + PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, +#endif /* LLSEC802154_USES_FRAME_COUNTER */ + /* Scope 2 attributes: used between end-to-end nodes. */ /* These must be last */ PACKETBUF_ADDR_SENDER, @@ -277,6 +283,8 @@ void packetbuf_attr_copyfrom(struct packetbuf_attr *attrs, #define PACKETBUF_ATTR_BYTE 8 #define PACKETBUF_ADDRSIZE (LINKADDR_SIZE * PACKETBUF_ATTR_BYTE) +#define PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT 0xffff + struct packetbuf_attrlist { uint8_t type; uint8_t len; diff --git a/os/services/rpl-border-router/native/border-router-mac.c b/os/services/rpl-border-router/native/border-router-mac.c index fbf8b6496..7fe4fc6ed 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -64,6 +64,20 @@ struct tx_callback { /*---------------------------------------------------------------------------*/ static struct tx_callback callbacks[MAX_CALLBACKS]; /*---------------------------------------------------------------------------*/ +void +init_sec(void) +{ + /* use the CSMA LLSEC config parameter */ +#if LLSEC802154_USES_AUX_HEADER + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == + PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT) { + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + CSMA_LLSEC_SECURITY_LEVEL); + } +#endif +} +/*---------------------------------------------------------------------------*/ + void packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx) { @@ -164,6 +178,13 @@ off() return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload() +{ + init_sec(); + return 127 - NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -176,6 +197,7 @@ const struct mac_driver border_router_mac_driver = { send_packet, packet_input, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index e8bb4b6b2..c8b7d862e 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -55,6 +55,9 @@ #if MAC_CONF_WITH_TSCH #include "net/mac/tsch/tsch.h" #endif /* MAC_CONF_WITH_TSCH */ +#if MAC_CONF_WITH_CSMA +#include "net/mac/csma/csma.h" +#endif #include "net/routing/routing.h" #include "net/mac/llsec802154.h" @@ -424,7 +427,7 @@ PT_THREAD(cmd_rpl_global_repair(struct pt *pt, shell_output_func output, char *a { PT_BEGIN(pt); - SHELL_OUTPUT(output, "Triggering routing global repair\n") + SHELL_OUTPUT(output, "Triggering routing global repair\n"); NETSTACK_ROUTING.global_repair("Shell"); PT_END(pt); @@ -447,7 +450,7 @@ PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char * { PT_BEGIN(pt); - SHELL_OUTPUT(output, "Triggering routes refresh\n") + SHELL_OUTPUT(output, "Triggering routes refresh\n"); rpl_refresh_routes("Shell"); PT_END(pt); @@ -729,6 +732,73 @@ PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args)) } #endif /* TSCH_WITH_SIXTOP */ /*---------------------------------------------------------------------------*/ +#if LLSEC802154_ENABLED +static +PT_THREAD(cmd_llsec_setlv(struct pt *pt, shell_output_func output, char *args)) +{ + + PT_BEGIN(pt); + + if(args == NULL) { + SHELL_OUTPUT(output, "Default LLSEC level is %d\n", + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); + PT_EXIT(pt); + } else { + int lv = atoi(args); + if(lv < 0 || lv > 7) { + SHELL_OUTPUT(output, "Illegal LLSEC Level %d\n", lv); + PT_EXIT(pt); + } else { + uipbuf_set_default_attr(UIPBUF_ATTR_LLSEC_LEVEL, lv); + uipbuf_clear_attr(); + SHELL_OUTPUT(output, "LLSEC default level set %d\n", lv); + } + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_llsec_setkey(struct pt *pt, shell_output_func output, char *args)) +{ + char *next_args; + + PT_BEGIN(pt); + + SHELL_ARGS_INIT(args, next_args); + + if(args == NULL) { + SHELL_OUTPUT(output, "Provide an index and a 16-char string for the key\n"); + PT_EXIT(pt); + } else { + int key; + SHELL_ARGS_NEXT(args, next_args); + key = atoi(args); + if(key < 0) { + SHELL_OUTPUT(output, "Illegal LLSEC Key index %d\n", key); + PT_EXIT(pt); + } else { +#if MAC_CONF_WITH_CSMA + /* Get next arg (key-string) */ + SHELL_ARGS_NEXT(args, next_args); + if(args == NULL) { + SHELL_OUTPUT(output, "Provide both an index and a key\n"); + } else if(strlen(args) == 16) { + csma_security_set_key(key, (const uint8_t *) args); + SHELL_OUTPUT(output, "Set key for index %d\n", key); + } else { + SHELL_OUTPUT(output, "Wrong length of key: '%s' (%d)\n", args, strlen(args)); + } +#else + SHELL_OUTPUT(output, "Set key not supported.\n"); + PT_EXIT(pt); +#endif + } + } + PT_END(pt); +} +#endif /* LLSEC802154_ENABLED */ +/*---------------------------------------------------------------------------*/ void shell_commands_init(void) { @@ -801,6 +871,10 @@ const struct shell_command_t builtin_shell_commands[] = { #if TSCH_WITH_SIXTOP { "6top", cmd_6top, "'> 6top help': Shows 6top command usage" }, #endif /* TSCH_WITH_SIXTOP */ +#if LLSEC802154_ENABLED + { "llsec-set-level", cmd_llsec_setlv, "'> llsec-set-level ': Set the level of link layer security (show if no lv argument)"}, + { "llsec-set-key", cmd_llsec_setkey, "'> llsec-set-key ': Set the key of link layer security"}, +#endif /* LLSEC802154_ENABLED */ { NULL, NULL, NULL }, };