Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions drivers/include/slipdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
* @defgroup drivers_slipdev_stdio STDIO via SLIP
* @ingroup sys_stdio
* @brief Standard input/output backend multiplexed via SLIP
* @see [draft-bormann-t2trg-slipmux-03](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03)

Check warning on line 15 in drivers/include/slipdev.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
*
* This extension is part of the [Slipmux draft](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03).

Check warning on line 17 in drivers/include/slipdev.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
* @warning This module is under development for optimizations and module names might change!
*
* This will multiplex STDIO via the Serial Line Internet Protocol.
* The shell can be accessed via the `sliptty` tool.
Expand All @@ -23,11 +27,32 @@
* @see drivers_slipdev
*/

/**
* @defgroup drivers_slipdev_configuration CoAP via SLIP
* @ingroup drivers_slipdev
* @brief Exchange CoAP requests and responses via SLIP
* @see [draft-bormann-t2trg-slipmux-03](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03)

Check warning on line 34 in drivers/include/slipdev.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
*
* This extension is part of the [Slipmux draft](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03).

Check warning on line 36 in drivers/include/slipdev.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
* @warning This module is under development for optimizations and module names might change!
*
* This will multiplex CoAP messages via the Serial Line Internet Protocol.
* It spawns an extra thread as a CoAP server. The incoming requests are handled with `nanocoap`
* according to any `NANOCOAP_RESOURCE`s present in the binary. See @ref net_nanocoap for more.
*
* To enable this implementation, select
*
* USEMODULE += slipdev_config
*
* @see drivers_slipdev
*/

/**
* @defgroup drivers_slipdev SLIP network device
* @ingroup drivers_netdev
* @brief SLIP network device over @ref drivers_periph_uart
* @see [RFC 1055](https://github.com/RIOT-OS/RIOT/pull/6487)
* @see [RFC 1055](https://datatracker.ietf.org/doc/html/rfc1055)
*
* @{
*
* @file
Expand All @@ -42,6 +67,7 @@
#include "net/netdev.h"
#include "periph/uart.h"
#include "chunked_ringbuffer.h"
#include "sched.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -93,6 +119,14 @@
* @brief Device writes received data to stdin, next byte is escaped
*/
SLIPDEV_STATE_STDIN_ESC,
/**
* @brief Device writes received data as CoAP message
*/
SLIPDEV_STATE_CONFIG,
/**
* @brief Device writes received data as CoAP message, next byte is escaped
*/
SLIPDEV_STATE_CONFIG_ESC,
/**
* @brief Device is in standby, will wake up when sending data
*/
Expand Down Expand Up @@ -120,13 +154,19 @@
typedef struct {
netdev_t netdev; /**< parent class */
slipdev_params_t config; /**< configuration parameters */
chunk_ringbuf_t rb; /**< Ringbuffer to store received frames. */
chunk_ringbuf_t rb; /**< Ringbuffer to store received networking frames.*/
/* Written to from interrupts (with irq_disable */
/* to prevent any simultaneous writes), */
/* consumed exclusively in the network stack's */
/* loop at _isr. */

uint8_t rxmem[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */

#if IS_USED(MODULE_SLIPDEV_CONFIG)
chunk_ringbuf_t rb_config; /**< Ringbuffer stores received configuration frames */
uint8_t rxmem_config[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */
kernel_pid_t coap_server_pid; /**< The PID of the CoAP server */
#endif
/**
* @brief Device state
* @see [Device state definitions](@ref drivers_slipdev_states)
Expand Down
7 changes: 7 additions & 0 deletions drivers/slipdev/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ FEATURES_REQUIRED += periph_uart
ifneq (,$(filter slipdev_stdio,$(USEMODULE)))
USEMODULE += isrpipe
endif
ifneq (,$(filter slipdev_config,$(USEMODULE)))
USEMODULE += checksum
USEMODULE += sock_udp
USEMODULE += gnrc_ipv6
USEMODULE += nanocoap_sock
USEMODULE += nanocoap_resources
endif
9 changes: 8 additions & 1 deletion drivers/slipdev/include/slipdev_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,16 @@ extern "C" {
/**
* @brief Marker byte for beginning of stdio
* @see taken from diagnostic transfer from
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-02#section-4)
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-03#section-4)
*/
#define SLIPDEV_STDIO_START (0x0aU)

/**
* @brief Marker byte for beginning of configuration/CoAP
* @see taken from configuration from
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-03#section-5)
*/
#define SLIPDEV_CONFIG_START (0xa9U)
/** @} */

/**
Expand Down
160 changes: 146 additions & 14 deletions drivers/slipdev/slipdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @file
* @author Martine Lenders <[email protected]>
* @author Benjamin Valentin <[email protected]>
* @author Bennet Hattesen <[email protected]>
*/

#include <assert.h>
Expand All @@ -31,20 +32,37 @@

#include "isrpipe.h"
#include "mutex.h"
#if IS_USED(MODULE_SLIPDEV_CONFIG)
#include "checksum/crc16_ccitt.h"
#include "net/nanocoap.h"
#endif
#include "stdio_uart.h"

#if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
/* For synchronization with stdio/config threads */
mutex_t slipdev_mutex = MUTEX_INIT;
#endif

#if IS_USED(MODULE_SLIPDEV_CONFIG)
/* The special init is the result of normal fcs init combined with slipmux config start (0xa9) */
#define SPECIAL_INIT_FCS (0x374cU)
#define COAP_STACKSIZE (1024)

static char coap_stack[COAP_STACKSIZE];
#endif /* IS_USED(MODULE_SLIPDEV_CONFIG) */

static int _check_state(slipdev_t *dev);

static inline void slipdev_lock(void)
{
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
mutex_lock(&slipdev_mutex);
}
}

static inline void slipdev_unlock(void)
{
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
mutex_unlock(&slipdev_mutex);
}
}
Expand All @@ -54,7 +72,6 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
slipdev_t *dev = arg;

switch (dev->state) {
#if IS_USED(MODULE_SLIPDEV_STDIO)
case SLIPDEV_STATE_STDIN:
switch (byte) {
case SLIPDEV_ESC:
Expand All @@ -64,7 +81,11 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
dev->state = SLIPDEV_STATE_NONE;
break;
default:
isrpipe_write_one(&stdin_isrpipe, byte);
#if IS_USED(MODULE_SLIPDEV_STDIO)
if (dev->config.uart == STDIO_UART_DEV) {
isrpipe_write_one(&stdin_isrpipe, byte);
}
#endif
break;
}
return;
Expand All @@ -78,24 +99,81 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
break;
}
dev->state = SLIPDEV_STATE_STDIN;
isrpipe_write_one(&stdin_isrpipe, byte);
#if IS_USED(MODULE_SLIPDEV_STDIO)
if (dev->config.uart == STDIO_UART_DEV) {
isrpipe_write_one(&stdin_isrpipe, byte);
}
#endif
return;
case SLIPDEV_STATE_CONFIG:
switch (byte) {
case SLIPDEV_ESC:
dev->state = SLIPDEV_STATE_CONFIG_ESC;
break;
case SLIPDEV_END:
dev->state = SLIPDEV_STATE_NONE;
#if IS_USED(MODULE_SLIPDEV_CONFIG)
crb_end_chunk(&dev->rb_config, true);
thread_flags_set(thread_get(dev->coap_server_pid), 1);
#endif
break;
default:
#if IS_USED(MODULE_SLIPDEV_CONFIG)
/* discard frame if byte can't be added */
if (!crb_add_byte(&dev->rb_config, byte)) {
DEBUG("slipdev: rx buffer full, drop frame\n");
crb_end_chunk(&dev->rb_config, false);
dev->state = SLIPDEV_STATE_NONE;
return;
}
#endif
break;
}
return;
case SLIPDEV_STATE_CONFIG_ESC:
switch (byte) {
case SLIPDEV_END_ESC:
byte = SLIPDEV_END;
break;
case SLIPDEV_ESC_ESC:
byte = SLIPDEV_ESC;
break;
}
#if IS_USED(MODULE_SLIPDEV_CONFIG)
/* discard frame if byte can't be added */
if (!crb_add_byte(&dev->rb_config, byte)) {
DEBUG("slipdev: rx buffer full, drop frame\n");
crb_end_chunk(&dev->rb_config, false);
dev->state = SLIPDEV_STATE_NONE;
return;
}
#endif
dev->state = SLIPDEV_STATE_CONFIG;
return;
case SLIPDEV_STATE_NONE:
/* is diagnostic frame? */
if (IS_USED(MODULE_SLIPDEV_STDIO) &&
(byte == SLIPDEV_STDIO_START) &&
(dev->config.uart == STDIO_UART_DEV)) {
if (byte == SLIPDEV_STDIO_START) {
dev->state = SLIPDEV_STATE_STDIN;
return;
}

if (byte == SLIPDEV_CONFIG_START) {
#if IS_USED(MODULE_SLIPDEV_CONFIG)
/* try to create new frame */
if (!crb_start_chunk(&dev->rb_config)) {
return;
}
#endif
dev->state = SLIPDEV_STATE_CONFIG;
return;
}

/* ignore empty frame */
if (byte == SLIPDEV_END) {
return;
}

/* try to create new frame */
/* try to create new ip frame */
if (!crb_start_chunk(&dev->rb)) {
return;
}
Expand Down Expand Up @@ -198,8 +276,8 @@ void slipdev_write_bytes(uart_t uart, const uint8_t *data, size_t len)

static int _check_state(slipdev_t *dev)
{
/* power states not supported when multiplexing stdio */
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
/* power states not supported when multiplexing stdio / configuration */
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
return 0;
}

Expand Down Expand Up @@ -272,7 +350,7 @@ static void _isr(netdev_t *netdev)
}
}

#if !IS_USED(MODULE_SLIPDEV_STDIO)
#if !(IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
static int _set_state(slipdev_t *dev, netopt_state_t state)
{
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
Expand Down Expand Up @@ -309,7 +387,7 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t max_le
return -ENOTSUP;
}
}
#endif /* !MODULE_SLIPDEV_STDIO */
#endif /* !(MODULE_SLIPDEV_STDIO || MODULE_SLIPDEV_CONFIG) */

static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
{
Expand Down Expand Up @@ -348,15 +426,69 @@ static const netdev_driver_t slip_driver = {
.isr = _isr,
.get = _get,
.confirm_send = _confirm_send,
#if IS_USED(MODULE_SLIPDEV_STDIO)
#if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
.set = netdev_set_notsup,
#else
.set = _set,
#endif
};

#if IS_USED(MODULE_SLIPDEV_CONFIG)
static void *_coap_server_thread(void *arg)
{
static uint8_t buf[512];
slipdev_t *dev = arg;
while (1) {
thread_flags_wait_any(1);
size_t len;
while (crb_get_chunk_size(&dev->rb_config, &len)) {
crb_consume_chunk(&dev->rb_config, buf, len);
Comment on lines +444 to +445
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mguetschow @benpicco I think we had brain damage when we reviewed & merged this. It's an obvious buffer overflow waiting to happen.

if (len > sizeof(buf)) { goto Fail }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun 👀


/* Is the crc correct via residue(=0xF0B8) test */
if (crc16_ccitt_fcs_update(SPECIAL_INIT_FCS, buf, len) != 0xF0B8) {
break;
}

/* cut off the FCS checksum at the end */
size_t pktlen = len - 2;

coap_pkt_t pkt;
sock_udp_ep_t remote;
coap_request_ctx_t ctx = {
.remote = &remote,
};
if (coap_parse(&pkt, buf, pktlen) < 0) {
break;
}
unsigned int res = 0;
if ((res = coap_handle_req(&pkt, buf, sizeof(buf), &ctx)) <= 0) {
break;
}

uint16_t fcs_sum = crc16_ccitt_fcs_finish(SPECIAL_INIT_FCS, buf, res);

slipdev_lock();
slipdev_write_byte(dev->config.uart, SLIPDEV_CONFIG_START);
slipdev_write_bytes(dev->config.uart, buf, res);
slipdev_write_bytes(dev->config.uart, (uint8_t *) &fcs_sum, 2);
slipdev_write_byte(dev->config.uart, SLIPDEV_END);
slipdev_unlock();
}
}

return NULL;
}
#endif /* MODULE_SLIPDEV_CONFIG */

void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params, uint8_t index)
{
#if IS_USED(MODULE_SLIPDEV_CONFIG)
crb_init(&dev->rb_config, dev->rxmem_config, sizeof(dev->rxmem_config));

dev->coap_server_pid = thread_create(coap_stack, sizeof(coap_stack), THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _coap_server_thread,
(void *)dev, "Slipmux CoAP server");
#endif
/* set device descriptor fields */
dev->config = *params;
dev->state = 0;
Expand Down
6 changes: 3 additions & 3 deletions drivers/slipdev/stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#include "stdio_base.h"
#include "stdio_uart.h"

mutex_t slipdev_mutex = MUTEX_INIT;

static void _isrpipe_write(void *arg, uint8_t data)
{
isrpipe_write_one(arg, (char)data);
Expand All @@ -34,9 +32,11 @@ static void _isrpipe_write(void *arg, uint8_t data)
static void _init(void)
{
/* intentionally overwritten in netdev init so we have stdio before
* the network device is initialized is initialized */
* the network device is initialized */
uart_init(slipdev_params[0].uart, slipdev_params[0].baudrate,
_isrpipe_write, &stdin_isrpipe);

slipdev_write_byte(slipdev_params[0].uart, SLIPDEV_END);
}

static ssize_t _write(const void *buffer, size_t len)
Expand Down
Loading